ผสาน (กับสควอช) การเปลี่ยนแปลงทั้งหมดจากสาขาอื่นเป็นการกระทำเดียว


479

ใน Git มีวิธีใดที่จะรวมการเปลี่ยนแปลงทั้งหมดจากสาขาหนึ่งไปยังอีกสาขาหนึ่ง แต่สควอชไปเป็นคอมมิชชันเดียวในเวลาเดียวกันได้หรือไม่?

ฉันมักจะทำงานในคุณสมบัติใหม่ในสาขาที่แยกต่างหากและจะกระทำ / ผลักดันเป็นประจำ - ส่วนใหญ่สำหรับการสำรองข้อมูลหรือถ่ายโอนสิ่งที่ฉันกำลังทำงานกับเครื่องอื่น ความมุ่งมั่นเหล่านั้นส่วนใหญ่พูดว่า "Feature xxx WIP" หรือสิ่งที่ซ้ำซ้อน

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

มีวิธีง่าย ๆ ในการทำเช่นนี้?

อีกวิธีหนึ่งคำสั่งที่ลบล้างการคอมมิททั้งหมดในสาขาตั้งแต่จุดที่มันถูกแยกออก?

คำตอบ:


601

ตัวเลือกหนึ่งคือในที่สุดก็ทำgit merge --squash <feature branch>git commit

จากการรวม Git

--squash

--no-squash

สร้างแผนผังการทำงานและสถานะดัชนีราวกับว่ามีการผสานจริงเกิดขึ้น (ยกเว้นข้อมูลการผสาน) แต่อย่าทำการคอมมิตหรือย้ายHEADหรือบันทึก $GIT_DIR/MERGE_HEADเพื่อทำให้git commitคำสั่งถัดไป เพื่อสร้างการคอมมิชชัน สิ่งนี้ช่วยให้คุณสามารถสร้างการคอมมิชชันเดียวที่ด้านบนของสาขาปัจจุบันที่มีผลเหมือนกับการรวมสาขาอื่น (หรือมากกว่าในกรณีของปลาหมึกยักษ์)


1
คุณสมบัติเจ๋ง! ฉันรักคอมไพล์ ในขณะที่ฉันจะใช้สิ่งนี้ในอนาคตตอนนี้ฉันยังคงแนะนำให้รู้จักวิธีหลีกเลี่ยงการใช้ -i มันเป็นทักษะที่ดีที่มีในกรณีที่คุณต้องการทำให้พวกเขาเป็นมากกว่าการกระทำ
Will Buck

4
คำเตือน: ใช้งานได้ แต่ข้อความการส่งข้อความเริ่มต้นรวมถึงบันทึกจากสาขาที่กำลังผสาน ปัญหาคือมันดูคล้ายกับรูปแบบที่คุณเห็นตามปกติซึ่งข้อความทั้งหมดที่แสดงไม่ได้เป็นส่วนหนึ่งของข้อความยืนยัน แต่ในกรณีนี้มันเป็นเช่นนั้น ดังนั้นหากคุณไม่ต้องการทั้งหมดคุณต้องลบมันทั้งหมดออกจากข้อความยืนยัน ฉันควรจะทดสอบสิ่งนี้ก่อนที่จะใช้ ...
Still_dreaming_1

23
สิ่งนั้นและได้รับการเตือนว่าจะไม่ถูกมองว่าเป็นการรวมสาขา stackoverflow.com/questions/19308790/…
Ryan

3
IMHO สิ่งนี้ควรได้รับการเรียกrebase --squash
แอนดี้

ดังนั้น (เนื่องจากมันไม่ได้รวมสาขาฟีเจอร์) มันจะเหมาะสมถ้าคุณกำลังจะลบสาขาฟีเจอร์หลังจากคอมมิท ถูกต้องไหม (ฉันไม่ใช่ผู้เชี่ยวชาญคอมไพล์)
Andrew Spencer

214

พบมัน! คำสั่งผสานมี--squashตัวเลือก

git checkout master
git merge --squash WIP

ณ จุดนี้ทุกอย่างถูกรวมเข้าด้วยกันอาจมีความขัดแย้ง แต่ไม่มุ่งมั่น ดังนั้นตอนนี้ฉันสามารถ:

git add .
git commit -m "Merged WIP"

2
สิ่งที่ไม่git add .ทำอะไร?
Michael Potter

1
@MichaelPotter มันเพิ่มไฟล์และการเปลี่ยนแปลงทั้งหมด
Daksh Shah

2
git add .เพิ่มไฟล์ที่ไม่ได้เพิกเฉยทั้งหมดในไดเรกทอรีปัจจุบันฉันจะระวังในการเก็บไฟล์ที่ไม่ได้ตั้งใจด้วยวิธีนี้
Jake Cobb

7
ในฐานะที่เป็นทางเลือกgit add .คุณสามารถใช้git add -uเพื่อเพิ่มไฟล์ที่เพิ่มไว้ในทรีแล้วเท่านั้น
Brandon Ogle

19
แนะนำว่า "git เพิ่ม" ทำยังสับสน เมื่อฉันทำ "คอมไพล์ผสาน - สควอช WIP" มันมีการเปลี่ยนแปลงแบนในดัชนีแล้ว สิ่งที่จำเป็นต้องทำก็คือกระทำ กำลังทำ "git add" จะเพิ่มการเปลี่ยนแปลงที่เกิดขึ้นในไดเรกทอรีการทำงาน แต่ไม่ได้เป็นส่วนหนึ่งของสาขาคุณลักษณะ คำถามคือทำอย่างไรจึงจะเปลี่ยนแปลงการกระทำในฟีเจอร์สาขาได้เช่นเดียวกับการคอมมิชชัน
John Pankowicz

