วิธีเพิ่มไฟล์ที่เปลี่ยนแปลงไปยังคอมมิชชันเก่า (ไม่ใช่ครั้งสุดท้าย) ใน Git


461

ฉันเปลี่ยนหลายสิ่งในชั่วโมงที่ผ่านมาและยืนยันทีละขั้นตอน แต่ฉันเพิ่งรู้ว่าฉันลืมเพิ่มไฟล์ที่เปลี่ยนแปลงบางคอมมิชชันที่แล้ว

บันทึกมีลักษณะดังนี้:

    GIT TidyUpRequests u:1 d:0> git log 
    commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:43:55 2010 +0200

        The Main program now tests both Webservices at once

    commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463 
    Author: David Klein <>
    Date:   Tue Apr 27 09:43:27 2010 +0200

        ISBNDBQueryHandler now uses the XPath functions from XPath.fs too

    commit 06a504e277fd98d97eed4dad22dfa5933d81451f 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:30:34 2010 +0200

        AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs

    commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
    Author: David Klein <> 
    Date:   Tue Apr 27 09:29:53 2010 +0200

        Factored out some common XPath Operations

ความคิดใด ๆ


คำตอบ:


694

git rebaseใช้ โดยเฉพาะ:

  1. ใช้git stashสำหรับจัดเก็บการเปลี่ยนแปลงที่คุณต้องการเพิ่ม
  2. ใช้git rebase -i HEAD~10(หรือหลายครั้งที่คุณต้องการเห็น)
  3. เป็นเครื่องหมายของการกระทำในคำถาม ( a0865...) สำหรับการแก้ไขโดยการเปลี่ยนคำในช่วงเริ่มต้นของเส้นเข้าไปในpick editอย่าลบบรรทัดอื่นที่จะลบการกระทำ [^ vimnote]
  4. บันทึกไฟล์ rebase และ git จะกลับไปที่เชลล์และรอให้คุณแก้ไขการคอมมิทนั้น
  5. ป๊อปสะสมโดยใช้ git stash pop
  6. git add <file>เพิ่มไฟล์ของคุณด้วย
  7. git commit --amend --no-editแก้ไขการกระทำด้วย
  8. ทำสิ่งgit rebase --continueที่จะเขียนส่วนที่เหลือของคุณมุ่งมั่นกับใหม่
  9. ทำซ้ำตั้งแต่ขั้นตอนที่ 2 ขึ้นไปหากคุณทำเครื่องหมายมากกว่าหนึ่งคอมมิทเพื่อทำการแก้ไข

[^ vimnote]: หากคุณใช้งานอยู่vimคุณจะต้องกดInsertปุ่มเพื่อแก้ไขจากนั้นEscพิมพ์:wqเพื่อบันทึกไฟล์ออกจากโปรแกรมแก้ไขและใช้การเปลี่ยนแปลง หรือคุณสามารถกำหนดค่าคอมไพล์ที่ใช้งานง่ายกระทำการแก้ไขgit config --global core.editor "nano"ด้วย


23
จะเป็นอย่างไรถ้าคุณมีการเปลี่ยนแปลงแบบไม่สเตจที่คุณต้องการเพิ่มในการแก้ไข git addถ้าฉันซ่อนพวกเขาก็ไม่สามารถทำได้
Sam

15
Sam คุณสามารถปลดการเปลี่ยนแปลงในขณะที่ทำคอมมิชชันมันจะทำงานได้ดี
omnikron

17
หมายเหตุ: เมื่อคุณทำเครื่องหมายคอมมิทด้วยeditห้ามลบคอมมิทอื่นที่แสดงรายการไว้ในไฟล์ หากคุณทำเช่นนั้นความมุ่งมั่นจะถูกลบและคุณจะต้องทำตามขั้นตอนเหล่านี้เพื่อให้พวกเขากลับมา
David Tuite

2
เกี่ยวกับสิ่งที่ @DavidTuite พูดถึงนิสัยของฉันเมื่อทำสิ่งต่าง ๆ ในคอมไพล์ที่ฉันไม่แน่ใจว่าจะเปิดออกได้อย่างไรคือการสร้างสาขา "branchname-ref" เพื่อบันทึกสถานะปัจจุบันของไทม์ไลน์ในกรณีที่ฉันพลาด เมื่อฉันทำเสร็จแล้วฉันจะลบมัน
Raphael

1
ในขั้นตอนที่ 6 ให้รวมเครื่องหมาย (จุด) ในคำสั่ง คำสั่งที่ถูกต้อง:git add .
ทอม

323

หากต้องการ "แก้ไข" การกระทำแบบเก่าด้วยการเปลี่ยนแปลงเล็กน้อยโดยไม่ต้องเปลี่ยนข้อความการส่งข้อความของการส่งข้อความเก่าซึ่งOLDCOMMITมีลักษณะ091b73aดังนี้:

git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

คุณยังสามารถใช้git commit --squash=OLDCOMMITเพื่อแก้ไขข้อความการส่งข้อความเก่าในระหว่างการรีบูต


  • git rebase --interactiveจะนำขึ้นแก้ไขข้อความ (ซึ่งสามารถกำหนดค่า ) เพื่อยืนยัน (หรือแก้ไข) คำแนะนำลำดับ rebase มีข้อมูลสำหรับการเปลี่ยนแปลงคำสั่ง rebaseในไฟล์; เพียงบันทึกและออกจากตัวแก้ไข ( :wqในvim ) เพื่อดำเนินการต่อด้วยการรีบูต
  • --autosquashจะใส่การ--fixup=OLDCOMMITกระทำใด ๆ โดยอัตโนมัติตามลำดับที่ต้องการ โปรดทราบว่า--autosquashจะใช้ได้เฉพาะเมื่อ--interactiveมีการใช้ตัวเลือก
  • ^ในหมายความว่ามันมีการอ้างอิงถึงกระทำก่อนOLDCOMMIT^OLDCOMMIT

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

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


18
ชัดเจนกว่าตัวเลือกอื่น ๆ และมันทำงานได้อย่างมีเสน่ห์
Chris Mitchelmore

5
@Jonah: แก้ไขไม่ได้เปิดให้แก้ไขกระทำข้อความแต่เพื่อยืนยัน (หรือแก้ไข) ขั้นตอน rebase ไม่สามารถหลีกเลี่ยงได้ --autosquashจะใช้ได้เฉพาะเมื่อ--interactiveตัวเลือกที่ถูกนำมาใช้
Joel Purra

5
การใช้โซลูชันนี้ฉันติดคอมไพล์แสดง VIM ปัญหาของฉันคือฉันไม่รู้วิธีใช้ VIM ฉันจะออกจากมันได้อย่างไรฉันจะควบคุมสิ่งนี้ได้อย่างไรและทำให้เกิดความสับสน
Neon Warge

2
@NeonWarge: git config --global core.editor "pico"บรรณาธิการของทางเลือกที่จะกำหนดโดยใช้ตัวอย่างเช่น มีอีกหลายวิธีในการกำหนดค่า git และ / หรือเปลี่ยนแปลงตัวแก้ไขเริ่มต้นของระบบของคุณ
Joel Purra

2
นามแฝงที่ดีหนึ่งบรรทัดที่นี่
idanp

61

ด้วย git 1.7 มีวิธีใช้ที่ง่ายมากgit rebase:

จัดไฟล์ของคุณ:

git add $files

สร้างข้อความคอมมิชชันใหม่และใช้ซ้ำข้อความคอมมิชชันของ "commit"

git commit -c master~4

เติมหน้าfixup!ในหัวเรื่อง (หรือsquash!หากคุณต้องการแก้ไขการมอบหมาย (ข้อความ)):

fixup! Factored out some common XPath Operations

ใช้git rebase -i --autosquashเพื่อแก้ไขการกระทำของคุณ


2
+1 ใช้ประโยชน์จากคำสั่ง fixup ใหม่ (1.7+): stackoverflow.com/questions/2302736/trimming-git-checkins/
VonC

@ Knittl ฉันลองใช้วิธีการของคุณในการเพิ่มไฟล์อื่นลงในไฟล์เก่าของฉัน (ไม่ได้ถูกพุช) แต่เมื่อทำการรีบูตฉันจะได้รับYou asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'และถ้าฉันใช้git rebase -i --autosquashฉันก็จะได้รับnoopหัวเรื่อง ความคิดใดที่ฉันทำผิด
oschrenk

7
@oschrenk: คุณต้องให้คำมั่นสัญญาที่คุณต้องการรีgit rebase -i --autosquash HEAD~10
บูต

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

@ PaulOdeon: ฉันไม่เข้าใจคำถามของคุณ คุณพยายามทำอะไรและคุณประสบปัญหาที่ไหน
knittl

8

คุณสามารถลองrebase --interactiveเซสชั่นเพื่อแก้ไขการกระทำเดิมของคุณ (หากคุณยังไม่ได้ผลักดันการกระทำเหล่านั้นไปที่ repo อื่น)

บางครั้งสิ่งที่แก้ไขใน b.2 ไม่สามารถแก้ไขเพื่อที่ไม่สมบูรณ์แบบทีเดียวกระทำมันแก้ไขเพราะที่กระทำถูกฝังลึกอยู่ในชุดแพทช์
นั่นคือสิ่งที่ rebase เชิงโต้ตอบมีไว้สำหรับ: ใช้หลังจาก "s" และ "b" มากมายโดยการจัดเรียงใหม่และแก้ไขคอมมิชชัน

เริ่มต้นด้วยการคอมมิทล่าสุดที่คุณต้องการเก็บตามที่เป็นอยู่:

git rebase -i <after-this-commit>

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

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

คำอธิบายออนไลน์มีความบริสุทธิ์ใจเพื่อคุณ git rebase จะไม่ดูที่พวกเขา แต่ที่ชื่อ commit ("deadbee" และ "fa1afe1" ในตัวอย่างนี้) ดังนั้นอย่าลบหรือแก้ไขชื่อ

โดยการเปลี่ยนคำสั่ง "เลือก" กับคำสั่ง "แก้ไข" คุณสามารถบอก rebase คอมไพล์หยุดหลังจากใช้ที่กระทำเพื่อให้คุณสามารถแก้ไขไฟล์และ / หรือกระทำข้อความแก้ไขกระทำและดำเนินการต่อ rebasing

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