สควอช X สุดท้ายของฉันกระทำด้วยกันโดยใช้ Git


3588

ฉันจะสควอช X สุดท้ายของฉันให้คอมมิตด้วย Git ได้อย่างไร?


12
คำถามที่คล้ายกัน: stackoverflow.com/questions/7275508/…
koppor

4
ที่เกี่ยวข้อง: Git - รวมหลายกระทำก่อนที่จะผลักดัน

2
@matt TortoiseGit เป็นเครื่องมือของคุณ มันมีฟังก์ชั่นเดียว "รวมถึงหนึ่งกระทำ" ซึ่งจะเรียกทุกขั้นตอนโดยอัตโนมัติในพื้นหลัง น่าเสียดายที่มีเฉพาะใน Windows ดูคำตอบของฉันด้านล่าง
Matthias M

1
สำหรับ squashing
จนถึงการ

1
โพสต์สควอชอย่างใดอย่างหนึ่งจะต้องบังคับให้กองกำลังดันstackoverflow.com/questions/10298291/ …
vikramvi

คำตอบ:


2092

การใช้งานgit rebase -i <after-this-commit>และแทนที่ "เลือก" ที่กระทำสองและต่อด้วย "สควอช" หรือ "fixup" ที่อธิบายไว้ในคู่มือการใช้งาน

ในตัวอย่าง<after-this-commit>นี้อาจเป็นแฮช SHA1 หรือตำแหน่งสัมพัทธ์จาก HEAD ของสาขาปัจจุบันที่วิเคราะห์คอมมิทสำหรับคำสั่ง rebase ตัวอย่างเช่นหากผู้ใช้ต้องการเพื่อดู 5 git rebase -i HEAD~5กระทำจากหัวปัจจุบันในอดีตคำสั่งคือ


260
ฉันคิดว่านี่ตอบคำถามนี้ได้ดีกว่าstackoverflow.com/a/5201642/295797
Roy Truelove

92
ความหมายคือ<after-this-commit>อะไร
2540625

43
<after-this-commit>คือการกระทำ X + 1 คือผู้ปกครองของการกระทำที่เก่าแก่ที่สุดที่คุณต้องการสควอช
joozek

339
ฉันพบว่าคำตอบนี้สั้นเกินไปที่จะเข้าใจอย่างไม่น่าสงสัย ตัวอย่างจะช่วย
Ian Ollmann

54
ความแตกต่างระหว่างrebase -iวิธีการนี้และreset --softคือrebase -iช่วยให้ฉันสามารถรักษาผู้เขียนกระทำในขณะที่reset --softช่วยให้ฉันแนะนำ บางครั้งฉันต้องสควอชกระทำการร้องขอดึง แต่ยังคงรักษาข้อมูลผู้เขียน บางครั้งฉันต้องรีเซ็ตซอฟท์ด้วยความมุ่งมั่นของตัวเอง ขึ้นกับคำตอบที่ยอดเยี่ยมทั้งสองคำตอบ
zionyx

3827

คุณสามารถทำเช่นนี้ได้ค่อนข้างง่ายโดยไม่ต้องหรือ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 ไปยังจุดสุดท้ายที่คุณไม่ต้องการสควอช ไม่ว่าจะเป็นดัชนีหรือแผนผังการทำงานจะถูกแตะเบา ๆ โดยปล่อยให้ดัชนีอยู่ในสถานะที่ต้องการสำหรับการกระทำใหม่ของคุณ (เช่นมีการเปลี่ยนแปลงทั้งหมดจากการกระทำที่คุณกำลังจะ "ทิ้ง")


163
ฮา! ฉันชอบวิธีนี้ มันเป็นสิ่งที่ใกล้เคียงกับจิตวิญญาณของปัญหา มันน่าเสียดายที่มันต้องใช้วูดูมากมาย ควรเพิ่มสิ่งนี้ลงในคำสั่งพื้นฐานอย่างใดอย่างหนึ่ง อาจเป็นไปได้หรือแม้กระทั่งgit rebase --squash-recent git commit --amend-many
Adrian Ratnapala

13
@ABB: หากสาขาของคุณมีการตั้งค่า "อัปสตรีม" คุณอาจจะสามารถใช้branch@{upstream}(หรือเพียงแค่@{upstream}สำหรับสาขาปัจจุบันในทั้งสองกรณีส่วนสุดท้ายสามารถย่อให้@{u}ดู; gitrevisions ) สิ่งนี้อาจแตกต่างจาก“ การผลักดันครั้งล่าสุด” ของคุณ (เช่นถ้ามีคนผลักสิ่งที่สร้างไว้บนการผลักดันล่าสุดของคุณแล้วคุณดึงข้อมูลนั้น) แต่ดูเหมือนว่ามันอาจจะใกล้เคียงกับสิ่งที่คุณต้องการ
Chris Johnsen

104
kinda-sorta นี้ต้องการให้ฉันไปpush -fแต่อย่างอื่นมันก็น่ารักขอบคุณ
2rs2ts

39
@ 2rs2ts git push -f เสียงอันตราย ระวังเฉพาะการสควอชที่กระทำในท้องถิ่น อย่าแตะต้องเลย
Matthias M

20
ฉันยังต้องใช้git push --forceหลังจากนั้นเพื่อให้ได้รับมอบหมาย
Zach Saucier

740

คุณสามารถใช้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 ในคำตอบของเขาคือคุณได้รับข้อความการส่งข้อความที่มีการส่งข้อความยืนยันทั้งหมดที่คุณกำลังส่ง


16
คุณพูดแบบนี้ว่า 'สง่างาม' มากกว่าgit rebase -iแต่คุณไม่ได้ให้เหตุผลอะไร ในแง่ที่ไม่แน่นอน -1 เนื่องจากดูเหมือนว่าสำหรับฉันแล้วในความเป็นจริงตรงกันข้ามนั้นเป็นจริงและนี่คือการแฮ็ก คุณไม่ได้ทำคำสั่งเกินความจำเป็นเพื่อบังคับgit mergeให้ทำสิ่งใดสิ่งหนึ่งที่git rebaseออกแบบมาเป็นพิเศษหรือไม่
Mark Amery

77
@ Mark Amery: มีเหตุผลหลายอย่างที่ฉันบอกว่านี่คือสง่างามมากขึ้น ตัวอย่างเช่นไม่เกี่ยวข้องกับการวางไข่แก้ไขโดยไม่จำเป็นจากนั้นค้นหาและแทนที่สตริงในไฟล์ "สิ่งที่ต้องทำ" การใช้git merge --squashยังใช้งานง่ายกว่าในสคริปต์ โดยพื้นฐานแล้วเหตุผลก็คือคุณไม่จำเป็นต้องมี "การโต้ตอบ" git rebase -iเลยสำหรับเรื่องนี้
Mark Longair

12
ข้อดีอีกอย่างคือgit merge --squashมีโอกาสน้อยที่จะสร้างความขัดแย้งในการเคลื่อนย้าย / ลบ / เปลี่ยนชื่อเมื่อเทียบกับการรีบูตโดยเฉพาะอย่างยิ่งถ้าคุณรวมจากสาขาท้องถิ่น (ข้อจำกัดความรับผิดชอบ: ขึ้นอยู่กับประสบการณ์เพียงอย่างเดียวให้แก้ไขฉันถ้านี่ไม่เป็นความจริงในกรณีทั่วไป!)
Cheezmeister

2
ฉันมักจะลังเลมากเมื่อพูดถึงเรื่องการตั้งค่าใหม่อย่างหนัก - ฉันจะใช้แท็กชั่วคราวแทนHEAD@{1}การอยู่ด้านที่ปลอดภัยเช่นเมื่อเวิร์กโฟลว์ของคุณถูกขัดจังหวะเป็นเวลาหนึ่งชั่วโมงโดยไฟดับ ฯลฯ
Tobias Kienzler

8
@BT: ทำลายความมุ่งมั่นของคุณ? :( ฉันไม่แน่ใจว่าคุณหมายถึงอะไรสิ่งใดก็ตามที่คุณให้คำมั่นว่าคุณจะสามารถกลับมาจากการอ้างอิงของ git ได้อย่างง่ายดายหากคุณมีงานที่ไม่มีข้อผูกมัด แต่ไฟล์ถูกจัดฉากคุณควรจะสามารถรับได้ เนื้อหาของพวกเขากลับมาแม้ว่าจะใช้งานได้มากกว่านี้หากงานของคุณไม่ได้จัดฉาก แต่ฉันเกรงว่าจะมีสิ่งเล็ก ๆ น้อย ๆ ที่สามารถทำได้นั่นคือเหตุผลที่คำตอบบอกล่วงหน้า: "ตรวจสอบก่อนว่าสถานะคอมไพล์สะอาด (ตั้งแต่การตั้งค่า git - ฮาร์ดจะยกเลิกการเปลี่ยนแปลงทั้งแบบ staged และ unstaged) "
Mark Longair

218

ฉันขอแนะนำให้หลีกเลี่ยงgit resetเมื่อเป็นไปได้ - โดยเฉพาะอย่างยิ่งสำหรับ Git-novices ถ้าคุณไม่จำเป็นต้องทำให้กระบวนการโดยอัตโนมัติเป็นไปตามจำนวนที่ได้ตกลงไว้มีวิธีแปลกใหม่น้อยกว่า ...

  1. ใส่คอมมิตที่จะถูกบีบลงในสาขาที่ทำงาน (หากยังไม่ได้เปิด) - ใช้ gitk สำหรับสิ่งนี้
  2. ตรวจสอบสาขาเป้าหมาย (เช่น 'ต้นแบบ')
  3. git merge --squash (working branch name)
  4. git commit

ข้อความคอมมิชชันจะถูกเติมไว้ล่วงหน้าตามสควอช


4
นี่เป็นวิธีที่ปลอดภัยที่สุด: ไม่ต้องรีเซ็ตซอฟท์ / ฮาร์ด (!!) หรือใช้การอ้างอิงซ้ำ!
TeChn4K

14
มันจะดีถ้าคุณขยายใน (1)
อดัม

2
@ อดัม: โดยทั่วไปหมายถึงใช้อินเทอร์เฟซ GUI ของgitkเพื่อติดป้ายกำกับบรรทัดรหัสที่คุณกำลังบีบอัดและติดป้ายฐานที่จะใช้สควอช ในกรณีปกติฉลากทั้งสองนี้จะมีอยู่แล้วดังนั้นสามารถข้ามขั้นตอน (1) ได้
สูงศักดิ์

3
โปรดทราบว่าวิธีนี้ไม่ได้ทำเครื่องหมายสาขาการทำงานว่าถูกผสานอย่างสมบูรณ์ดังนั้นการลบมันจึงจำเป็นต้องทำการลบ :(
Kyrstellaine

2
สำหรับ (1) ฉันพบgit branch your-feature && git reset --hard HEAD~Nวิธีที่สะดวกที่สุดแล้ว อย่างไรก็ตามมันเกี่ยวข้องกับการรีเซ็ต git อีกครั้งซึ่งคำตอบนี้พยายามหลีกเลี่ยง
eis

132

ตามคำตอบของ Chris Johnsen ,

เพิ่มนามแฝง "สควอช" ทั่วโลกจาก 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แก้ไขได้ด้วยตนเอง (หรือแก้ไขนามแฝงเพื่อให้เข้ากับรสนิยมของคุณ)


6
ที่น่าสนใจ แต่ฉันค่อนข้างจะพิมพ์ squashed กระทำข้อความด้วยตัวเองเป็นคำอธิบายสรุปของความมุ่งมั่นของฉันหลายกว่าจะมีการป้อนอัตโนมัติสำหรับฉัน ดังนั้นฉันควรระบุgit squash -m "New summary."และNกำหนดโดยอัตโนมัติเมื่อจำนวนการคอมมิชชันที่ไม่ได้ชำระ
คิวเมนตัส

1
@ABB ดูเหมือนคำถามแยกต่างหาก (ฉันไม่คิดว่ามันเป็นสิ่งที่ OP ขอมาฉันไม่เคยรู้สึกต้องการมันในเวิร์กโฟลว์สควอชคอมไพล์ของฉัน)
EthanB

3
อันนี้หวานน่ารัก โดยส่วนตัวฉันต้องการรุ่นที่ใช้ข้อความยืนยันจากคอมมิชชันแรกที่คอมมิทเข้าด้วยกัน จะดีสำหรับสิ่งต่าง ๆ เช่นการปรับช่องว่าง
funroll

@funroll ตกลง เพียงแค่ทิ้งข้อความยืนยันการทำงานล่าสุดเป็นความต้องการที่ธรรมดาสุด ๆ สำหรับฉัน เราน่าจะคิดได้ว่า ...
Steve Clay

2
@ABB คุณสามารถใช้git commit --amendเพื่อเปลี่ยนข้อความเพิ่มเติมได้ แต่นามแฝงนี้จะช่วยให้คุณเริ่มต้นได้ดีว่าควรมีอะไรในข้อความยืนยัน
dashesy

131

ขอบคุณโพสต์บล็อกที่มีประโยชน์นี้ฉันพบว่าคุณสามารถใช้คำสั่งนี้เพื่อกำจัด 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) จะอยู่ภายใต้คุณลักษณะกระทำและการเปลี่ยนแปลงไปpickfixup

เมื่อปิดตัวแก้ไขการแก้ไขจะถูกบีบเข้าสู่คุณลักษณะการส่งมอบและประวัติการส่งมอบของฉันจะดูดีและสะอาด!

สิ่งนี้ใช้ได้ดีเมื่อคอมมิชชันทั้งหมดเป็นโลคัล แต่ถ้าคุณลองเปลี่ยนคอมมิทที่ผลักไปที่รีโมตคุณสามารถสร้างปัญหาให้กับผู้พัฒนารายอื่นที่เช็คสาขาเดียวกัน!

ป้อนคำอธิบายรูปภาพที่นี่


5
คุณต้องเลือกอันดับหนึ่งและสควอชที่เหลือ? คุณควรแก้ไขคำตอบของคุณเพื่ออธิบายวิธีใช้ตัวแก้ไขการปฏิเสธแบบโต้ตอบอย่างละเอียดในรายละเอียดเพิ่มเติม
Kolob Canyon

2
ใช่ปล่อยให้pickอยู่ในบรรทัดที่ 1 หากคุณเลือกsquashหรือfixupสำหรับการกระทำที่บรรทัดที่ 1 คอมไพล์จะแสดงข้อความว่า "ข้อผิดพลาด: ไม่สามารถ 'แก้ไข' โดยไม่ต้องคอมมิชชันก่อนหน้า" จากนั้นจะให้ตัวเลือกแก่คุณในการแก้ไข: "คุณสามารถแก้ไขได้ด้วย 'รีบูต git --edit-todo' แล้วเรียกใช้ 'git rebase - ยุติ' หรือคุณสามารถยกเลิกและเริ่มต้นใหม่: "หรือคุณสามารถยกเลิกการ rebase ด้วย 'git rebase --abort'"
br3nt

56

หากคุณใช้ TortoiseGit คุณสามารถใช้ฟังก์ชันCombine to one commit:

  1. เปิดเมนูบริบทของ TortoiseGit
  2. เลือก Show Log
  3. ทำเครื่องหมายข้อผูกพันที่เกี่ยวข้องในมุมมองบันทึก
  4. เลือกCombine to one commitจากเมนูบริบท

รวมความมุ่งมั่น

ฟังก์ชั่นนี้ดำเนินการขั้นตอน git เดียวที่จำเป็นโดยอัตโนมัติ น่าเสียดายที่มีเฉพาะสำหรับ Windows


เท่าที่ฉันทราบนี้จะไม่ทำงานสำหรับการรวมกระทำ
Thorkil Holm-Jacobsen

1
แม้ว่ามันจะไม่ได้ถูกคอมเม้นท์จากผู้อื่น แต่มันก็ใช้ได้กับการกระทำที่ไม่ได้อยู่ใน HEAD ตัวอย่างเช่นความต้องการของฉันคือการกำจัด WIP บางอย่างที่ฉันทำด้วยคำอธิบายที่มีสติมากขึ้นก่อนที่จะกด ทำงานได้อย่างสวยงาม แน่นอนฉันยังคงหวังว่าฉันจะเรียนรู้วิธีการใช้คำสั่ง
ชาร์ลส์ Roberto Canato

55

ในการทำเช่นนี้คุณสามารถใช้คำสั่ง 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....

สำหรับรายละเอียดคลิกที่ลิงค์


48

จากบทความนี้ฉันพบว่าวิธีนี้ง่ายสำหรับ usecase ของฉัน

สาขา 'dev' ของฉันอยู่ก่อนหน้า 'origin / dev' โดย 96 commits (ดังนั้นคอมมิชชันเหล่านี้ยังไม่ได้ถูกผลักไปที่รีโมท)

ฉันต้องการกำจัดสิ่งเหล่านี้ให้เป็นหนึ่งก่อนผลักดันการเปลี่ยนแปลง ฉันจะรีเซ็ตสาขาเป็นสถานะของ 'ต้นทาง / dev' (นี่จะทำให้การเปลี่ยนแปลงทั้งหมดจาก 96 คอมมิทที่ไม่มีการกำหนดค่า) แล้วทำการเปลี่ยนแปลงในทันที:

git reset origin/dev
git add --all
git commit -m 'my commit message'

1
สิ่งที่ฉันต้องการ สควอชดาวน์กระทำจากสาขาคุณลักษณะของฉันแล้วฉันก็เลือกเชอร์รี่ที่มอบให้เจ้านาย
David Victor

1
นี่ไม่ได้เป็นการกระทำก่อนหน้า!
IgorGanapolsky

คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับ @igorGanapolsky ได้ไหม?
trudolf

3
@trudolf นี่ไม่ใช่การสควอชจริงๆ นี่เป็นการยอมรับการเปลี่ยนแปลงทั้งหมดของคุณในครั้งเดียว
IgorGanapolsky

15
ใช่แล้วมันจะทำให้คุณมุ่งมั่นทั้งหมด ขอแสดงความยินดี
trudolf

45

ในสาขาที่คุณต้องการรวมคอมมิชชันทำงาน:

git rebase -i HEAD~(n number of commits back to review)

ตัวอย่าง:

git rebase -i HEAD~1

สิ่งนี้จะเปิดตัวแก้ไขข้อความและคุณต้องสลับ 'เลือก' ต่อหน้าการส่งแต่ละรายการด้วย 'สควอช' หากคุณต้องการให้คอมมิชชันเหล่านี้รวมเข้าด้วยกัน จากเอกสาร:

p, pick = ใช้กระทำ

s, squash = ใช้การคอมมิต แต่รวมเข้ากับการคอมมิชชันก่อนหน้า

ตัวอย่างเช่นหากคุณต้องการรวมการกระทำทั้งหมดเข้าด้วยกันการเลือกคือสิ่งแรกที่คุณทำและสิ่งที่จะเกิดขึ้นในอนาคตทั้งหมด หากใช้เป็นกลุ่มให้ใช้: xในโหมดแทรกเพื่อบันทึกและออกจากโปรแกรมแก้ไข

จากนั้นให้ดำเนินการ rebase ต่อ:

git rebase --continue

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีนี้และวิธีอื่น ๆ ในการเขียนประวัติการส่งข้อความของคุณดูโพสต์ที่มีประโยชน์นี้


2
โปรดอธิบายสิ่งที่--continueและเสียงเรียกเข้า:xทำเช่นกัน
not2qubit

การรีบูตจะเกิดขึ้นในบล็อกในขณะที่ผ่านการคอมมิชชันในสาขาของคุณหลังจากที่คุณgit addกำหนดค่าที่ถูกต้องในไฟล์ที่คุณใช้git rebase --continueเพื่อย้ายไปยังคอมมิชชันถัดไปและเริ่มผสาน :xเป็นคำสั่งเดียวที่จะบันทึกการเปลี่ยนแปลงของไฟล์เมื่อใช้ vim ดูสิ่งนี้
aabiro

32

คำตอบที่ผิดปกติเป็นสิ่งที่ดี แต่ฉันรู้สึกไม่แน่ใจเกี่ยวกับเรื่องนี้ดังนั้นฉันจึงตัดสินใจที่จะเพิ่มภาพหน้าจอสองสามภาพ

ขั้นตอนที่ 0: บันทึก git

git logดูที่ที่คุณอยู่ด้วย สำคัญที่สุดค้นหาแฮชการคอมมิชชันของการคอมมิชชันแรกที่คุณไม่ต้องการสควอช ดังนั้นเฉพาะ:

ป้อนคำอธิบายรูปภาพที่นี่

ขั้นตอนที่ 1: การรีคอมไพล์ git

ดำเนินการgit rebase -i [your hash]ในกรณีของฉัน:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

ขั้นตอนที่ 2: เลือก / บีบสิ่งที่คุณต้องการ

ในกรณีของฉันฉันต้องการสควอชทุกอย่างในการส่งครั้งแรก สั่งซื้อจากคนแรกที่ผ่านมาดังนั้นตรงวิธีการอื่น ๆ git logในขณะที่ ในกรณีของฉันฉันต้องการ:

ป้อนคำอธิบายรูปภาพที่นี่

ขั้นตอนที่ 3: ปรับข้อความ

หากคุณเลือกการส่งและการบีบอัดที่เหลือคุณสามารถปรับการส่งข้อความได้

ป้อนคำอธิบายรูปภาพที่นี่

แค่นั้นแหละ. เมื่อคุณบันทึกสิ่งนี้ ( :wq) คุณทำเสร็จแล้ว ลองดูด้วยgit logนะ


2
จะดีที่ได้เห็นผลลัพธ์สุดท้ายเช่นgit log
ทิโมธี LJ Stewart

2
ไม่เป็นไรขอบคุณ. นี่คือสิ่งที่ฉันทำ
Axalix

@Axalix คุณลบสายของคุณทั้งหมดหรือไม่ นั่นเป็นวิธีที่คุณสูญเสียความมุ่งมั่นของคุณ
a3y3

31

ขั้นตอนที่ 1

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) คำสั่งด้านบนจะเหมือนกันยกเว้นเครื่องมือแก้ไข คุณอาจได้รับการแก้ไขที่แตกต่างกัน

ขั้นตอนที่ 2

  1. ก่อนอื่นให้เพิ่มไฟล์ที่จำเป็นสำหรับการคอมมิท
git add <files>
  1. จากนั้นส่งคอมมิชชันที่ใช้--fixupตัวเลือกและสิ่งOLDCOMMITที่เราควรจะรวม (สควอช) สิ่งนี้
git commit --fixup=OLDCOMMIT

fixup1 <OLDCOMMIT_MSG>ตอนนี้จะสร้างใหม่กระทำที่ด้านบนของหัว

  1. จากนั้นดำเนินการดังต่อไปนี้คำสั่งเพื่อผสาน (สควอช) OLDCOMMITใหม่กระทำเพื่อ
git rebase --interactive --autosquash OLDCOMMIT^

นี่หมายความว่าก่อนหน้านี้กระทำการ^ คำสั่งOLDCOMMITนี้จะrebaseเปิดหน้าต่างโต้ตอบบนเครื่องมือแก้ไข (vim หรือ nano) ที่เราไม่จำเป็นต้องทำอะไรเลยเพียงแค่บันทึกและออกก็เพียงพอแล้ว เนื่องจากตัวเลือกที่ส่งไปยังสิ่งนี้จะย้ายการส่งล่าสุดไปยังถัดจากการส่งเก่าโดยอัตโนมัติและเปลี่ยนการดำเนินการเป็นfixup (เทียบเท่ากับสควอช) จากนั้นการรีบูตจะดำเนินต่อไปและเสร็จสิ้น

ขั้นตอนที่ 3

  1. หากจำเป็นต้องเพิ่มการเปลี่ยนแปลงใหม่ไปยังหน้าล่าสุดกระทำหมายถึงสามารถใช้กับ--amendgit-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

ข้อสรุป

  • ข้อดีของขั้นตอนที่ 1 คือการสควอชหลายคอมมิทและสั่งใหม่ แต่ขั้นตอนนี้จะเป็นเรื่องยากถ้าเราจำเป็นต้องรวมการแก้ไขเพื่อคอมมิชชันเก่ามาก
  • ดังนั้นขั้นตอนที่ 2 ช่วยผสานความมุ่งมั่นกับความมุ่งมั่นที่เก่ามากได้อย่างง่ายดาย
  • และขั้นตอนที่ 3 มีประโยชน์ในกรณีที่จะสควอชการเปลี่ยนแปลงใหม่เพื่อกระทำล่าสุด

เพียงอัปเดตสองคอมมิทล่าสุดแม้ฉันจะรีเซ็ตเป็นคอมมิทถึงการคอมมิทครั้งที่ 6 ไม่รู้ทำไม
Carlos Liu

แม้คุณสามารถจัดเรียงคำสั่งการส่งใหม่ได้ มันใช้งานได้ดี
rashok

29

หากต้องการสควอช 10 ครั้งสุดท้ายให้คอมมิชชันเดียว:

git reset --soft HEAD~10 && git commit -m "squashed commit"

หากคุณต้องการอัปเดตสาขาระยะไกลด้วยสควอชคอมมิต:

git push -f

- บังคับเป็นสิ่งที่อันตรายเมื่อมีหลายคนทำงานในสาขาที่ใช้ร่วมกันเนื่องจากเป็นการอัพเดตแบบรีโมตด้วยสำเนาโลคัลของคุณ - บังคับกับการเช่าอาจดีกว่าเพราะทำให้มั่นใจว่าระยะไกลไม่มีข้อผูกมัดจากผู้อื่นตั้งแต่คุณดึงข้อมูลล่าสุด
bharath

27

หากคุณอยู่ในสาขาระยะไกล (เรียกว่าfeature-branch) ที่ถูกโคลนจากพื้นที่เก็บข้อมูลทองคำ ( golden_repo_name) แล้วนี่เป็นเทคนิคในการสควอชคอมมิชชันของคุณเป็นหนึ่ง:

  1. ชำระเงิน repo ทอง

    git checkout golden_repo_name
    
  2. สร้างสาขาใหม่จาก (repo ทองคำ) ดังนี้

    git checkout -b dev-branch
    
  3. สควอชผสานกับสาขาท้องถิ่นของคุณที่คุณมีอยู่แล้ว

    git merge --squash feature-branch
    
  4. กระทำการเปลี่ยนแปลงของคุณ (นี่จะเป็นสิ่งเดียวที่กระทำใน dev-branch)

    git commit -m "My feature complete"
    
  5. ผลักสาขาไปยังพื้นที่เก็บข้อมูลในท้องถิ่นของคุณ

    git push origin dev-branch
    

เนื่องจากฉันเพิ่งถูกบีบประมาณ 100 คอมมิต (สำหรับการซิงค์สาขา svn ผ่าน git-svn) นี่เร็วกว่าการรีบูตแบบโต้ตอบ!
ปราชญ์

1
อ่านลงฉันเห็นความคิดเห็นของ @ Chris ซึ่งเป็นสิ่งที่ฉันเคยทำ (rebase - soft ... ) - เลวร้ายเกินไปที่ stackoverflow ไม่ได้ใส่คำตอบกับ upvotes อีกหลายร้อยที่ด้านบน ...
ปราชญ์

1
เห็นด้วยกับคุณ @sage ให้หวังว่าพวกเขาจะทำมันได้ในอนาคต
Sandesh Kumar

นี่เป็นวิธีที่ถูกต้อง วิธีการ Rebase นั้นดี แต่ควรใช้สำหรับสควอชเป็นทางเลือกสุดท้ายเท่านั้น
Axalix

20

สิ่งที่สามารถจะสะดวกจริงๆ: ค้นหากระทำกัญชาคุณต้องการสควอชที่ด้านบนของการพูด
d43e15

ตอนนี้ใช้

git reset d43e15
git commit -am 'new commit name'

2
นี้. ทำไมไม่มีคนใช้อีกต่อไป มันเร็วกว่าการรีบูตและการบีบแต่ละครั้ง
a3y3

17

นี่เป็น 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 ปัญหาแม้ว่า


7
+1: มันสนุกและให้คำแนะนำเพราะฉันไม่เห็นชัดเจนเลยว่าคุณสามารถใส่อะไรที่ซับซ้อนกว่าชื่อของโปรแกรมในตัวแปรสภาพแวดล้อม GIT_EDITOR
Mark Longair

16

หากคุณต้องการ squish ทุกการกระทำในการกระทำเดียว (เช่นเมื่อปล่อยโครงการสาธารณะเป็นครั้งแรก) ให้ลอง:

git checkout --orphan <new-branch>
git commit

14

ฉันคิดว่าวิธีที่ง่ายที่สุดในการทำเช่นนี้คือการทำให้สาขาใหม่หลุดจากต้นแบบและทำการผสาน - ถอนออกจากสาขาฟีเจอร์

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

จากนั้นคุณมีการเปลี่ยนแปลงทั้งหมดพร้อมที่จะกระทำ


14

2563โซลูชั่นง่าย ๆโดยไม่ต้องรีบูต:

git reset --soft HEAD~2

git commit -m "new commit message"

git push --force

2 หมายความว่าคอมมิชชันสุดท้ายจะถูกแบน คุณสามารถแทนที่ด้วยหมายเลขใดก็ได้


12

Simple one-liner ที่ใช้งานได้ตลอดเวลาเนื่องจากคุณอยู่ในสาขาที่คุณต้องการสควอชมาสเตอร์เป็นสาขาที่มาจากการกระทำล่าสุดและคอมมิชชันล่าสุดประกอบด้วยข้อความคอมมิทและผู้แต่งที่คุณต้องการใช้:

git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}

4
ฉันรู้สึกสับสนอย่างมากเกี่ยวกับการบีบอัดคอมมิชชันและความซับซ้อนอย่างโง่เขลาเพียงแค่ใช้ข้อความสุดท้ายและสควอชพวกเขาให้เป็นหนึ่งเดียว! ทำไมมันถึงยากขนาดนั้น ???? ซับอันนี้ทำเพื่อฉัน ขอบคุณจากก้นบึ้งของหัวใจฉัน
Locane

12

หากตัวอย่างเช่นคุณต้องการสควอช 3 ครั้งล่าสุดจะคอมมิชชันเดียวในสาขา (ที่เก็บข้อมูลระยะไกล) ในตัวอย่าง: https://bitbucket.org

สิ่งที่ฉันทำคือ

  1. รีเซ็ต git - ซอฟต์เฮด ~ 3 &&
  2. คอมไพล์
  3. git push กำเนิด (branch_name) - บังคับ

3
เพียงระวังเพราะถ้าคุณใช้กำลังก็ไม่มีทางที่จะเรียกคืนคอมมิชชันก่อนหน้านี้ได้เนื่องจากคุณลบมันออก
อัลเบิร์ต Ruelan

12

⚠️คำเตือน: "การยอมรับครั้งสุดท้ายของฉัน" อาจไม่ชัดเจน

  (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 คุณเห็นสิ่งนี้:

สี่กระทำ:

  • เพิ่ม Danny Kirwan
  • เพิ่มคริสตินที่สมบูรณ์แบบ
  • LA1974
  • บิลคลินตัน

กำลังคิดว่าจะไม่มีใครสนใจอ่านประวัติที่เก็บข้อมูลแบบเต็ม (ที่จริงมีที่เก็บคลิกที่ลิงค์ด้านบน!) คุณตัดสินใจที่จะกำจัดสิ่งเหล่านี้ git reset --soft HEAD~4 && git commitดังนั้นคุณจะไปและวิ่ง จากนั้นคุณgit push --forceก็ไปที่ GitHub เพื่อล้างค่า PR ของคุณ

แล้วจะเกิดอะไรขึ้น คุณเพิ่งทำคอมมิชชันที่ได้รับจาก Fritz ไปยัง Bill Clinton เพราะคุณลืมไปว่าเมื่อวานนี้คุณกำลังทำงานกับ Buckingham Nicks เวอร์ชันของโครงการนี้ และgit logไม่ตรงกับสิ่งที่คุณเห็นใน GitHub

OR คุณธรรมของเรื่องราว

  1. ค้นหาไฟล์ที่คุณต้องการที่จะได้รับไปและgit checkoutพวกเขา
  2. ค้นหาคำมั่นสัญญาที่แน่นอนที่คุณต้องการเก็บไว้ในประวัติศาสตร์และgit reset --softสิ่งนั้น
  3. ทำให้git commitwarps นั้นโดยตรงจากจากไปสู่

1
นี่เป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้ 100% หาก HEAD ปัจจุบันของคุณเป็นสถานะที่ถูกต้องที่คุณต้องการคุณสามารถข้าม # 1
สแตน

นี่เป็นวิธีเดียวที่ฉันรู้ว่าช่วยให้สามารถเขียนประวัติการส่งมอบครั้งแรกได้
Vadorequest

9

หากคุณไม่สนใจเกี่ยวกับข้อความคอมมิทของคอมมิทที่อยู่ระหว่างคอมมิชชันคุณสามารถใช้

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend

7

หากคุณทำงานกับ GitLab คุณสามารถคลิกตัวเลือกสควอชในคำขอรวมที่แสดงด้านล่าง ข้อความยืนยันจะเป็นชื่อของคำขอรวม

ป้อนคำอธิบายรูปภาพที่นี่


6
git rebase -i HEAD^^

โดยที่จำนวน ^ คือ X

(ในกรณีนี้สควอชทั้งสองกระทำล่าสุด)


6

นอกจากคำตอบที่ยอดเยี่ยมอื่น ๆ ฉันต้องการเพิ่มgit rebase -iความสับสนให้กับคำสั่งการมอบหมาย - เก่าไปใหม่กว่าหนึ่งหรือในทางกลับกันได้อย่างไร นี่คือขั้นตอนการทำงานของฉัน:

  1. git rebase -i HEAD~[N]ซึ่ง N คือจำนวนของการกระทำที่ฉันต้องการที่จะเข้าร่วมเริ่มต้นจากหนึ่งล่าสุด ดังนั้นgit rebase -i HEAD~5จะหมายถึง "สควอชสุดท้าย 5 คอมมิชชันเป็นอันใหม่";
  2. ตัวแก้ไขปรากฏขึ้นโดยแสดงรายการข้อผูกพันที่ฉันต้องการผสาน ตอนนี้พวกเขาจะแสดงในลำดับย้อนกลับ : การกระทำที่เก่ากว่าอยู่ด้านบน ทำเครื่องหมายว่า "สควอช" หรือ "s" ทั้งหมดที่กระทำในนั้นยกเว้นอันแรก / อันที่เก่ากว่า : มันจะถูกใช้เป็นจุดเริ่มต้น บันทึกและปิดเครื่องมือแก้ไข
  3. บรรณาธิการจะปรากฏขึ้นอีกครั้งพร้อมข้อความเริ่มต้นสำหรับการส่งข้อความใหม่: เปลี่ยนตามความต้องการของคุณบันทึกและปิด สควอชเสร็จแล้ว!

แหล่งที่มาและเพิ่มเติมอ่าน: # 1 , # 2


6

สิ่งที่เกี่ยวกับคำตอบสำหรับคำถามที่เกี่ยวข้องกับเวิร์กโฟลว์เช่นนี้?

  1. กระทำในท้องถิ่นจำนวนมากผสมกับการผสานหลายอย่างจากต้นแบบ ,
  2. ในที่สุดก็ผลักไปที่ระยะไกล
  3. การประชาสัมพันธ์และการผสานการต้นแบบโดยวิจารณ์ (ใช่มันจะง่ายกว่าสำหรับผู้พัฒนาmerge --squashหลังจาก PR แต่ทีมคิดว่าจะทำให้กระบวนการช้าลง)

ฉันไม่เห็นเวิร์กโฟลว์แบบนี้ในหน้านี้ (นั่นอาจเป็นนัยน์ตาของฉัน) หากฉันเข้าใจrebaseอย่างถูกต้องการผสานหลายครั้งจะต้องใช้การแก้ไขข้อขัดแย้งหลายอย่าง ฉันไม่ต้องการแม้แต่จะคิดเกี่ยวกับเรื่องนี้!

ดังนั้นดูเหมือนว่าจะได้ผลสำหรับเรา

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. แก้ไขและคอมมิชชันในพื้นที่มาก ๆ ผสานต้นแบบอย่างสม่ำเสมอ
  5. git checkout new-branch
  6. git merge --squash new-branch-temp // เปลี่ยนการเปลี่ยนแปลงทั้งหมดในสเตจ
  7. git commit 'one message to rule them all'
  8. git push
  9. ผู้ตรวจทานทำการประชาสัมพันธ์และผสานรวมกับผู้เชี่ยวชาญ

จากความคิดเห็นมากมายฉันชอบแนวทางของคุณ สะดวกและรวดเร็วมาก
Artem Solovev

5

ฉันพบวิธีแก้ปัญหาทั่วไปเพิ่มเติมไม่ได้ระบุการยอมรับ '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 ควรใช้สิ่งนี้)


ฉันลองใช้นามแฝงแล้ว แต่ฉันไม่แน่ใจว่าตัวเลือกแทนที่จะมีผลหรือไม่ พวกเขาควรทำอย่างไร
ฝนตก

sed แรกเพียงทิ้งประวัติศาสตร์ไปยังคอนโซล sed ที่สองแทนที่ 'pick' ด้วย 'f' (fixup) ทั้งหมดและเขียนไฟล์เอดิเตอร์แบบแทนที่ (อ็อพชัน -i) ดังนั้นอันที่สองก็ทำงานได้ทั้งหมด
อีธาน

คุณพูดถูกการนับจำนวนเฉพาะของเอ็นคอมมิทนั้นเป็นเรื่องที่ผิดพลาดมาก มันทำให้ฉันเมาหลายครั้งและเสียเวลาหลายชั่วโมงพยายามที่จะเลิกทำการรีบูท
IgorGanapolsky

สวัสดีอีธานฉันอยากรู้ว่าเวิร์กโฟลว์นี้จะซ่อนความขัดแย้งที่อาจเกิดขึ้นกับการรวมหรือไม่ ดังนั้นโปรดพิจารณาหากคุณมีสองสาขาหลักและทาส หากทาสมีข้อขัดแย้งกับเจ้านายและเราใช้git squash masterเมื่อเราตรวจสอบจากทาส มันจะเกิดอะไรขึ้น? เราจะซ่อนความขัดแย้งไหม?
Sergio Bilello

@Sergio นี่เป็นกรณีของการเขียนประวัติศาสตร์ใหม่ดังนั้นคุณอาจจะมีความขัดแย้งหากคุณสควอชยอมรับว่าได้ถูกผลักไปแล้วจากนั้นลองผสาน / รีบูตเวอร์ชันสควอชกลับมา (คดีเล็ก ๆ น้อย ๆ อาจหายไปได้)
Ethan

5

ในคำถามมันอาจคลุมเครือในสิ่งที่มีความหมายโดย "ล่าสุด"

เช่น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 (การสูญเสียกระทำอย่างสมบูรณ์สำหรับการเปลี่ยนแปลงหลังจากการแยกและก่อนที่จะรวม


4

1) รีเซ็ต git - soft HEAD ~ n

n - จำนวนการคอมมิต, ต้องสควอช

2) คอมไพล์คอมมิท -m "ข้อความคอมมิทใหม่"

3) git push ต้นกำเนิด branch_name --force

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.