30

ลองgit rebase -i masterที่สาขาฟีเจอร์ของคุณ จากนั้นคุณสามารถเปลี่ยนทั้งหมดยกเว้น 'เลือก' เป็น 'สควอช' เพื่อรวมการกระทำ ดูsquashing มุ่งมั่นกับ rebase

ในที่สุดคุณสามารถทำการผสานจากสาขาหลัก


8
ใช่มันใช้งานได้ แต่ฉันไม่ต้องการให้มีการรีบูตแบบโต้ตอบ ฉันต้องการทุกอย่างตั้งแต่กิ่งแบน
แบรดโรบินสัน

2
+1 สิ่งนี้ทำให้มีประวัติที่สะอาด มันง่ายมากที่จะระบุและจัดการกระทำเป็นแต่ละแพทช์, การ์ด, เรื่องราว ฯลฯ
ไรอัน

2

ใช้git merge --squash <feature branch>เป็นคำตอบที่ยอมรับได้นั้นเป็นการหลอกลวง แต่จะไม่แสดงสาขาที่ผสานตามที่ผสานจริง

ดังนั้นทางออกที่ดีกว่าคือ:

  • สร้างสาขาใหม่จากต้นแบบล่าสุด
  • ผสาน <feature branch>เข้ากับการใช้ข้างต้นgit merge --squash
  • ผสานสาขาที่สร้างขึ้นใหม่เข้ากับต้นแบบ

วิกินี้อธิบายขั้นตอนโดยละเอียด


0

ฉันได้สร้างนามแฝงคอมไพล์ของตัวเองเพื่อทำสิ่งนี้ ฉันเรียกมันว่าgit freebase ! จะทำให้สาขาฟีเจอร์ที่ยุ่งเหยิงไม่สามารถแก้ไขได้ของคุณและสร้างมันขึ้นมาใหม่เพื่อให้มันกลายเป็นสาขาใหม่ที่มีชื่อเดียวกันกับคอมมิชชันที่ถูกบีบอัดไว้ในคอมมิชชันที่คอมมิชชัน ในตอนท้ายมันจะช่วยให้คุณสามารถใช้สิ่งที่กระทำข้อความที่คุณต้องการสำหรับสาขา "ฟรีตาม" ใหม่ของคุณ

ติดตั้งโดยใส่นามแฝงต่อไปนี้ใน. gitconfig ของคุณ:

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

ใช้จากสาขาฟีเจอร์ของคุณโดยเรียกใช้: git freebase <new-base>

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

ฉันจะรักษามันไว้ใน dotfiles repo บน github: https://github.com/stevecrozz/dotfiles/blob/master/.gitconfig


ทำงานเหมือนความสุข! คุณอาจดูที่Evernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/…
Ilya Sheershoff

-1

git merge --squash <feature branch> เป็นตัวเลือกที่ดี "การคอมไพล์คอมไพล์" จะบอกให้คุณทราบทุกฟีเจอร์การคอมมิทข้อความที่คุณเลือกเก็บไว้

สำหรับการผสานที่น้อยลง

git merge do x times --git reset HEAD ^ - soft แล้วคอมไพล์คอมมิท

ความเสี่ยง - ไฟล์ที่ถูกลบอาจกลับมา


-5

คุณสามารถทำได้ด้วยคำสั่ง "rebase" มาเรียกกิ่งไม้ "หลัก" และ "คุณสมบัติ":

git checkout feature
git rebase main

คำสั่ง rebase จะเล่นซ้ำทั้งหมดของการกระทำใน "คุณสมบัติ" เป็นหนึ่งกระทำกับผู้ปกครองเท่ากับ "หลัก"

คุณอาจต้องการเรียกใช้git merge mainก่อนgit rebase mainถ้ามีการเปลี่ยนแปลง "หลัก" เนื่องจาก "คุณสมบัติ" ถูกสร้างขึ้น (หรือตั้งแต่การผสานล่าสุด) ด้วยวิธีนี้คุณยังมีประวัติเต็มของคุณในกรณีที่คุณมีข้อขัดแย้งผสาน

หลังการรีบูตคุณสามารถผสานสาขาของคุณเข้ากับเมนซึ่งจะทำให้การผสานข้างหน้ารวดเร็ว:

git checkout main
git merge feature

ดูหน้าrebaseของการทำความเข้าใจ Git Conceptuallyสำหรับภาพรวมที่ดี


สิ่งนี้ไม่ได้ผลสำหรับฉัน ฉันเพิ่งสร้าง repo ทดสอบง่ายๆด้วยสาขา WIP และลองข้างต้นและได้รับความขัดแย้งผสาน (แม้ว่าฉันไม่ได้ทำการเปลี่ยนแปลงใด ๆ กับต้นแบบ)
แบรดโรบินสัน

หากคุณลักษณะถูกสร้างขึ้นจาก main (git checkout -b feature main) และคุณได้ทำการผสานล่าสุดจาก main คุณไม่ควรได้รับข้อขัดแย้งจาก rebase
NamshubWriter

ตกลงลองอีกครั้ง ไม่ได้รับความขัดแย้งในครั้งนี้ แต่ประวัติศาสตร์ไม่ได้ถูกแบน
แบรดโรบินสัน

ลองดูที่เอกสารประกอบการเขียน git-merge อีกครั้งคุณจะถูกต้องข้อผูกพันบางอย่างจะยังคงอยู่ หากคุณทำการผสานก่อนหน้าจากคุณลักษณะ "หลัก" ถึง "แล้วการรีบูตจะลบบางส่วนออก แต่ไม่ใช่ทั้งหมด
NamshubWriter

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