ลบการกระทำที่เฉพาะเจาะจง


287

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

ดังนั้นนี่เป็นคำถามที่ง่ายขึ้น:

จากสถานการณ์สมมติต่อไปนี้ฉันจะลบการคอมมิท 2 ได้อย่างไร

$ mkdir git_revert_test && cd git_revert_test

$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/

$ echo "line 1" > myfile

$ git add -A

$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 myfile

$ echo "line 2" >> myfile

$ git commit -am "commit 2"
[master 342f9bb] commit 2
 1 files changed, 1 insertions(+), 0 deletions(-)

$ echo "line 3" >> myfile

$ git commit -am "commit 3"
[master 1bcb872] commit 3
 1 files changed, 1 insertions(+), 0 deletions(-)

ผลที่คาดหวังคือ

$ cat myfile
line 1
line 3

นี่คือตัวอย่างของวิธีที่ฉันพยายามแปลงกลับ

$ git revert 342f9bb
Automatic revert failed.  After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.

5
หากใครพบสิ่งนี้ในขณะที่ค้นหาปัญหาเดียวกันนี่คือสิ่งที่ฉันทำลงไป: คัดลอกและวาง อย่างจริงจัง. ใช้เวลา 6+ ชั่วโมงในการพยายามหาวิธีแก้ไขปัญหาที่แนะนำ ในท้ายที่สุดฉันหมดเวลาดึงต้นฉบับขึ้นมาและคัดลอก / วางประมาณ 20 ไฟล์ ใช้เวลาไม่ถึง 5 นาทีและทุกอย่างก็ดีขึ้นเรื่อย ๆ (แม้ว่าไฟล์เหล่านั้นจะถูกรวมเข้ากับการเปลี่ยนแปลงในสาขาอื่น ๆ ที่เกิดขึ้นก่อนหน้านี้ล้มเหลว) ฉันขอแนะนำให้คุณใช้วิธีนี้ด้วย ไม่เพียง แต่จะง่ายที่สุดฉันยังสงสัยว่ามันเป็นสิ่งเดียวที่ใช้งานได้
Joshua Cheek

ฉันเผชิญกับปัญหาที่คล้ายกัน แต่อาจซับซ้อนกว่า: มีสาขาที่มีข้อผูกมัดหลายร้อยข้อที่ฉันอยากจะสควอช น่าเสียดายที่คอมมิชชันจากสาขาอื่นถูกรวมกลับเข้าสาขาที่จุดกึ่งกลางดังนั้นจำเป็นต้องมี "การรวมเข้าด้วยกัน" ก่อนที่ฉันจะสควอช ฉันลงเส้นทางที่คล้ายกันตามที่แนะนำโดย tk ด้านล่าง (การหยิบเชอร์รี่ + โดยใช้เครื่องหมายช่วง) แต่มันสร้างความขัดแย้งในไฟล์อื่น ๆ ในท้ายที่สุดการคัดลอก & วาง + การแก้ไขด้วยตนเองสองสามอันคือเส้นทางที่ง่ายที่สุด การพิจารณาอย่างคุ้มค่าแน่นอนถ้าคุณพบว่าตัวเองใช้เวลากับเรื่องนี้มากเกินไป
Federico

คำตอบ:


73

อัลกอริทึมที่ Git ใช้เมื่อคำนวณ diff's ที่จะเปลี่ยนกลับจำเป็นต้องใช้

  1. บรรทัดที่ถูกเปลี่ยนกลับจะไม่ถูกแก้ไขโดยการกระทำใด ๆ ในภายหลัง
  2. จะไม่มีการกระทำใด ๆ "ติดกัน" ในภายหลังในประวัติศาสตร์

คำจำกัดความของ "ติดกัน" จะขึ้นอยู่กับจำนวนบรรทัดเริ่มต้นจากบริบทที่แตกต่างกันซึ่งก็คือ 3 ดังนั้นหาก 'myfile' ถูกสร้างขึ้นเช่นนี้:

$ cat >myfile <<EOF
line 1
junk
junk
junk
junk
line 2
junk
junk
junk
junk
line 3
EOF
$ git add myfile
$ git commit -m "initial check-in"
 1 files changed, 11 insertions(+), 0 deletions(-)
 create mode 100644 myfile

