ฉันจะสควอชได้อย่างไร


183

ฉันค่อนข้างใหม่กับคุณสมบัติการรีบูตทั้งหมดภายในคอมไพล์ สมมติว่าฉันได้ทำสิ่งต่อไปนี้:

A -> B -> C -> D

หลังจากนั้นฉันทราบว่าDมีการแก้ไขซึ่งขึ้นอยู่กับรหัสใหม่บางอย่างที่เพิ่มเข้ามาAและการกระทำเหล่านี้อยู่ด้วยกัน ฉันจะสควอชวิธีAและDร่วมกันและการลาBและCคนเดียว?

คำตอบ:


258

คุณสามารถเรียกใช้git rebase --interactiveและจัดลำดับ D ใหม่ก่อน B และสควอช D เป็น A

Git จะเปิดโปรแกรมแก้ไขและคุณจะเห็นไฟล์เช่นนี้เช่น: git rebase --interactive HEAD~4

pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D

# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

ตอนนี้คุณเปลี่ยนไฟล์ที่มีลักษณะดังนี้:

pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C

และคอมไพล์จะรวมการเปลี่ยนแปลงของ A และ D เข้าด้วยกันเป็นคอมมิชชันหนึ่งแล้วใส่ B และ C ในภายหลัง เมื่อคุณไม่ต้องการที่จะเก็บข้อความการกระทำของ D แทนคุณsquashจะใช้fixupคำหลัก หากต้องการข้อมูลเพิ่มเติมfixupคุณสามารถอ่านgit rebaseเอกสารหรือตรวจสอบคำถามนี้ซึ่งมีคำตอบที่ดี


5
ตอนแรกฉันอ่านมันว่า "rebase D เข้าสู่ A, สควอช D เป็น A จากนั้น rebase B เข้าสู่ DA" ยังไม่ชัดเจนจากคำตอบที่สามารถทำได้โดยจัดเรียงบรรทัดใหม่ในโปรแกรมแก้ไขข้อความ
Victor Sergienko

3
หากสาขาของคุณอยู่ในพื้นที่คุณจะได้รับThere is no tracking information for the current branchข้อผิดพลาดเมื่อทำการรีบูต git rebase -i HEAD~4ในกรณีนี้คุณจะต้องระบุจำนวนกระทำที่คุณต้องการที่จะทำงานด้วยเช่นนี้ ดูคำตอบนี้
johndodo

1
ฉันใช้โหมดอินเทอร์แอกทีฟ (git rebase -i) เป็นเวลาหลายปีฉันเพิ่งรู้ว่ามันสามารถจัดลำดับใหม่ได้ ขอบคุณ🤟🏻
CalvinChe

43

หมายเหตุ: คุณควรไม่เปลี่ยนกระทำที่ได้รับการผลักดันที่จะซื้อคืนอื่นในทางใด ๆจนกว่าคุณจะรู้ว่าผลที่ตามมา

git log --oneline -4

D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A

git rebase --interactive

pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A

ชนิด i (ใส่ VIM ในโหมดแทรก)

เปลี่ยนรายการให้มีลักษณะดังนี้ (คุณไม่ต้องลบหรือรวมข้อความยืนยัน) อย่าพลาดsquash! :

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

พิมพ์Escแล้วZZ(บันทึกและออก VIM)

# This is a combination of 2 commits.
# The first commit's message is:

commit_message_for_D

# This is the 2nd commit message:

commit_message_for_A

ชนิด i

เปลี่ยนข้อความเป็นสิ่งที่คุณต้องการให้ข้อความการส่งข้อความใหม่ดูเหมือน ฉันขอแนะนำนี่เป็นคำอธิบายของการเปลี่ยนแปลงที่เกิดขึ้นAและD:

new_commit_message_for_A_and_D

พิมพ์Escจากนั้นZZ

git log --oneline -4

E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B

git show E

(You should see a diff showing a combination of changes from A and D)

Eคุณได้สร้างตอนนี้ใหม่กระทำ มุ่งมั่นAและDไม่ได้อยู่ในประวัติศาสตร์ของคุณอีกต่อไป แต่จะไม่หายไป คุณยังสามารถกู้คืนได้ในจุดนี้และอีกสักครู่โดยgit rebase --hard D( git rebase --hardจะทำลายการเปลี่ยนแปลงในท้องถิ่น! )


3

สำหรับผู้ที่ใช้SourceTree :

ตรวจสอบให้แน่ใจว่าคุณยังไม่ได้ส่งข้อความยืนยัน

  1. พื้นที่เก็บข้อมูล> การคืนเงินเชิงโต้ตอบ ...
  2. ลาก D (การมอบหมายที่ใหม่กว่า) เพื่อให้อยู่เหนือ A (การกระทำที่เก่ากว่า) โดยตรง
  3. ตรวจสอบให้แน่ใจว่าการกระทำ D ถูกเน้น
  4. คลิก Squash with previous

1

การตอบโต้เชิงโต้ตอบจะทำงานได้ดีจนกว่าคุณจะมีสาขาคุณลักษณะขนาดใหญ่ที่มี 20-30 คอมมิทและ / หรือการรวมสองสามอย่างจากมาสเตอร์หรือ / และการแก้ไขข้อขัดแย้งในขณะที่คุณกำลังคอมมิชชันในสาขาของคุณ แม้จะพบการกระทำของฉันในประวัติศาสตร์และการแทนที่pickด้วยsquashก็ไม่ได้ทำงานที่นี่ ดังนั้นผมจึงมองหาวิธีอื่นและพบนี้บทความ ฉันทำการเปลี่ยนแปลงเพื่อทำงานกับสาขาแยกกัน:

git checkout master
git fetch
git pull
git merge branch-name
git reset origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git push -f --set-upstream origin branch-name

ก่อนหน้านี้ฉันได้รับคำขอดึงของฉันด้วยประมาณ ~ 30 คอมมิชชันที่มีการรวม 2-3 รายการจากความขัดแย้งหลัก + การแก้ไข และหลังจากนี้ฉันได้รับการประชาสัมพันธ์ที่ชัดเจนด้วยการกระทำอย่างใดอย่างหนึ่ง

PS ที่นี่คือสคริปต์ทุบตีเพื่อทำขั้นตอนนี้ใน automode


วิธีแก้ปัญหาแรกในบทความนั้นดีมากขอบคุณสำหรับลิงค์
Hoody

-1

$ git checkout

$ git log - ออนไลน์

D
C
B
A

$ git rebase --onto HEAD ^^^ HEAD ^

$ git log - ออนไลน์

D
A

ฉันคิดว่าคุณหมายถึง--onelineอะไร และมันดูเหมือนว่าคุณได้ปรับตัวลดลงCและการBซึ่งไม่ได้เป็นสิ่งที่ OP ได้ตั้งใจ
bstpierre

ไม่ได้ผลสำหรับฉัน มันย้ายทั้ง HEAD ของฉันและมาสเตอร์ลงไปที่ A แต่ไม่ได้รวม D เข้ากับ A ( git show A) และ D, C และ B ได้หายไปในบันทึกการอ้างอิงของฉัน ต้องgit rebase Dกลับมา
เนท
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.