คำตอบก่อนหน้านี้ส่วนใหญ่ผิดไปอย่างอันตราย!
อย่าทำอย่างนี้:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
ในครั้งต่อไปที่คุณเรียกใช้git rebase
(หรือgit pull --rebase
) 3 การกระทำเหล่านั้นจะถูกยกเลิกอย่างเงียบ ๆnewbranch
! (ดูคำอธิบายด้านล่าง)
ทำสิ่งนี้แทน:
git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
- ก่อนอื่นจะละทิ้ง 3 การกระทำล่าสุด (
--keep
เหมือน--hard
แต่ปลอดภัยกว่าล้มเหลวแทนที่จะทิ้งการเปลี่ยนแปลงที่ไม่มีข้อผูกมัด)
newbranch
จากนั้นก็จะปิดส้อม
- จากนั้นมันจะทำการหยิบเชอร์รี่ทั้ง 3 ตัวกลับเข้า
newbranch
มา เนื่องจากพวกมันไม่ได้ถูกอ้างถึงโดยสาขาอีกต่อไปมันก็ทำเช่นนั้นโดยใช้reflogของ git : HEAD@{2}
เป็นความมุ่งมั่นที่HEAD
เคยอ้างถึง 2 การทำงานที่ผ่านมานั่นคือก่อนที่เราจะ 1 ออกnewbranch
และ 2 ใช้git reset
เพื่อทิ้ง 3 คอมมิชชัน
คำเตือน: reflog ถูกเปิดใช้งานโดยค่าเริ่มต้น แต่ถ้าคุณได้ปิดใช้งานด้วยตนเอง (เช่นโดยการใช้ "เปลือย" เก็บคอมไพล์) คุณจะไม่สามารถที่จะได้รับ 3 git reset --keep HEAD~3
กระทำกลับมาหลังจากที่ทำงาน
ทางเลือกที่ไม่พึ่งพาการอ้างอิงคือ:
# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3
(ถ้าคุณต้องการคุณสามารถเขียน@{-1}
- สาขาที่เช็คเอาท์ก่อนหน้า - แทนoldbranch
)
คำอธิบายทางเทคนิค
ทำไมถึงgit rebase
ทิ้ง 3 คอมมิชชันหลังจากตัวอย่างแรก? เป็นเพราะgit rebase
ไม่มีอาร์กิวเมนต์เปิดใช้งาน--fork-point
ตัวเลือกโดยค่าเริ่มต้นซึ่งใช้ reflog ท้องถิ่นเพื่อพยายามที่จะแข็งแกร่งกับสาขาต้นน้ำที่ถูกผลักดัน
สมมติว่าคุณแยกต้นกำเนิด / ปรมาจารย์เมื่อมีการยอมรับ M1, M2, M3 จากนั้นให้สามการกระทำ:
M1--M2--M3 <-- origin/master
\
T1--T2--T3 <-- topic
แต่มีบางคนเขียนประวัติโดยใช้ต้นกำเนิด / แรงผลักดันหลักเพื่อลบ M2:
M1--M3' <-- origin/master
\
M2--M3--T1--T2--T3 <-- topic
ใช้ reflog ในพื้นที่ของคุณgit rebase
จะเห็นว่าคุณแยกจากชาติกำเนิดก่อนหน้าของสาขาต้นกำเนิด / หลักและด้วยเหตุนี้การมอบหมาย M2 และ M3 จึงไม่ได้เป็นส่วนหนึ่งของสาขาหัวข้อของคุณ ดังนั้นจึงสันนิษฐานว่ามีเหตุผลตั้งแต่ M2 ถูกลบออกจากสาขาต้นน้ำคุณไม่ต้องการมันในสาขาหัวข้อของคุณอีกต่อไปเมื่อสาขาหัวข้อถูก rebased:
M1--M3' <-- origin/master
\
T1'--T2'--T3' <-- topic (rebased)
พฤติกรรมนี้เหมาะสมและโดยทั่วไปเป็นสิ่งที่ถูกต้องเมื่อรีบูต
ดังนั้นเหตุผลที่คำสั่งต่อไปนี้ล้มเหลว:
git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch
เป็นเพราะพวกเขาออกจาก reflog ในสถานะที่ไม่ถูกต้อง Git มองnewbranch
ว่ามีการแยกสาขาต้นน้ำในการแก้ไขที่รวม 3 คอมมิตจากนั้นการreset --hard
เขียนประวัติต้นน้ำใหม่เพื่อลบการคอมมิชชันและในครั้งถัดไปที่คุณรันgit rebase
มันจะลบทิ้งเหมือนกับการคอมมิชชันอื่นที่ถูกลบออกจากอัปสตรีม
แต่ในกรณีนี้เราต้องการให้ 3 ข้อตกลงนั้นได้รับการพิจารณาให้เป็นส่วนหนึ่งของหัวข้อ เพื่อให้บรรลุเป้าหมายนั้นเราจำเป็นต้องตัดทวนต้นน้ำออกจากการแก้ไขก่อนหน้านี้ซึ่งไม่รวม 3 คอมมิท นั่นคือสิ่งที่โซลูชันที่แนะนำของฉันทำดังนั้นพวกเขาจึงออกจากการอ้างอิงในสภาพที่ถูกต้อง
สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ความหมายของ--fork-point
ในrebase คอมไพล์และคอมไพล์ผสานฐานเอกสาร