$ perl -p -i -e 's/line 2/this is the second line/;' myfile
$ git commit -am "changed line 2 to second line"
[master d6cbb19] changed line 2
 1 files changed, 1 insertions(+), 1 deletions(-)

$ perl -p -i -e 's/line 3/this is the third line/;' myfile
$ git commit -am "changed line 3 to third line"
[master dd054fe] changed line 3
 1 files changed, 1 insertions(+), 1 deletions(-)

$ git revert d6cbb19
Finished one revert.
[master 2db5c47] Revert "changed line 2"
 1 files changed, 1 insertions(+), 1 deletions(-)

จากนั้นก็ทำงานได้ตามที่คาดหวัง

คำตอบที่สองนั้นน่าสนใจมาก มีคุณสมบัติที่ยังไม่เปิดตัวอย่างเป็นทางการ (แม้ว่าจะมีอยู่ใน Git v1.7.2-rc2) ที่เรียกว่ากลยุทธ์การแปลงกลับ คุณสามารถเรียกใช้คอมไพล์ได้ดังนี้:

git revert - กลยุทธ์แก้ไข <commit>

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


1
perl -pมีประโยชน์สำหรับการเขียนโปรแกรมสั้นมาก (หนึ่งบรรทัด) ซึ่งวนรอบและส่งผ่านอินพุตไปยังเอาต์พุตคล้ายกับ sed perl -iถูกนำมาใช้สำหรับการแก้ไขไฟล์ในสถานที่ perl -eเป็นวิธีการที่จะส่งรหัสที่จะประเมิน
Hal Eisen

281

มีสี่วิธีในการทำเช่นนี้:

  • วิธีทำความสะอาดเปลี่ยนกลับ แต่เก็บบันทึกการเปลี่ยนกลับ:

    git revert --strategy resolve <commit>
    
  • วิธีที่รุนแรงให้ลบการกระทำล่าสุดทั้งหมด:

    git reset --soft "HEAD^"
    

หมายเหตุ: หลีกเลี่ยงgit reset --hardเนื่องจากจะเป็นการยกเลิกการเปลี่ยนแปลงทั้งหมดในไฟล์ตั้งแต่การส่งครั้งล่าสุด หาก--softไม่ได้ผลค่อนข้างลองหรือ--mixed--keep

  • Rebase (แสดงบันทึกการกระทำ 5 ครั้งล่าสุดและลบบรรทัดที่คุณไม่ต้องการหรือเรียงลำดับใหม่หรือสควอชหลายคอมมิทในครั้งเดียวหรือทำสิ่งอื่นที่คุณต้องการนี่เป็นเครื่องมืออเนกประสงค์มาก):

    git rebase -i HEAD~5
    

และหากมีข้อผิดพลาดเกิดขึ้น:

git rebase --abort
  • การรีบูตด่วน: ลบเฉพาะการส่งคำสั่งโดยใช้ id:

    git rebase --onto commit-id^ commit-id
    
  • ทางเลือก: คุณสามารถลอง:

    git cherry-pick commit-id
    
  • อีกทางเลือกหนึ่ง:

    git revert --no-commit
    
  • เป็นทางเลือกสุดท้ายถ้าคุณต้องการเสรีภาพเต็มรูปแบบของการแก้ไขประวัติ (เช่นเพราะคอมไพล์ไม่ได้ช่วยให้คุณสามารถแก้ไขสิ่งที่คุณต้องการ) คุณสามารถใช้วิธีนี้อย่างรวดเร็วโปรแกรมเปิดแหล่ง: reposurgeon

หมายเหตุ: แน่นอนการเปลี่ยนแปลงทั้งหมดนี้ทำในเครื่องคุณควรgit pushใช้การเปลี่ยนแปลงกับรีโมท และในกรณีที่ repo ของคุณไม่ต้องการลบการกระทำ ("ไม่อนุญาตให้ส่งต่ออย่างรวดเร็ว" ซึ่งเกิดขึ้นเมื่อคุณต้องการลบการส่งที่คุณกดไว้แล้ว) คุณสามารถใช้git push -fเพื่อบังคับการเปลี่ยนแปลง

Note2: หากทำงานในสาขาและคุณจำเป็นต้องบังคับให้กดคุณควรหลีกเลี่ยงอย่างยิ่งgit push --forceเพราะอาจเป็นการเขียนทับสาขาอื่น ๆ (ถ้าคุณทำการเปลี่ยนแปลงในสาขานั้นแม้ว่าคุณจะทำการเช็คเอาต์ปัจจุบันที่สาขาอื่น) ชอบที่จะเสมอระบุสาขาที่ห่างไกลเมื่อคุณบังคับให้ผลักดันgit push --force origin your_branch :


ตามคำแนะนำของ @gaborous: ทำ "git rebase -i HEAD ~ 2" ตอนนี้คุณมีหลายทางเลือก ในกลุ่มคุณจะเห็นบรรทัดที่มีความคิดเห็น: หนึ่งในนั้นบอกคุณว่าคุณสามารถลบบรรทัดได้ (ซึ่งควรจะเป็นคอมมิทที่คุณต้องการกำจัด) และคอมมิชชันนี้จะถูกลบออกพร้อมกับบันทึกในประวัติของคุณ
แมว Ilker

git revert - กลยุทธ์แก้ไข <commit> คำสั่งนี้ใช้งานได้สำหรับฉัน ขอบคุณ :)
Swathin

2
git rebase -i HEAD~5ทำงานให้ฉัน จากนั้นฉันเพิ่งลบการกระทำที่ฉันไม่ต้องการและฉันสามารถแก้ปัญหาได้ในเวลาน้อยกว่า 30 วินาที ขอบคุณ.
lv10

118

นี่คือทางออกที่ง่าย:

git rebase -i HEAD~x

(หมายเหตุ: xคือจำนวนข้อผูกพัน)

เมื่อดำเนินการไฟล์ Notepad จะเปิด ใส่dropนอกเหนือจากการกระทำของคุณ
หากคุณไม่รู้จัก Vim เพียงคลิกที่แต่ละคำที่คุณต้องการแก้ไขจากนั้นกดปุ่ม "I" (สำหรับโหมดแทรก) เมื่อคุณพิมพ์เสร็จแล้วกดปุ่ม "esc" เพื่อออกจากโหมดแทรก



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

และนั่นคือคุณเสร็จแล้ว ... เพียงซิงค์แดชบอร์ด git และการเปลี่ยนแปลงจะถูกผลักไปยังระยะไกล

หากความมุ่งมั่นที่คุณดร็อปอยู่บนรีโมทแล้วคุณจะต้องบังคับให้กด ตั้งแต่ --force ถือว่า เป็นอันตรายต่อgit push --force-with-leaseการใช้งาน


มีวิธีที่ดีในการค้นหาว่า 'x' ควรจะเป็นอย่างไรถ้าคุณรู้ว่าแฮชของคำสั่งที่มีปัญหา?
jlewkovich

1
สำหรับคนที่มี CPP ความคิด: รวม x (จำนวนคำสั่ง) เช่น HEAD ~ 4 รวม 4 คอมมิทล่าสุด
เริมวิศวกรฟรี

ข้อเสนอแนะที่สมบูรณ์แบบ เพียงแค่ต้องการเพิ่มสิ่งนี้ยังยกเลิกการเปลี่ยนแปลงจากการส่งที่ลดลง
celerno

พยายามที่จะย้อนกลับ 3 คอมมิท: git rebase -i HEAD-3 มีข้อผิดพลาดร้ายแรง: ต้องการการแก้ไขเดี่ยวที่ไม่ถูกต้องอัป
สตรีม

1
@Ustin มัน ~ 3 ไม่ใช่ -3
JD-V

37

ทางเลือกของคุณอยู่ระหว่าง

  1. การรักษาข้อผิดพลาดและแนะนำการแก้ไขและ
  2. ลบข้อผิดพลาดและเปลี่ยนประวัติ

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

Git revert เป็นเครื่องมืออัตโนมัติที่ต้องทำ (1) มันสร้างการคอมมิทใหม่ยกเลิกการคอมมิทก่อนหน้านี้ คุณจะเห็นข้อผิดพลาดและการลบในประวัติโครงการ แต่ผู้ที่ดึงออกจากที่เก็บของคุณจะไม่ประสบปัญหาเมื่อพวกเขาอัปเดต มันไม่ทำงานอย่างอัตโนมัติในตัวอย่างของคุณดังนั้นคุณต้องแก้ไข 'myfile' (เพื่อลบบรรทัดที่ 2) ทำgit add myfileและgit commitจัดการกับความขัดแย้ง จากนั้นคุณจะจบลงด้วยสี่คอมมิชชันในประวัติของคุณด้วยคอมมิชชัน 4 การคืนค่าคอมมิชชัน 2

หากไม่มีใครสนใจว่าประวัติของคุณเปลี่ยนแปลงคุณสามารถเขียนใหม่และลบการกระทำ 2 (ตัวเลือก 2) git rebase -i 8230fa3วิธีง่ายๆในการทำเช่นนี้คือการใช้ นี้จะวางคุณลงในโปรแกรมแก้ไขและคุณสามารถเลือกที่จะไม่รวมถึงการที่ผิดพลาดกระทำโดยการเอากระทำ (และการเก็บรักษา "เลือก" ถัดไปที่อื่น ๆ กระทำข้อความ. อย่าอ่านในผลกระทบของการทำเช่นนี้


การ Rebase อาจเป็นเรื่องยากเนื่องจากดูเหมือนว่ามีการผสาน
Cascabel

3
git rebase -i 8230fa3 และลบรายการการกระทำได้ผลดีมากสำหรับฉันกับการเปลี่ยนแปลงเฉพาะที่ของฉัน ขอบคุณ!
ซามูเอล

26

ประมาณ 1

ก่อนอื่นให้รับแฮชการกระทำ (เช่น: 1406cd61) ที่คุณต้องการเปลี่ยนกลับ แก้ไขง่ายจะอยู่ด้านล่างคำสั่ง

$ git revert 1406cd61

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

ประมาณ 2

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

ขั้นตอนที่ 1:ค้นหาการกระทำก่อนที่จะส่งการกระทำที่คุณต้องการลบgit log

ขั้นตอนที่ 2:ชำระเงินที่กระทำgit checkout <commit hash>

ขั้นตอนที่ 3:สร้างสาขาใหม่โดยใช้การชำระเงินในปัจจุบันของคุณgit checkout -b <new branch>

ขั้นตอนที่ 4:ตอนนี้คุณต้องเพิ่มความมุ่งมั่นหลังจากการกระทำที่ถูกลบออกgit cherry-pick <commit hash>

ขั้นตอนที่ 5:ตอนนี้ทำซ้ำขั้นตอนที่ 4 สำหรับการกระทำอื่น ๆ ทั้งหมดที่คุณต้องการเก็บไว้

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

ขั้นตอนที่ 7:เปลี่ยนเป็นสาขาที่หักของคุณgit checkout <broken branch>

ขั้นตอนที่ 8:ตอนนี้ทำการฮาร์ดรีเซ็ตบนกิ่งที่หักไปยังการส่งก่อนที่จะทำการลบgit reset --hard <commit hash>

ขั้นตอนที่ 9:ผสานสาขาคงที่ของคุณเข้ากับสาขานี้git merge <branch name>

ขั้นตอนที่ 10:ผลักดันการเปลี่ยนแปลงที่ถูกผสานกลับไปยังจุดเริ่มต้น คำเตือน: สิ่งนี้จะเขียนทับ repo ทางไกล!git push --force origin <branch name>

คุณสามารถทำกระบวนการโดยไม่ต้องสร้างสาขาใหม่โดยแทนที่ขั้นตอนที่ 2 และ 3 ด้วยขั้นตอนที่ 8 จากนั้นไม่ดำเนินการขั้นตอนที่ 7 และ 9


1
วิธีการแรกทำงานเหมือนจับใจ ซึ่งจะรวมถึงการคอมมิชชันที่ระบุว่าการคอมมิชชันที่คุณต้องการถูกเปลี่ยนกลับซึ่งเป็นสิ่งที่ดีจริงๆสำหรับวัตถุประสงค์ในการติดตาม
suarsenegger

18

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

git checkout -b tmp-branch my-topic-branch  # Use a temporary branch to be safe.
git rebase -i master  # Interactively rebase against master branch.

เมื่อถึงจุดนี้โปรแกรมแก้ไขข้อความของคุณจะเปิดมุมมอง rebase เชิงโต้ตอบ ตัวอย่างเช่น

-git rebase-สิ่งที่ต้องทำ

  1. ลบการกระทำที่คุณไม่ต้องการโดยการลบบรรทัดของพวกเขา
  2. บันทึกและออก

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

git checkout my-topic-branch
git reset --hard tmp-branch  # Overwrite your topic branch with the temp branch.
git branch -d tmp-branch  # Delete the temporary branch.

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


คุณช่วยยกตัวอย่างของ 'ลองใช้กลยุทธ์อื่น' ได้ไหม?
pfabri

@pfabri คุณสามารถทำได้เช่นเลือกเชอร์รี่สองช่วงคอมมิชชันที่คุณไม่ได้กระทำ คุณสามารถย้อนกลับการกระทำที่ไม่ดี คุณสามารถหลีกเลี่ยงการใช้วิธีแก้ปัญหาด้วยการคอมไพล์ด้วยการเลิกทำการเปลี่ยนแปลงด้วยตนเองหรือเริ่มจากสาขาใหม่โดยไม่ต้องมีข้อผูกมัดที่ไม่ดีและทำซ้ำการเปลี่ยนแปลงที่ดีด้วยตนเอง หากการกระทำที่ไม่ถูกต้องมีข้อมูลที่ละเอียดอ่อนคุณจะต้องใช้กลยุทธ์ที่ระมัดระวังมากขึ้น: help.github.com/th/articles/…
Dennis

8

จากคำตอบอื่น ๆ ที่นี่ฉันรู้สึกสับสนกับวิธีที่git rebase -iสามารถนำการลบออกได้ดังนั้นฉันหวังว่ามันจะดีกว่าที่จะเขียนกรณีทดสอบที่นี่ (คล้ายกับ OP)

นี่คือbashสคริปต์ที่คุณสามารถวางเพื่อสร้างที่เก็บการทดสอบใน/tmpโฟลเดอร์:

set -x

rm -rf /tmp/myrepo*
cd /tmp

mkdir myrepo_git
cd myrepo_git
git init
git config user.name me
git config user.email me@myself.com

mkdir folder
echo aaaa >> folder/file.txt
git add folder/file.txt
git commit -m "1st git commit"

echo bbbb >> folder/file.txt
git add folder/file.txt
git commit -m "2nd git commit"

echo cccc >> folder/file.txt
git add folder/file.txt
git commit -m "3rd git commit"

echo dddd >> folder/file.txt
git add folder/file.txt
git commit -m "4th git commit"

echo eeee >> folder/file.txt
git add folder/file.txt
git commit -m "5th git commit"

ณ จุดนี้เรามีfile.txtเนื้อหาเหล่านี้:

aaaa
bbbb
cccc
dddd
eeee

ณ จุดนี้ HEAD อยู่ในอันดับที่ 5, HEAD ~ 1 จะเป็นอันดับที่ 4 และ HEAD ~ 4 จะเป็นอันดับที่ 1 (ดังนั้น HEAD ~ 5 จะไม่มีอยู่) สมมติว่าเราต้องการลบการคอมมิท 3 - เราสามารถออกคำสั่งนี้ในmyrepo_gitไดเรกทอรี:

git rebase -i HEAD~4

( โปรดทราบว่าgit rebase -i HEAD~5ผลลัพธ์ที่มี "ร้ายแรง: จำเป็นต้องมีการแก้ไขครั้งเดียว; HEAD upstream HEAD ~ 5" ที่ไม่ถูกต้อง ) ตัวแก้ไขข้อความ (ดูภาพหน้าจอใน@Dennis 'คำตอบ ) จะเปิดขึ้นพร้อมเนื้อหาเหล่านี้:

pick 5978582 2nd git commit
pick 448c212 3rd git commit
pick b50213c 4th git commit
pick a9c8fa1 5th git commit

# Rebase b916e7f..a9c8fa1 onto b916e7f
# ...

ดังนั้นเราจึงได้รับทั้งหมดตั้งแต่ (แต่ไม่รวม ) HEAD ที่เราร้องขอ ~ 4 ลบบรรทัดpick 448c212 3rd git commitและบันทึกไฟล์ คุณจะได้รับคำตอบนี้จากgit rebase:

error: could not apply b50213c... 4th git commit

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply b50213c... 4th git commit

ณ จุดนี้เปิด myrepo_git / folder/file.txtในโปรแกรมแก้ไขข้อความ คุณจะเห็นว่ามันได้รับการแก้ไข:

aaaa
bbbb
<<<<<<< HEAD
=======
cccc
dddd
>>>>>>> b50213c... 4th git commit

โดยพื้นฐานแล้วgitเห็นว่าเมื่อ HEAD ไปถึงการคอมมิชชันที่ 2 มีเนื้อหาของaaaa+ bbbb; และจากนั้นมีการเพิ่มcccc+ ddddซึ่งไม่รู้วิธีผนวกเข้ากับเนื้อหาที่มีอยู่

ดังนั้นที่นี่gitไม่สามารถตัดสินใจสำหรับคุณ - มันเป็นคุณที่มีการตัดสินใจ: โดยการเอาที่ 3 กระทำคุณทั้งสองให้การเปลี่ยนแปลงที่นำโดยมัน (ที่นี่บรรทัดcccc) - หรือคุณไม่ได้ หากคุณไม่ต้องการเพียงแค่ลบบรรทัดพิเศษ - รวมถึงcccc- ใน - folder/file.txtโดยใช้โปรแกรมแก้ไขข้อความเพื่อให้ดูเหมือนว่า

aaaa
bbbb
dddd

... folder/file.txtแล้วบันทึก ตอนนี้คุณสามารถออกคำสั่งต่อไปนี้ในmyrepo_gitไดเรกทอรี:

$ nano folder/file.txt  # text editor - edit, save
$ git rebase --continue
folder/file.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

AH - ดังนั้นเพื่อที่จะทำเครื่องหมายว่าเราได้รับการแก้ไขความขัดแย้งที่เราต้อง , ก่อนที่จะทำ:git addfolder/file.txtgit rebase --continue

$ git add folder/file.txt
$ git rebase --continue

ที่นี่โปรแกรมแก้ไขข้อความจะเปิดขึ้นอีกครั้งแสดงบรรทัด4th git commit- ที่นี่เรามีโอกาสที่จะเปลี่ยนข้อความกระทำ (ซึ่งในกรณีนี้อาจมีความหมายเปลี่ยนเป็น4th (and removed 3rd) commitหรือคล้ายกัน) สมมติว่าคุณไม่ต้องการ - เพียงออกจากโปรแกรมแก้ไขข้อความโดยไม่บันทึก เมื่อคุณทำเช่นนั้นคุณจะได้รับ:

$ git rebase --continue
[detached HEAD b8275fc] 4th git commit
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.

ณ จุดนี้ตอนนี้คุณมีประวัติเช่นนี้ (ซึ่งคุณสามารถตรวจสอบด้วยคำพูดgitk .หรือเครื่องมืออื่น ๆ ) ของเนื้อหาของfolder/file.txt(ด้วย, เห็นได้ชัดว่าการประทับเวลาไม่เปลี่ยนแปลงของคอมมิชชันดั้งเดิม):

1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   dddd
                |  +eeee

และถ้าก่อนหน้านี้เราตัดสินใจที่จะรักษาสายcccc(เนื้อหาของคอมไพล์ที่ 3 กระทำที่เราลบ) เราจะได้:

1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +cccc
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   cccc
                |   dddd
                |  +eeee

นี่คือประเภทของการอ่านที่ฉันหวังว่าฉันจะได้พบเพื่อเริ่มต้นวิธีการgit rebaseทำงานในแง่ของการลบการกระทำ / การแก้ไข; หวังว่ามันจะช่วยคนอื่นด้วย ...


ช่างเป็นเรื่องที่ประเมินค่าไม่ได้ - กรณีใช้งานจริงที่ฉันต้องดิ้นรนสิ่งนี้ช่วยฉันได้มาก
pfabri

2

ดังนั้นดูเหมือนว่าการคอมมิทที่ไม่ถูกต้องถูกรวมในการคอมมิชชันการรวมในบางจุด ความมุ่งมั่นของคุณถูกดึงออกมาหรือยัง? ถ้าใช่คุณจะต้องการใช้git revert; คุณจะต้องกัดฟันและทำสิ่งที่ขัดแย้งกัน ถ้าไม่เช่นนั้นคุณสามารถรีบูทหรือย้อนกลับได้ แต่คุณสามารถทำได้ก่อนที่การรวมจะส่งมอบให้ทำซ้ำการผสาน

ไม่มีความช่วยเหลืออะไรมากที่เราสามารถให้คุณได้ในกรณีแรก หลังจากลองเปลี่ยนกลับและพบว่ารายการอัตโนมัติล้มเหลวคุณต้องตรวจสอบข้อขัดแย้งและแก้ไขให้เหมาะสม นี่เป็นกระบวนการเดียวกับการแก้ไขข้อขัดแย้งผสาน คุณสามารถใช้git statusเพื่อดูว่าข้อขัดแย้งอยู่ที่ใดแก้ไขไฟล์ที่ไม่ได้ถูกแยกค้นหาหวงที่ขัดแย้งกันหาวิธีแก้ปัญหาเพิ่มไฟล์ที่ขัดแย้งและสุดท้ายผูกมัด ถ้าคุณใช้git commitด้วยตัวเอง (ไม่-m <message>) มีข้อความที่ปรากฏขึ้นในการแก้ไขของคุณควรจะแม่แบบข้อความที่สร้างขึ้นโดยgit revert; คุณสามารถเพิ่มบันทึกเกี่ยวกับวิธีที่คุณแก้ไขข้อขัดแย้งจากนั้นบันทึกและออกจากการมอบหมาย

สำหรับกรณีที่สองแก้ไขปัญหาก่อนการผสานของคุณมีสองหน่วยย่อยขึ้นอยู่กับว่าคุณทำงานได้มากขึ้นตั้งแต่การรวม หากคุณยังไม่มีคุณก็สามารถgit reset --hard HEAD^ตัดการรวมทำการย้อนกลับแล้วทำซ้ำการผสาน แต่ฉันเดาว่าคุณมี ดังนั้นคุณจะต้องทำสิ่งนี้:

  • สร้างสาขาชั่วคราวก่อนทำการผสานและตรวจสอบ
  • ทำการย้อนกลับ (หรือใช้git rebase -i <something before the bad commit> <temporary branch>เพื่อลบการกระทำที่ไม่ดี)
  • ทำซ้ำการผสาน
  • รีบูตงานที่ตามมาของคุณกลับมา: git rebase --onto <temporary branch> <old merge commit> <real branch>
  • ลบสาขาชั่วคราว

1

ดังนั้นคุณทำงานและผลักมันให้เรียกพวกมันว่า A และ B เพื่อนร่วมงานของคุณก็ทำงานได้ดียอมรับ C และ D คุณรวมเพื่อนร่วมงานของคุณเข้าด้วยกัน (ผสานกระทำ E) จากนั้นก็ทำงานต่อไป ด้วย (ส่ง F) และพบว่าเพื่อนร่วมงานของคุณเปลี่ยนบางสิ่งที่เขาไม่ควรมี

ดังนั้นประวัติการกระทำของคุณจะเป็นดังนี้:

A -- B -- C -- D -- D' -- E -- F

คุณต้องการกำจัด C, D และ D 'จริงๆ เมื่อคุณบอกว่าคุณได้รวมผู้ร่วมงานของคุณเข้าด้วยกันแล้วคอมมิชชันเหล่านี้ก็ "ออกไปข้างนอก" แล้วดังนั้นการลบคอมมิชชันที่ใช้เช่นการรีคอมไพล์ git นั้นไม่มีข้อใดเลย เชื่อฉันฉันได้ลองแล้ว

ตอนนี้ฉันเห็นสองวิธี:

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

    git reset D'
    

    (แทนที่ D 'ด้วยแฮชการกระทำจริงที่คุณสามารถหาได้จาก git log

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

  • หากคุณได้ผลักงานที่คุณทำไว้หลังจากที่เพื่อนร่วมงานของคุณมุ่งมั่นแล้วคุณยังสามารถลองใช้ "reverse patch" ด้วยตนเองหรือใช้git revertงานได้ แต่เนื่องจากงานของคุณคือ ผสานความขัดแย้งมากขึ้นและสับสนมากขึ้น ดูเหมือนว่านั่นคือสิ่งที่คุณทำ ...


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