ในกรณีของฉันฉันมีmy-plugin
พื้นที่เก็บข้อมูลและmain-project
พื้นที่เก็บข้อมูลและฉันอยากจะแกล้งทำเป็นว่าmy-plugin
เคยพัฒนาในไดเรกทอรีย่อยของplugins
main-project
โดยทั่วไปฉันจะเขียนประวัติของที่my-plugin
เก็บเพื่อให้การพัฒนาทั้งหมดเกิดขึ้นในplugins/my-plugin
ไดเรกทอรีย่อย จากนั้นฉันเพิ่มประวัติการพัฒนาmy-plugin
ลงในmain-project
ประวัติศาสตร์และรวมต้นไม้สองต้นเข้าด้วยกัน เนื่องจากไม่มีplugins/my-plugin
ไดเรกทอรีอยู่ในที่main-project
เก็บจึงเป็นการรวมที่ไม่ขัดแย้งกันเล็กน้อย ที่เก็บผลลัพธ์มีประวัติทั้งหมดจากโครงการดั้งเดิมและมีสองราก
TL; DR
$ cp -R my-plugin my-plugin-dirty
$ cd my-plugin-dirty
$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all
$ cd ../main-project
$ git checkout master
$ git remote add --fetch my-plugin ../my-plugin-dirty
$ git merge my-plugin/master --allow-unrelated-histories
$ cd ..
$ rm -rf my-plugin-dirty
รุ่นยาว
ก่อนอื่นให้สร้างสำเนาของที่my-plugin
เก็บเพราะเรากำลังจะเขียนประวัติของที่เก็บนี้อีกครั้ง
ตอนนี้ไปที่รูทของที่my-plugin
เก็บเช็คสาขาหลักของคุณ (อาจmaster
) และรันคำสั่งต่อไปนี้ แน่นอนคุณควรแทนที่my-plugin
และplugins
ชื่อจริงของคุณคืออะไร
$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all
ตอนนี้สำหรับคำอธิบาย git filter-branch --tree-filter (...) HEAD
รันคำสั่งในทุกการกระทำที่สามารถเข้าถึงได้จาก(...)
HEAD
โปรดทราบว่าสิ่งนี้ทำงานโดยตรงกับข้อมูลที่เก็บไว้สำหรับการกระทำแต่ละครั้งดังนั้นเราจึงไม่ต้องกังวลเกี่ยวกับแนวคิดของ "ไดเรกทอรีการทำงาน", "ดัชนี", "การจัดเตรียม" และอื่น ๆ
ถ้าคุณเรียกใช้filter-branch
คำสั่งที่ล้มเหลวก็จะทิ้งบางไฟล์ใน.git
ไดเรกทอรีและครั้งต่อไปที่คุณพยายามที่filter-branch
จะบ่นเกี่ยวกับเรื่องนี้จนกว่าคุณจะจัดหาตัวเลือกในการ-f
filter-branch
สำหรับคำสั่งจริงฉันไม่มีโชคมากที่bash
จะทำสิ่งที่ฉันต้องการดังนั้นแทนที่จะใช้zsh -c
เพื่อzsh
เรียกใช้งานคำสั่ง ครั้งแรกที่ฉันตั้งค่าextended_glob
ตัวเลือกซึ่งเป็นสิ่งที่ช่วยให้^(...)
ไวยากรณ์ในmv
คำสั่งเช่นเดียวกับglob_dots
ตัวเลือกซึ่งช่วยให้ฉันเลือก dotfiles (เช่น.gitignore
) ด้วย glob ( ^(...)
)
ต่อไปฉันใช้mkdir -p
คำสั่งเพื่อสร้างทั้งสองplugins
และplugins/my-plugin
ในเวลาเดียวกัน
ในที่สุดฉันใช้คุณสมบัติzsh
"ลบ glob" ^(.git|plugins)
เพื่อจับคู่ไฟล์ทั้งหมดในไดเรกทอรีรากของที่เก็บยกเว้น.git
และmy-plugin
โฟลเดอร์ที่สร้างขึ้นใหม่ (การยกเว้น.git
อาจไม่จำเป็นที่นี่ แต่การลองย้ายไดเรกทอรีไปยังตัวเองถือเป็นข้อผิดพลาด)
ในที่เก็บของฉันการคอมมิชชันเริ่มต้นไม่ได้รวมไฟล์ใด ๆ ดังนั้นmv
คำสั่งส่งคืนข้อผิดพลาดในการคอมมิทเริ่มต้น ดังนั้นฉันจึงเพิ่มรายการ|| true
ที่git filter-branch
จะไม่ยกเลิก
--all
ตัวเลือกที่บอกfilter-branch
จะเขียนประวัติศาสตร์สำหรับทุกสาขาในพื้นที่เก็บข้อมูลและเพิ่มเติม--
เป็นสิ่งจำเป็นที่จะบอกgit
จะตีความว่ามันเป็นส่วนหนึ่งของรายการตัวเลือกสำหรับสาขาที่จะเขียนแทนการเป็นตัวเลือกให้กับfilter-branch
ตัวเอง
ตอนนี้ไปที่ที่main-project
เก็บของคุณแล้วดูสาขาที่คุณต้องการรวม เพิ่มสำเนาที่my-plugin
เก็บโลคัลของคุณ (ที่แก้ไขประวัติ) เป็นรีโมตmain-project
ด้วย:
$ git remote add --fetch my-plugin $PATH_TO_MY_PLUGIN_REPOSITORY
ตอนนี้คุณจะมีต้นไม้ที่ไม่เกี่ยวข้องสองต้นในประวัติการกระทำของคุณซึ่งคุณสามารถเห็นภาพได้อย่างชัดเจนโดยใช้:
$ git log --color --graph --decorate --all
เพื่อรวมพวกเขาใช้:
$ git merge my-plugin/master --allow-unrelated-histories
โปรดทราบว่าใน Git pre-2.9.0 --allow-unrelated-histories
ไม่มีตัวเลือกอยู่ หากคุณกำลังใช้รุ่นใดรุ่นหนึ่งเหล่านี้เพียงละเว้นตัวเลือก: ข้อความแสดงข้อผิดพลาดที่--allow-unrelated-histories
ป้องกันไม่ให้ถูกยังเพิ่มใน 2.9.0
คุณไม่ควรมีข้อขัดแย้งในการผสาน หากคุณทำเช่นนั้นอาจหมายถึงว่าfilter-branch
คำสั่งทำงานไม่ถูกต้องหรือมีplugins/my-plugin
ไดเรกทอรีอยู่main-project
แล้ว
ตรวจสอบให้แน่ใจว่าได้ป้อนข้อความการมอบหมายที่อธิบายได้สำหรับผู้มีส่วนร่วมในอนาคตสงสัยว่าแฮกเกอร์กำลังทำอะไรเพื่อสร้างที่เก็บที่มีสองราก
คุณสามารถเห็นกราฟการคอมมิตใหม่ซึ่งควรมีคอมมิททรูทสองอันโดยใช้git log
คำสั่งด้านบน โปรดทราบว่าเฉพาะmaster
สาขาที่จะถูกรวม ซึ่งหมายความว่าหากคุณมีงานสำคัญในmy-plugin
สาขาอื่นที่คุณต้องการรวมเข้ากับmain-project
ต้นไม้คุณควรละเว้นการลบmy-plugin
รีโมตจนกว่าคุณจะทำการผสานเหล่านี้ หากคุณไม่ทำเช่นนั้นการผูกมัดจากสาขาเหล่านั้นจะยังคงอยู่ในที่main-project
เก็บ แต่บางอันจะไม่สามารถเข้าถึงได้และไวต่อการรวบรวมขยะในที่สุด (นอกจากนี้คุณจะต้องอ้างถึงพวกเขาโดย SHA เนื่องจากการลบรีโมตจะลบสาขาการติดตามระยะไกล)
เป็นทางเลือกหลังจากคุณรวมทุกอย่างที่คุณต้องการเก็บไว้my-plugin
แล้วคุณสามารถลบmy-plugin
รีโมตโดยใช้:
$ git remote remove my-plugin
ตอนนี้คุณสามารถลบสำเนาของที่my-plugin
เก็บที่คุณเปลี่ยนประวัติได้อย่างปลอดภัย ในกรณีของฉันฉันยังเพิ่มการบอกเลิกการลงในที่my-plugin
เก็บจริงหลังจากการผสานเสร็จสมบูรณ์และถูกผลัก
ผ่านการทดสอบบน Mac OS X El Capitan ด้วยและgit --version 2.9.0
zsh --version 5.2
ไมล์สะสมของคุณอาจแตกต่างกันไป
อ้างอิง: