ฉันจะสควอช X สุดท้ายของฉันให้คอมมิตด้วย Git ได้อย่างไร?
ฉันจะสควอช X สุดท้ายของฉันให้คอมมิตด้วย Git ได้อย่างไร?
คำตอบ:
การใช้งานgit rebase -i <after-this-commit>
และแทนที่ "เลือก" ที่กระทำสองและต่อด้วย "สควอช" หรือ "fixup" ที่อธิบายไว้ในคู่มือการใช้งาน
ในตัวอย่าง<after-this-commit>
นี้อาจเป็นแฮช SHA1 หรือตำแหน่งสัมพัทธ์จาก HEAD ของสาขาปัจจุบันที่วิเคราะห์คอมมิทสำหรับคำสั่ง rebase ตัวอย่างเช่นหากผู้ใช้ต้องการเพื่อดู 5 git rebase -i HEAD~5
กระทำจากหัวปัจจุบันในอดีตคำสั่งคือ
<after-this-commit>
อะไร
<after-this-commit>
คือการกระทำ X + 1 คือผู้ปกครองของการกระทำที่เก่าแก่ที่สุดที่คุณต้องการสควอช
rebase -i
วิธีการนี้และreset --soft
คือrebase -i
ช่วยให้ฉันสามารถรักษาผู้เขียนกระทำในขณะที่reset --soft
ช่วยให้ฉันแนะนำ บางครั้งฉันต้องสควอชกระทำการร้องขอดึง แต่ยังคงรักษาข้อมูลผู้เขียน บางครั้งฉันต้องรีเซ็ตซอฟท์ด้วยความมุ่งมั่นของตัวเอง ขึ้นกับคำตอบที่ยอดเยี่ยมทั้งสองคำตอบ
คุณสามารถทำเช่นนี้ได้ค่อนข้างง่ายโดยไม่ต้องหรือgit rebase
git merge --squash
ในตัวอย่างนี้เราจะสควอช 3 คอมมิชชันล่าสุด
ถ้าคุณต้องการเขียนข้อความคอมมิชชันใหม่ตั้งแต่ต้นความพอเพียงนี้:
git reset --soft HEAD~3 &&
git commit
หากคุณต้องการเริ่มแก้ไขข้อความคอมมิทใหม่ด้วยการต่อข้อความคอมมิตที่มีอยู่แล้ว (เช่นคล้ายกับgit rebase -i
รายการคำสั่งการเลือก / สควอช / สควอช / … / สควอช) เริ่มต้นด้วย) คุณต้องแยกข้อความเหล่านั้น พวกเขาไปที่git commit
:
git reset --soft HEAD~3 &&
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
ทั้งสองวิธีใช้วิธีการสควอชสามครั้งล่าสุดเพื่อคอมมิตใหม่ในลักษณะเดียวกัน ซอฟต์รีเซ็ตเพิ่ง re-points HEAD ไปยังจุดสุดท้ายที่คุณไม่ต้องการสควอช ไม่ว่าจะเป็นดัชนีหรือแผนผังการทำงานจะถูกแตะเบา ๆ โดยปล่อยให้ดัชนีอยู่ในสถานะที่ต้องการสำหรับการกระทำใหม่ของคุณ (เช่นมีการเปลี่ยนแปลงทั้งหมดจากการกระทำที่คุณกำลังจะ "ทิ้ง")
git rebase --squash-recent
git commit --amend-many
branch@{upstream}
(หรือเพียงแค่@{upstream}
สำหรับสาขาปัจจุบันในทั้งสองกรณีส่วนสุดท้ายสามารถย่อให้@{u}
ดู; gitrevisions ) สิ่งนี้อาจแตกต่างจาก“ การผลักดันครั้งล่าสุด” ของคุณ (เช่นถ้ามีคนผลักสิ่งที่สร้างไว้บนการผลักดันล่าสุดของคุณแล้วคุณดึงข้อมูลนั้น) แต่ดูเหมือนว่ามันอาจจะใกล้เคียงกับสิ่งที่คุณต้องการ
push -f
แต่อย่างอื่นมันก็น่ารักขอบคุณ
git push --force
หลังจากนั้นเพื่อให้ได้รับมอบหมาย
คุณสามารถใช้git merge --squash
สิ่งนี้ได้ซึ่งดูสง่างามกว่าเล็กน้อยgit rebase -i
เล็กน้อย สมมติว่าคุณอยู่ในระดับปริญญาโทและคุณต้องการที่จะสควอช 12 ครั้งสุดท้ายเป็นหนึ่ง
คำเตือน: ก่อนอื่นให้แน่ใจว่าคุณยอมรับงานของคุณ - ตรวจสอบว่าgit status
สะอาด (ตั้งแต่git reset --hard
จะโยนออกไปจัดฉากและการเปลี่ยนแปลง unstaged)
แล้ว:
# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12
# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}
# Commit those squashed changes. The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit
เอกสารgit merge
อธิบาย--squash
ตัวเลือกในรายละเอียดเพิ่มเติม
อัปเดต:ข้อได้เปรียบที่แท้จริงเพียงอย่างเดียวของวิธีนี้เหนือคำgit reset --soft HEAD~12 && git commit
แนะนำที่ง่ายกว่าของ Chris Johnsen ในคำตอบของเขาคือคุณได้รับข้อความการส่งข้อความที่มีการส่งข้อความยืนยันทั้งหมดที่คุณกำลังส่ง
git rebase -i
แต่คุณไม่ได้ให้เหตุผลอะไร ในแง่ที่ไม่แน่นอน -1 เนื่องจากดูเหมือนว่าสำหรับฉันแล้วในความเป็นจริงตรงกันข้ามนั้นเป็นจริงและนี่คือการแฮ็ก คุณไม่ได้ทำคำสั่งเกินความจำเป็นเพื่อบังคับgit merge
ให้ทำสิ่งใดสิ่งหนึ่งที่git rebase
ออกแบบมาเป็นพิเศษหรือไม่
git merge --squash
ยังใช้งานง่ายกว่าในสคริปต์ โดยพื้นฐานแล้วเหตุผลก็คือคุณไม่จำเป็นต้องมี "การโต้ตอบ" git rebase -i
เลยสำหรับเรื่องนี้
git merge --squash
มีโอกาสน้อยที่จะสร้างความขัดแย้งในการเคลื่อนย้าย / ลบ / เปลี่ยนชื่อเมื่อเทียบกับการรีบูตโดยเฉพาะอย่างยิ่งถ้าคุณรวมจากสาขาท้องถิ่น (ข้อจำกัดความรับผิดชอบ: ขึ้นอยู่กับประสบการณ์เพียงอย่างเดียวให้แก้ไขฉันถ้านี่ไม่เป็นความจริงในกรณีทั่วไป!)
HEAD@{1}
การอยู่ด้านที่ปลอดภัยเช่นเมื่อเวิร์กโฟลว์ของคุณถูกขัดจังหวะเป็นเวลาหนึ่งชั่วโมงโดยไฟดับ ฯลฯ
ฉันขอแนะนำให้หลีกเลี่ยงgit reset
เมื่อเป็นไปได้ - โดยเฉพาะอย่างยิ่งสำหรับ Git-novices ถ้าคุณไม่จำเป็นต้องทำให้กระบวนการโดยอัตโนมัติเป็นไปตามจำนวนที่ได้ตกลงไว้มีวิธีแปลกใหม่น้อยกว่า ...
git merge --squash (working branch name)
git commit
ข้อความคอมมิชชันจะถูกเติมไว้ล่วงหน้าตามสควอช
gitk
เพื่อติดป้ายกำกับบรรทัดรหัสที่คุณกำลังบีบอัดและติดป้ายฐานที่จะใช้สควอช ในกรณีปกติฉลากทั้งสองนี้จะมีอยู่แล้วดังนั้นสามารถข้ามขั้นตอน (1) ได้
git branch your-feature && git reset --hard HEAD~N
วิธีที่สะดวกที่สุดแล้ว อย่างไรก็ตามมันเกี่ยวข้องกับการรีเซ็ต git อีกครั้งซึ่งคำตอบนี้พยายามหลีกเลี่ยง
เพิ่มนามแฝง "สควอช" ทั่วโลกจาก bash: (หรือ Git Bash บน Windows)
git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'
... หรือใช้พรอมต์คำสั่งของ Windows:
git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
~/.gitconfig
ตอนนี้
คุณควรมีชื่อแทนนี้:
[alias]
squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
การใช้งาน:
git squash N
... ซึ่งสควอชโดยอัตโนมัติล่าสุด N
กระทำ
หมายเหตุ: ข้อความการคอมมิชชันของผลลัพธ์คือการรวมกันของคอมมิตที่คอมมิตตามลำดับ หากคุณไม่พึงพอใจกับสิ่งนั้นคุณสามารถgit commit --amend
แก้ไขได้ด้วยตนเอง (หรือแก้ไขนามแฝงเพื่อให้เข้ากับรสนิยมของคุณ)
git squash -m "New summary."
และN
กำหนดโดยอัตโนมัติเมื่อจำนวนการคอมมิชชันที่ไม่ได้ชำระ
git commit --amend
เพื่อเปลี่ยนข้อความเพิ่มเติมได้ แต่นามแฝงนี้จะช่วยให้คุณเริ่มต้นได้ดีว่าควรมีอะไรในข้อความยืนยัน
ขอบคุณโพสต์บล็อกที่มีประโยชน์นี้ฉันพบว่าคุณสามารถใช้คำสั่งนี้เพื่อกำจัด 3 คอมมิชชันล่าสุด:
git rebase -i HEAD~3
สิ่งนี้มีประโยชน์เนื่องจากสามารถใช้งานได้แม้ในสาขาท้องถิ่นที่ไม่มีข้อมูลการติดตาม / repo ระยะไกล
คำสั่งจะเปิดตัวแก้ไขการรีบูตแบบโต้ตอบซึ่งจะช่วยให้คุณสามารถสั่งซื้อใหม่, สควอช, reword และอื่น ๆ ตามปกติ
การใช้เครื่องมือแก้ไขการรีบูตแบบโต้ตอบ:
ตัวแก้ไขการปฏิเสธแบบโต้ตอบแสดงการยอมรับสามครั้งล่าสุด ข้อ จำกัด นี้ถูกกำหนดโดยHEAD~3
เมื่อรันคำสั่งgit rebase -i HEAD~3
เมื่อใช้คำสั่ง
การคอมมิชชันล่าสุดHEAD
จะแสดงเป็นอันดับแรกในบรรทัดที่ 1 บรรทัดที่ขึ้นต้นด้วย a#
คือข้อคิดเห็น / เอกสาร
เอกสารที่ปรากฏค่อนข้างชัดเจน ในบรรทัดใดก็ตามที่คุณสามารถเปลี่ยนคำสั่งจากpick
เป็นคำสั่งที่คุณเลือก
ฉันชอบที่จะใช้คำสั่ง fixup
นี้เป็น "squashes" การเปลี่ยนแปลงการกระทำของการกระทำในบรรทัดข้างต้นและทิ้งข้อความของการกระทำ
ในฐานะที่กระทำในบรรทัดที่ 1 ในกรณีส่วนใหญ่ที่คุณจะออกจากนี้เป็นHEAD
pick
คุณไม่สามารถใช้squash
หรือfixup
เนื่องจากไม่มีข้อผูกมัดอื่น ๆ ในการกำจัดการมอบหมาย
คุณสามารถเปลี่ยนลำดับของการคอมมิท สิ่งนี้อนุญาตให้คุณสควอชหรือการแก้ไขที่คอมมิชชันที่ไม่ได้ติดกันตามลำดับเวลา
ตัวอย่างการปฏิบัติในชีวิตประจำวัน
ฉันเพิ่งมุ่งมั่นคุณสมบัติใหม่ ตั้งแต่นั้นมาฉันได้ทำการแก้ไขข้อบกพร่องสองครั้ง แต่ตอนนี้ฉันได้ค้นพบข้อผิดพลาด (หรืออาจเป็นเพียงแค่ข้อผิดพลาดการสะกดคำ) ในคุณสมบัติใหม่ที่ฉันมุ่งมั่น น่ารำคาญมาก! ฉันไม่ต้องการให้คนใหม่สร้างมลภาวะให้กับประวัติการกระทำของฉัน!
สิ่งแรกที่ฉันทำคือแก้ไขข้อผิดพลาดและทำการคอมมิทใหม่ด้วยความคิดเห็น squash this into my new feature!
สิ่งแรกที่ผมทำคือการแก้ไขความผิดพลาดและทำให้ใหม่กระทำด้วยการแสดงความคิดเห็น
จากนั้นฉันเรียกใช้git log
หรือgitk
รับค่า SHA ของคุณลักษณะใหม่ (ในกรณีนี้1ff9460
)
ต่อไปผมจะนำมาขึ้นบรรณาธิการ rebase git rebase -i 1ff9460~
แบบโต้ตอบกับ ~
หลังจากที่กระทำ SHA บอกบรรณาธิการที่จะรวมที่กระทำในการแก้ไข
ต่อไปผมจะย้ายกระทำที่มีการแก้ไข ( fe7f1e0
) จะอยู่ภายใต้คุณลักษณะกระทำและการเปลี่ยนแปลงไปpick
fixup
เมื่อปิดตัวแก้ไขการแก้ไขจะถูกบีบเข้าสู่คุณลักษณะการส่งมอบและประวัติการส่งมอบของฉันจะดูดีและสะอาด!
สิ่งนี้ใช้ได้ดีเมื่อคอมมิชชันทั้งหมดเป็นโลคัล แต่ถ้าคุณลองเปลี่ยนคอมมิทที่ผลักไปที่รีโมตคุณสามารถสร้างปัญหาให้กับผู้พัฒนารายอื่นที่เช็คสาขาเดียวกัน!
pick
อยู่ในบรรทัดที่ 1 หากคุณเลือกsquash
หรือfixup
สำหรับการกระทำที่บรรทัดที่ 1 คอมไพล์จะแสดงข้อความว่า "ข้อผิดพลาด: ไม่สามารถ 'แก้ไข' โดยไม่ต้องคอมมิชชันก่อนหน้า" จากนั้นจะให้ตัวเลือกแก่คุณในการแก้ไข: "คุณสามารถแก้ไขได้ด้วย 'รีบูต git --edit-todo' แล้วเรียกใช้ 'git rebase - ยุติ' หรือคุณสามารถยกเลิกและเริ่มต้นใหม่: "หรือคุณสามารถยกเลิกการ rebase ด้วย 'git rebase --abort'"
หากคุณใช้ TortoiseGit คุณสามารถใช้ฟังก์ชันCombine to one commit
:
Show Log
Combine to one commit
จากเมนูบริบทฟังก์ชั่นนี้ดำเนินการขั้นตอน git เดียวที่จำเป็นโดยอัตโนมัติ น่าเสียดายที่มีเฉพาะสำหรับ Windows
ในการทำเช่นนี้คุณสามารถใช้คำสั่ง git ต่อไปนี้
git rebase -i HEAD~n
n (= 4 ที่นี่) คือจำนวนการส่งครั้งล่าสุด จากนั้นคุณมีตัวเลือกดังต่อไปนี้
pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....
อัปเดตเหมือนด้านล่างpick
หนึ่งคอมมิชชันและsquash
รายการอื่น ๆ เป็นล่าสุด
p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....
สำหรับรายละเอียดคลิกที่ลิงค์
จากบทความนี้ฉันพบว่าวิธีนี้ง่ายสำหรับ usecase ของฉัน
สาขา 'dev' ของฉันอยู่ก่อนหน้า 'origin / dev' โดย 96 commits (ดังนั้นคอมมิชชันเหล่านี้ยังไม่ได้ถูกผลักไปที่รีโมท)
ฉันต้องการกำจัดสิ่งเหล่านี้ให้เป็นหนึ่งก่อนผลักดันการเปลี่ยนแปลง ฉันจะรีเซ็ตสาขาเป็นสถานะของ 'ต้นทาง / dev' (นี่จะทำให้การเปลี่ยนแปลงทั้งหมดจาก 96 คอมมิทที่ไม่มีการกำหนดค่า) แล้วทำการเปลี่ยนแปลงในทันที:
git reset origin/dev
git add --all
git commit -m 'my commit message'
ในสาขาที่คุณต้องการรวมคอมมิชชันทำงาน:
git rebase -i HEAD~(n number of commits back to review)
ตัวอย่าง:
git rebase -i HEAD~1
สิ่งนี้จะเปิดตัวแก้ไขข้อความและคุณต้องสลับ 'เลือก' ต่อหน้าการส่งแต่ละรายการด้วย 'สควอช' หากคุณต้องการให้คอมมิชชันเหล่านี้รวมเข้าด้วยกัน จากเอกสาร:
ตัวอย่างเช่นหากคุณต้องการรวมการกระทำทั้งหมดเข้าด้วยกันการเลือกคือสิ่งแรกที่คุณทำและสิ่งที่จะเกิดขึ้นในอนาคตทั้งหมด หากใช้เป็นกลุ่มให้ใช้: xในโหมดแทรกเพื่อบันทึกและออกจากโปรแกรมแก้ไข
จากนั้นให้ดำเนินการ rebase ต่อ:
git rebase --continue
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีนี้และวิธีอื่น ๆ ในการเขียนประวัติการส่งข้อความของคุณดูโพสต์ที่มีประโยชน์นี้
--continue
และเสียงเรียกเข้า:x
ทำเช่นกัน
คำตอบที่ผิดปกติเป็นสิ่งที่ดี แต่ฉันรู้สึกไม่แน่ใจเกี่ยวกับเรื่องนี้ดังนั้นฉันจึงตัดสินใจที่จะเพิ่มภาพหน้าจอสองสามภาพ
git log
ดูที่ที่คุณอยู่ด้วย สำคัญที่สุดค้นหาแฮชการคอมมิชชันของการคอมมิชชันแรกที่คุณไม่ต้องการสควอช ดังนั้นเฉพาะ:
ดำเนินการgit rebase -i [your hash]
ในกรณีของฉัน:
$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d
ในกรณีของฉันฉันต้องการสควอชทุกอย่างในการส่งครั้งแรก สั่งซื้อจากคนแรกที่ผ่านมาดังนั้นตรงวิธีการอื่น ๆ git log
ในขณะที่ ในกรณีของฉันฉันต้องการ:
หากคุณเลือกการส่งและการบีบอัดที่เหลือคุณสามารถปรับการส่งข้อความได้
แค่นั้นแหละ. เมื่อคุณบันทึกสิ่งนี้ ( :wq
) คุณทำเสร็จแล้ว ลองดูด้วยgit log
นะ
git log
1) ระบุการแฮชแบบสั้น
# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....
ที่นี่git log --oneline
ยังสามารถใช้เพื่อรับแฮชแบบสั้น
2) ถ้าคุณต้องการที่จะสควอช (ผสาน) การกระทำสุดท้ายสองครั้ง
# git rebase -i deab3412
3) นี่เป็นการเปิดตัวnano
แก้ไขสำหรับการรวม และดูเหมือนว่าด้านล่าง
....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....
4) การเปลี่ยนชื่อคำว่าpick
การที่มีอยู่ก่อนsquash
abcd1234
หลังจากเปลี่ยนชื่อแล้วควรเป็นดังนี้
....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....
5) ตอนนี้บันทึกและปิดตัวnano
แก้ไข กดctrl + o
และกดEnter
เพื่อบันทึก จากนั้นกดctrl + x
เพื่อออกจากตัวแก้ไข
6) จากนั้นnano
เอดิเตอร์จะเปิดขึ้นอีกครั้งเพื่ออัพเดตความคิดเห็นหากจำเป็นต้องอัพเดต
7) ตอนนี้มันถูกบีบอัดเรียบร้อยแล้วคุณสามารถตรวจสอบได้โดยการตรวจสอบบันทึก
# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....
8) ตอนนี้กดเพื่อ repo หมายเหตุเพื่อเพิ่ม+
เครื่องหมายก่อนชื่อสาขา นั่นหมายถึงการผลักดันอย่างรุนแรง
# git push origin +master
หมายเหตุ: สิ่งนี้ขึ้นอยู่กับการใช้ git บนubuntu
เชลล์ หากคุณใช้ระบบปฏิบัติการอื่น ( Windows
หรือMac
) คำสั่งด้านบนจะเหมือนกันยกเว้นเครื่องมือแก้ไข คุณอาจได้รับการแก้ไขที่แตกต่างกัน
git add <files>
--fixup
ตัวเลือกและสิ่งOLDCOMMIT
ที่เราควรจะรวม (สควอช) สิ่งนี้git commit --fixup=OLDCOMMIT
fixup1 <OLDCOMMIT_MSG>
ตอนนี้จะสร้างใหม่กระทำที่ด้านบนของหัว
OLDCOMMIT
ใหม่กระทำเพื่อgit rebase --interactive --autosquash OLDCOMMIT^
นี่หมายความว่าก่อนหน้านี้กระทำการ^
คำสั่งOLDCOMMIT
นี้จะrebase
เปิดหน้าต่างโต้ตอบบนเครื่องมือแก้ไข (vim หรือ nano) ที่เราไม่จำเป็นต้องทำอะไรเลยเพียงแค่บันทึกและออกก็เพียงพอแล้ว เนื่องจากตัวเลือกที่ส่งไปยังสิ่งนี้จะย้ายการส่งล่าสุดไปยังถัดจากการส่งเก่าโดยอัตโนมัติและเปลี่ยนการดำเนินการเป็นfixup
(เทียบเท่ากับสควอช) จากนั้นการรีบูตจะดำเนินต่อไปและเสร็จสิ้น
--amend
git-commit
# git log --pretty=oneline --abbrev-commit
cdababcd Fix issue B
deab3412 Fix issue A
....
# git add <files> # New changes
# git commit --amend
# git log --pretty=oneline --abbrev-commit
1d4ab2e1 Fix issue B
deab3412 Fix issue A
....
ที่นี่--amend
จะรวมการเปลี่ยนแปลงใหม่เพื่อยอมรับล่าสุดcdababcd
และสร้าง ID การยอมรับใหม่1d4ab2e1
หากต้องการสควอช 10 ครั้งสุดท้ายให้คอมมิชชันเดียว:
git reset --soft HEAD~10 && git commit -m "squashed commit"
หากคุณต้องการอัปเดตสาขาระยะไกลด้วยสควอชคอมมิต:
git push -f
หากคุณอยู่ในสาขาระยะไกล (เรียกว่าfeature-branch
) ที่ถูกโคลนจากพื้นที่เก็บข้อมูลทองคำ ( golden_repo_name
) แล้วนี่เป็นเทคนิคในการสควอชคอมมิชชันของคุณเป็นหนึ่ง:
ชำระเงิน repo ทอง
git checkout golden_repo_name
สร้างสาขาใหม่จาก (repo ทองคำ) ดังนี้
git checkout -b dev-branch
สควอชผสานกับสาขาท้องถิ่นของคุณที่คุณมีอยู่แล้ว
git merge --squash feature-branch
กระทำการเปลี่ยนแปลงของคุณ (นี่จะเป็นสิ่งเดียวที่กระทำใน dev-branch)
git commit -m "My feature complete"
ผลักสาขาไปยังพื้นที่เก็บข้อมูลในท้องถิ่นของคุณ
git push origin dev-branch
สิ่งที่สามารถจะสะดวกจริงๆ: ค้นหากระทำกัญชาคุณต้องการสควอชที่ด้านบนของการพูด
d43e15
ตอนนี้ใช้
git reset d43e15
git commit -am 'new commit name'
นี่เป็น kludgy สุดยอด แต่เป็นวิธีที่ยอดเยี่ยมดังนั้นฉันจะโยนมันเข้าไปในวงแหวน:
GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo
การแปล: จัดเตรียม "ตัวแก้ไข" ใหม่สำหรับคอมไพล์ซึ่งหากชื่อไฟล์ที่จะแก้ไขคือgit-rebase-todo
(พรอมต์รีบูตแบบโต้ตอบ) เปลี่ยนทั้งหมดยกเว้น "เลือก" ครั้งแรกเป็น "สควอช" และอื่น ๆ วางไข่เป็นกลุ่ม - ดังนั้นเมื่อคุณถูกถาม ในการแก้ไขข้อความคอมมิชชันคุณได้รับเสียงเรียกเข้า (และเห็นได้ชัดว่าฉันถูกบีบห้าครั้งสุดท้ายในสาขา foo แต่คุณสามารถเปลี่ยนแปลงได้ตามที่คุณต้องการ)
ผมอาจจะทำในสิ่งที่มาร์ค Longair ปัญหาแม้ว่า
หากคุณต้องการ squish ทุกการกระทำในการกระทำเดียว (เช่นเมื่อปล่อยโครงการสาธารณะเป็นครั้งแรก) ให้ลอง:
git checkout --orphan <new-branch>
git commit
ฉันคิดว่าวิธีที่ง่ายที่สุดในการทำเช่นนี้คือการทำให้สาขาใหม่หลุดจากต้นแบบและทำการผสาน - ถอนออกจากสาขาฟีเจอร์
git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch
จากนั้นคุณมีการเปลี่ยนแปลงทั้งหมดพร้อมที่จะกระทำ
2563โซลูชั่นง่าย ๆโดยไม่ต้องรีบูต:
git reset --soft HEAD~2
git commit -m "new commit message"
git push --force
2 หมายความว่าคอมมิชชันสุดท้ายจะถูกแบน คุณสามารถแทนที่ด้วยหมายเลขใดก็ได้
Simple one-liner ที่ใช้งานได้ตลอดเวลาเนื่องจากคุณอยู่ในสาขาที่คุณต้องการสควอชมาสเตอร์เป็นสาขาที่มาจากการกระทำล่าสุดและคอมมิชชันล่าสุดประกอบด้วยข้อความคอมมิทและผู้แต่งที่คุณต้องการใช้:
git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}
หากตัวอย่างเช่นคุณต้องการสควอช 3 ครั้งล่าสุดจะคอมมิชชันเดียวในสาขา (ที่เก็บข้อมูลระยะไกล) ในตัวอย่าง: https://bitbucket.org
สิ่งที่ฉันทำคือ
(MASTER)
Fleetwood Mac Fritz
║ ║
Add Danny Lindsey Stevie
Kirwan Buckingham Nicks
║ ╚═══╦══════╝
Add Christine ║
Perfect Buckingham
║ Nicks
LA1974══════════╝
║
║
Bill <══════ YOU ARE EDITING HERE
Clinton (CHECKED OUT, CURRENT WORKING DIRECTORY)
ในประวัติศาสตร์ที่ย่อมากของhttps://github.com/fleetwood-mac/band-history repository คุณได้เปิดคำขอดึงเพื่อรวมเข้าไว้ใน Bill Clinton กระทำในต้นฉบับ ( MASTER
) Fleetwood Mac ส่งมอบ
คุณเปิดคำขอดึงและใน GitHub คุณเห็นสิ่งนี้:
สี่กระทำ:
กำลังคิดว่าจะไม่มีใครสนใจอ่านประวัติที่เก็บข้อมูลแบบเต็ม (ที่จริงมีที่เก็บคลิกที่ลิงค์ด้านบน!) คุณตัดสินใจที่จะกำจัดสิ่งเหล่านี้ git reset --soft HEAD~4 && git commit
ดังนั้นคุณจะไปและวิ่ง จากนั้นคุณgit push --force
ก็ไปที่ GitHub เพื่อล้างค่า PR ของคุณ
แล้วจะเกิดอะไรขึ้น คุณเพิ่งทำคอมมิชชันที่ได้รับจาก Fritz ไปยัง Bill Clinton เพราะคุณลืมไปว่าเมื่อวานนี้คุณกำลังทำงานกับ Buckingham Nicks เวอร์ชันของโครงการนี้ และgit log
ไม่ตรงกับสิ่งที่คุณเห็นใน GitHub
git checkout
พวกเขาgit reset --soft
สิ่งนั้นgit commit
warps นั้นโดยตรงจากจากไปสู่หากคุณไม่สนใจเกี่ยวกับข้อความคอมมิทของคอมมิทที่อยู่ระหว่างคอมมิชชันคุณสามารถใช้
git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend
หากคุณทำงานกับ GitLab คุณสามารถคลิกตัวเลือกสควอชในคำขอรวมที่แสดงด้านล่าง ข้อความยืนยันจะเป็นชื่อของคำขอรวม
git rebase -i HEAD^^
โดยที่จำนวน ^ คือ X
(ในกรณีนี้สควอชทั้งสองกระทำล่าสุด)
นอกจากคำตอบที่ยอดเยี่ยมอื่น ๆ ฉันต้องการเพิ่มgit rebase -i
ความสับสนให้กับคำสั่งการมอบหมาย - เก่าไปใหม่กว่าหนึ่งหรือในทางกลับกันได้อย่างไร นี่คือขั้นตอนการทำงานของฉัน:
git rebase -i HEAD~[N]
ซึ่ง N คือจำนวนของการกระทำที่ฉันต้องการที่จะเข้าร่วมเริ่มต้นจากหนึ่งล่าสุด ดังนั้นgit rebase -i HEAD~5
จะหมายถึง "สควอชสุดท้าย 5 คอมมิชชันเป็นอันใหม่";สิ่งที่เกี่ยวกับคำตอบสำหรับคำถามที่เกี่ยวข้องกับเวิร์กโฟลว์เช่นนี้?
merge --squash
หลังจาก PR แต่ทีมคิดว่าจะทำให้กระบวนการช้าลง)ฉันไม่เห็นเวิร์กโฟลว์แบบนี้ในหน้านี้ (นั่นอาจเป็นนัยน์ตาของฉัน) หากฉันเข้าใจrebase
อย่างถูกต้องการผสานหลายครั้งจะต้องใช้การแก้ไขข้อขัดแย้งหลายอย่าง ฉันไม่ต้องการแม้แต่จะคิดเกี่ยวกับเรื่องนี้!
ดังนั้นดูเหมือนว่าจะได้ผลสำหรับเรา
git pull master
git checkout -b new-branch
git checkout -b new-branch-temp
git checkout new-branch
git merge --squash new-branch-temp
// เปลี่ยนการเปลี่ยนแปลงทั้งหมดในสเตจgit commit 'one message to rule them all'
git push
ฉันพบวิธีแก้ปัญหาทั่วไปเพิ่มเติมไม่ได้ระบุการยอมรับ 'N' แต่เป็น branch / commit-id ที่คุณต้องการสควอชด้านบน นี่เป็นข้อผิดพลาดน้อยกว่าการนับคอมมิทถึงการคอมมิทเฉพาะ - เพียงระบุแท็กโดยตรงหรือถ้าคุณต้องการนับคุณสามารถระบุ HEAD ~ N
ในเวิร์กโฟลว์ของฉันฉันเริ่มสาขาและความมุ่งมั่นแรกของฉันที่สาขาสรุปเป้าหมาย ฉันต้องการที่จะทำคือgit squash master
กลับไปที่ข้อความแรกจากนั้นฉันก็พร้อมที่จะผลักดัน
ฉันใช้นามแฝง:
squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i
สิ่งนี้จะถ่ายโอนข้อมูลประวัติที่ถูกบีบอัดก่อนที่จะทำเช่นนี้ซึ่งจะช่วยให้คุณมีโอกาสกู้คืนได้โดยการดึงรหัสยืนยันเก่าออกจากคอนโซลหากคุณต้องการเปลี่ยนกลับ (ผู้ใช้โซลาริสทราบว่าใช้-i
ตัวเลือกGNU sed ผู้ใช้ Mac และ Linux ควรใช้สิ่งนี้)
git squash master
เมื่อเราตรวจสอบจากทาส มันจะเกิดอะไรขึ้น? เราจะซ่อนความขัดแย้งไหม?
ในคำถามมันอาจคลุมเครือในสิ่งที่มีความหมายโดย "ล่าสุด"
เช่นgit log --graph
เอาท์พุทดังต่อไปนี้ (ประยุกต์):
* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| |
* | commit H1
| |
* | commit H2
|/
|
จากนั้นคอมมิตสุดท้ายตามเวลาคือ H0, ผสาน, B0 ในการสควอชพวกเขาคุณจะต้องรีบูทสาขาที่รวมอยู่ในการคอมมิชชัน H1
ปัญหาคือว่า H0 มี H1 และ H2 (และโดยทั่วไปจะกระทำมากกว่าก่อนที่จะรวมและหลังการแตกแขนง) ในขณะที่ B0 ทำไม่ได้ ดังนั้นคุณต้องจัดการการเปลี่ยนแปลงจาก H0, ผสาน, H1, H2, B0 อย่างน้อย
เป็นไปได้ที่จะใช้ rebase แต่ในลักษณะที่แตกต่างจากนั้นในคนอื่น ๆ กล่าวถึงคำตอบ:
rebase -i HEAD~2
ตัวเลือกนี้จะแสดงตัวเลือกให้คุณ (ดังที่ได้กล่าวไว้ในคำตอบอื่น ๆ ):
pick B1
pick B0
pick H0
ใส่สควอชแทนที่จะเลือกเป็น H0:
pick B1
pick B0
s H0
หลังจากบันทึกและออกจากการรีบูตจะมีผลบังคับใช้ในการเปิดหลังจาก H1 นั่นหมายความว่ามันจะขอให้คุณแก้ไขข้อขัดแย้งอีกครั้ง (โดยที่ HEAD จะเป็น H1 ในตอนแรกและจากนั้นจึงรวบรวมคอมมิชชันตามที่ใช้)
หลังจาก rebase จะเสร็จสิ้นคุณสามารถเลือกข้อความสำหรับ squashed H0 และ B0:
* commit squashed H0 and B0
|
* commit B1
|
* commit H1
|
* commit H2
|
PS หากคุณเพิ่งรีเซ็ตเป็น BO: (ตัวอย่างเช่นการใช้reset --mixed
ที่อธิบายไว้ในรายละเอียดเพิ่มเติมได้ที่นี่https://stackoverflow.com/a/18690845/2405850 ):
git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'
จากนั้นคุณสควอชเข้าสู่การเปลี่ยนแปลง B0 ของ H0, H1, H2 (การสูญเสียกระทำอย่างสมบูรณ์สำหรับการเปลี่ยนแปลงหลังจากการแยกและก่อนที่จะรวม
1) รีเซ็ต git - soft HEAD ~ n
n - จำนวนการคอมมิต, ต้องสควอช
2) คอมไพล์คอมมิท -m "ข้อความคอมมิทใหม่"
3) git push ต้นกำเนิด branch_name --force