สควอชคุณตกลงในแพทช์เดียวด้วย git format-patch อย่างไร


163

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

git format-patch master HEAD # yields zillions of patches, even though there's 
                             # only one commit since master

ฉันอยากรู้ว่าคุณจะใช้วิธีใดในข้อเสนอด้านล่างนี้ แจ้งให้เราทราบ;)
VonC

4
ฉันจะใช้คอมไพล์ git ตามที่ Rob Di Marco แนะนำ แต่ฉันหยุดทำงานเป็นเวลาสองสัปดาห์โดยเพิ่งได้เห็นการเกิดของเด็กผู้หญิงคนที่สองของฉันเมื่อคืนดังนั้นมันจะชั่วครู่ก่อนที่ฉันจะใช้มัน! :)
skiphoppy

2
ฉันชอบที่จะเห็น git format-patch - หัวหน้าควอชหัวหน้า
schoetbi

1
ลองต้นแบบ .. หัวหน้าเพื่อระบุช่วง rev
Konrad Kleine

คำตอบ:


186

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

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

หวังว่านี่จะช่วยได้!


2
นี่คือสิ่งที่ฉันใช้เมื่อฉันต้องการเก็บประวัติไว้ในเครื่อง (ในกรณีที่ฉันต้องแก้ไขโปรแกรมแก้ไข) มิฉะนั้นฉันก็ใช้ rebase -i และสควอชคอมมิชชัน
sebnow

5
สำหรับฉันแล้วมันทำงานได้อย่างน่าเชื่อถือมากขึ้นgit comit -m "My squashed commits"มิฉะนั้นจะเพิ่มไฟล์ที่ไม่ได้ติดตามอื่น ๆ
เซบาสเตียน

นอกจากนี้คุณสามารถสลับไปยังการคอมมิทเฉพาะแทนมาสเตอร์และทำสิ่งนี้เพื่อสร้างแพทช์จากการคอมมิทถึงคอมมิท:git checkout 775ec2a && git checkout -b patch && git merge --squash branchname
Berry M.

131

เพียงเพิ่มโซลูชันอีกหนึ่งรายการลงในหม้อ: หากคุณใช้วิธีนี้แทน:

git format-patch master --stdout > my_new_patch.diff

จากนั้นก็จะยังคงเป็น 8 แพตช์ ... แต่พวกเขาทั้งหมดจะอยู่ใน patchfile เดียวและจะใช้เป็นหนึ่งเดียวกับ:

git am < my_new_patch.diff

13
ฉันชอบวิธีนี้ เป็นที่น่าสังเกตว่าบางครั้งมันอาจสร้าง patch ที่ใหญ่กว่าวิธีที่ @Adam Alexander อธิบายไว้ นี่เป็นเพราะบางไฟล์อาจถูกแก้ไขมากกว่าหนึ่งครั้งผ่านการกระทำ วิธีการนี้จะถือว่าการกระทำแต่ละรายการแยกกันแม้ว่าไฟล์บางไฟล์จะถูกย้อนกลับ แต่ส่วนใหญ่แล้วนี่ไม่ใช่ปัญหา
gumik

1
ตัวเลือกนี้ยอดเยี่ยมถ้าคุณพยายามหลีกเลี่ยงการรวมกัน! (เช่นคุณต้องการข้ามบางคอมมิท) คุณยังสามารถgit rebase -i ...และสควอชพวกเขาทั้งหมดเป็นหนึ่ง
Jorge Orpinel

21

ฉันมักจะใช้คอมไพล์ diff ในตัวอย่างของคุณ

git diff master > patch.txt

15
ยกเว้นว่าคุณจะผูกมัดข้อความและข้อมูลเมตาทั้งหมด ความสวยงามของ git format-patch คือมันเป็นไปได้ที่จะสร้างทั้งสาขาใหม่จากชุดของแพทช์
mcepl

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

อันที่จริงข้อความที่รวมกันสามารถทำได้โดยใช้git logดูคำตอบของฉันสำหรับตัวอย่าง
woojoo666

2
ตัวเลือกที่ดี แต่ให้พิจารณาว่า 'git diff' ไม่สามารถรวมความแตกต่างแบบไบนารีได้ (อาจมีตัวเลือกให้ทำ)
Santiago Villafuerte

18

นี่คือการปรับคำตอบของอเล็กซานเดอร์ในกรณีที่การเปลี่ยนแปลงของคุณอยู่ในกิ่ง ทำสิ่งต่อไปนี้:

  • สร้างสาขาใหม่ทิ้ง "tmpsquash" จากจุดที่เราต้องการ (มองหาคีย์ SHA ที่ใช้ "git --log" หรือด้วย gitg เลือกการกระทำที่คุณต้องการเป็นหัว tmpsquash การกระทำที่อยู่ในนั้นจะเป็น การกระทำที่ถูกแบน)
  • รวมการเปลี่ยนแปลงจากต้นแบบเป็น tmpsquash
  • คอมมิตการเปลี่ยนแปลงที่ถูกแบนไปเป็น tmpsquash
  • สร้างชุดข้อมูลแก้ไขด้วยการคอมมิต
  • กลับไปที่สาขาหลัก

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$

การเปลี่ยนแปลงต้นแบบเป็นรูปแบบการต่อต้านหากคุณจะไม่ผลักพวกเขาให้ห่างไกลตัวเอง และถ้าคุณต้องการคุณอาจไม่จำเป็นต้องสร้างไฟล์ปะแก้สำหรับพวกเขา
ivan_pozdeev

18

ตามที่คุณรู้อยู่แล้วgit format-patch -8 HEADจะให้แปดแผ่น

หากคุณต้องการให้ 8 คอมมิชชันของคุณปรากฏเป็นหนึ่งเดียวและไม่ควรเขียนประวัติของสาขา ( o-o-X-A-B-C-D-E-F-G-H) ใหม่คุณสามารถ:

git rebase -i
// squash A, B, C, D, E ,F, G into H

หรือและมันจะเป็นทางออกที่ดีกว่าให้เล่น 8 คอมมิทใหม่ทั้งหมดจากคอมมิทXใหม่

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

ด้วยวิธีนี้คุณมีเพียงหนึ่งการกระทำที่สาขา "การจัดส่ง" และมันแสดงถึงการกระทำทั้งหมด 8 ครั้งล่าสุดของคุณ


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

5

Format-patch ระหว่างสองแท็ก:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>

5

วิธีที่ง่ายที่สุดคือการใช้git diffและเพิ่มgit logถ้าคุณต้องการข้อความคอมมิทรวมที่เมธอดสควอชจะแสดงผล ตัวอย่างเช่นในการสร้างแพทช์ระหว่างกระทำabcdและ1234:

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

จากนั้นเมื่อใช้แพทช์:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

อย่าลืม--binaryอาร์กิวเมนต์git diffเมื่อต้องจัดการกับไฟล์ที่ไม่ใช่ข้อความเช่นรูปภาพหรือวิดีโอ


0

ตามคำตอบของ Adam Alexander:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.