มี 2 ขั้นตอนในการบรรลุเป้าหมายนี้:
- สร้างการมอบหมายที่ว่างเปล่าใหม่
- เขียนประวัติใหม่เพื่อเริ่มจากการกระทำที่ว่างเปล่านี้
เราจะใส่ค่าคอมมิชชันว่างเปล่าใหม่ไว้ที่สาขาชั่วคราวnewroot
เพื่อความสะดวก
1. สร้างการมอบหมายที่ว่างเปล่าใหม่
มีหลายวิธีที่คุณสามารถทำได้
ใช้เพียงแค่การประปา
วิธีที่สะอาดที่สุดคือการใช้ระบบประปาของ Git เพื่อสร้างการกระทำโดยตรงซึ่งหลีกเลี่ยงการสัมผัสสำเนาการทำงานหรือดัชนีหรือสาขาที่เช็คเอาท์เป็นต้น
สร้างวัตถุต้นไม้สำหรับไดเรกทอรีว่าง:
tree=`git hash-object -wt tree --stdin < /dev/null`
ล้อมรอบกระทำ:
commit=`git commit-tree -m 'root commit' $tree`
สร้างการอ้างอิงถึงมัน:
git branch newroot $commit
แน่นอนคุณสามารถจัดเรียงขั้นตอนทั้งหมดเป็นหนึ่งซับถ้าคุณรู้ว่าเปลือกของคุณดีพอ
โดยไม่ต้องประปา
ด้วยคำสั่งเครื่องเคลือบปกติคุณจะไม่สามารถสร้างการมอบหมายที่ว่างเปล่าโดยไม่ตรวจสอบจากnewroot
สาขาและอัปเดตดัชนีและสำเนาการทำงานซ้ำ ๆ ได้โดยไม่มีเหตุผล แต่บางคนอาจเข้าใจง่ายกว่านี้:
git checkout --orphan newroot
git rm -rf .
git clean -fd
git commit --allow-empty -m 'root commit'
โปรดทราบว่าใน Git เวอร์ชั่นเก่าที่ไม่มี--orphan
สวิตช์checkout
คุณต้องเปลี่ยนบรรทัดแรกด้วย:
git symbolic-ref HEAD refs/heads/newroot
2. เขียนซ้ำประวัติศาสตร์เพื่อเริ่มต้นจากการกระทำที่ว่างเปล่านี้
คุณมีสองตัวเลือกที่นี่: การรีบูทหรือเขียนประวัติใหม่ทั้งหมด
rebasing
git rebase --onto newroot --root master
สิ่งนี้มีข้อดีของความเรียบง่าย อย่างไรก็ตามมันจะอัปเดตชื่อผู้เดินทางและวันที่ในทุกการกระทำล่าสุดในสาขา
นอกจากนี้ด้วยประวัติกรณีขอบบางอย่างก็อาจล้มเหลวเนื่องจากการรวมความขัดแย้ง - แม้ว่าคุณจะ reboots ในการกระทำที่มีอะไร
เขียนประวัติศาสตร์ใหม่
วิธีทำความสะอาดคือการเขียนสาขาใหม่ แตกต่างกับgit rebase
คุณจะต้องมองขึ้นไปซึ่งการกระทำของคุณจะเริ่มจากสาขา:
git replace <currentroot> --graft newroot
git filter-branch master
การเขียนใหม่เกิดขึ้นในขั้นตอนที่สอง มันเป็นขั้นตอนแรกที่ต้องการคำอธิบาย สิ่งที่git replace
ไม่สามารถจะบอก Git ว่าเมื่อใดก็ตามที่เห็นว่ามีการอ้างอิงไปยังวัตถุที่คุณต้องการแทนที่, Git แทนควรดูที่การเปลี่ยนของวัตถุว่า
เมื่อใช้--graft
สวิตช์คุณกำลังบอกบางสิ่งที่แตกต่างจากปกติเล็กน้อย คุณกำลังพูดว่ายังไม่มีวัตถุทดแทน แต่คุณต้องการแทนที่<currentroot>
วัตถุยืนยันด้วยสำเนาที่แน่นอนของตัวเองยกเว้นการกระทำหลักของการแทนที่ควรเป็นวัตถุที่คุณระบุไว้ (เช่นการnewroot
กระทำ ) จากนั้นgit replace
ดำเนินการต่อและสร้างการกระทำนี้ให้คุณแล้วประกาศว่าการกระทำนั้นเป็นการแทนที่การกระทำดั้งเดิมของคุณ
ตอนนี้ถ้าคุณทำgit log
คุณจะเห็นว่าสิ่งที่มีอยู่แล้วมีลักษณะตามที่คุณต้องการให้พวกเขา: newroot
สาขาเริ่มต้น
อย่างไรก็ตามโปรดทราบgit replace
ว่าไม่ได้แก้ไขประวัติจริง - และไม่เผยแพร่ออกจากที่เก็บของคุณ มันเพิ่มการเปลี่ยนเส้นทางในเครื่องไปยังที่เก็บข้อมูลของคุณจากวัตถุหนึ่งไปยังอีกวัตถุหนึ่ง สิ่งนี้หมายความว่าไม่มีใครเห็นผลของการเปลี่ยนนี้ - เพียงคุณเท่านั้น
นั่นเป็นเหตุผลที่filter-branch
จำเป็นต้องมีขั้นตอน เมื่อgit replace
คุณสร้างสำเนาที่แน่นอนพร้อมกับพาเรนต์ที่ปรับแล้วให้คอมมิตสำหรับรูทคอมมิท git filter-branch
จากนั้นทำซ้ำกระบวนการนี้สำหรับการกระทำทั้งหมดต่อไปนี้เช่นกัน นี่คือที่ที่ประวัติศาสตร์ได้รับการเขียนใหม่เพื่อให้คุณสามารถแบ่งปันได้