วิธียกเลิก "git กระทำ - แก้ไข" ทำแทน "git กระทำ"


1294

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

มีวิธีการเลิกทำที่กระทำครั้งสุดท้ายหรือไม่ ถ้าฉันทำอะไรที่ชอบgit reset --hard HEAD^ความมุ่งมั่นแรกก็เลิกทำ

(ฉันยังไม่ได้ผลักไปยังไดเรกทอรีระยะไกลใด ๆ )

คำตอบ:


2290

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

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}

33
เจ๋งมาก +1 ฉันยังไม่ได้กับวินาทีสุดท้ายแก้ไขมุมมองเข้าไปเพื่อหาสิ่งที่เช่นตัวเลขให้ถูกต้องgit reflog {2}
JJD

179
เพื่อให้ชัดเจนคำสั่งแรกคือ "ยกเลิก" จริง มันผลิตหัวไดเรกทอรีการทำงาน (ไม่เปลี่ยนแปลง) git commit --amendและรัฐดัชนีก่อน ที่สองคือ "ทำซ้ำ" เป็นความมุ่งมั่นใหม่ การทำงานเหล่านี้สำหรับการใด ๆที่ไม่เพียงgit commit --amend
cdunn2001

60
git commitดังนั้นถ้าคุณไม่ได้แก้ไขด้วยข้อความใหม่กระทำที่คุณจำเป็นต้องกอบกู้ส่วนที่สองก็สามารถเป็นปกติ
Matt Montag

18
ด้วยเหตุผลบางอย่างที่ผมได้รับข้อผิดพลาดเมื่อทำงาน:git reset --soft HEAD@{1} fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisionsเมื่อฉันแทนที่HEAD@{1}แฮชคอมมิชชันที่เทียบเท่าที่แสดงในgit reflog(ขอบคุณ JJD!) คำตอบนี้ใช้ได้อย่างยอดเยี่ยม!
Tim Camber

20
@TimArnold HEAD@{1}ขึ้นอยู่กับเปลือกของคุณคุณอาจจะต้องใส่คำพูดเดียวหรือสองรอบ ถ้าฉันทำงานecho HEAD@{1}ใน tcsh ตัวอย่างผลลัพธ์คือHEAD@1เพราะวงเล็บปีกกาถูกตีความโดย tcsh หากฉันใช้เครื่องหมายคำพูดเดี่ยวเครื่องหมายวงเล็บจะถูกเก็บรักษาไว้
เคลวิน

136

ใช้บันทึกการอ้างอิง :

git branch fixing-things HEAD@{1}
git reset fixing-things

จากนั้นคุณควรมีการเปลี่ยนแปลงแก้ไขทั้งหมดของคุณก่อนหน้านี้เฉพาะในสำเนาการทำงานของคุณและสามารถกระทำอีกครั้ง

เพื่อดูรายการดัชนีประเภทก่อนหน้าทั้งหมด git reflog


7
สิ่งนี้จะลบดัชนีด้วย - ยังคงมีประโยชน์ แต่นอกเหนือไปจาก "เลิกทำ" อย่างง่าย
cdunn2001

3
มีความแตกต่างระหว่างHEAD@{1}และHEAD~1?
neaumusic

15
@neaumusic: ใช่! HEAD~1เป็นเหมือนกับHEAD^และตัวระบุผู้ปกครองของปัจจุบันกระทำ HEAD@{1}ในทางตรงกันข้ามหมายถึงการกระทำที่หัวหน้าชี้ไปก่อนหน้านี้นั่นหมายถึงการกระทำที่แตกต่างกันเมื่อคุณชำระเงินสาขาที่แตกต่างกันหรือแก้ไขการกระทำ
knittl

@knittl อาไม่น่าแปลกใจฉันไม่คิดว่านี่เป็นไปได้ก่อนที่จะขอบคุณอีกครั้งข้อมูลที่ดี
neaumusic

9
ขั้นตอนกำปั้นซ้ำซ้อน ง่ายgit reset HEAD@{1}พอ
dwelle

79

ค้นหาข้อผูกพันที่แก้ไขเพิ่มเติมโดย:

git log --reflog

หมายเหตุ: คุณสามารถเพิ่ม--patchเพื่อดูเนื้อความของคำสั่งเพื่อความชัดเจน git reflogเช่นเดียวกับ

จากนั้นรีเซ็ต HEAD ของคุณเป็นกระทำก่อนหน้าในจุดที่ถูกต้องโดย:

git reset SHA1 --hard

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

จากนั้นเลือกเชอร์รี่อื่นที่คุณต้องการ:

git cherry-pick SHA1

26
หากคุณทำเช่นgit reset SHA1 --softนั้นคุณสามารถเก็บการเปลี่ยนแปลงล่าสุดไว้และส่งมอบการเปลี่ยนแปลงนั้นได้
pravj

24

คุณสามารถแบ่งการกระทำออกจากคู่มือได้ตลอดเวลา

  • เริ่ม rebase เชิงโต้ตอบด้วย git rebase -i commit ^ โดยที่ commit เป็นคอมมิชชันที่คุณต้องการแยก ในความเป็นจริงช่วงการยอมรับใด ๆ ที่จะทำตราบใดที่มันมีการกระทำที่
  • ทำเครื่องหมายการมอบหมายที่คุณต้องการแยกด้วยการกระทำ "แก้ไข"
  • เมื่อพูดถึงการแก้ไขที่กระทำแล้วให้เรียกใช้ git reset HEAD ^ เอฟเฟกต์คือ HEAD ถูกกรอด์หนึ่งตัวและดัชนีจะตามหลังชุดสูท อย่างไรก็ตามต้นไม้ทำงานยังคงเหมือนเดิม
  • ตอนนี้เพิ่มการเปลี่ยนแปลงในดัชนีที่คุณต้องการในการกระทำครั้งแรก คุณสามารถใช้การเพิ่ม git (อาจโต้ตอบ) หรือ git-gui (หรือทั้งสองอย่าง) เพื่อทำเช่นนั้น
  • ยอมรับดัชนีตอนนี้ด้วยข้อความการกระทำใด ๆ ที่เหมาะสมในขณะนี้
  • ทำซ้ำสองขั้นตอนสุดท้ายจนกระทั่งต้นไม้ทำงานของคุณสะอาด
  • ดำเนินการต่อ rebase ด้วย git rebase - ยุติ

26
ทางซับซ้อนเกินไป git reflogเป็นสิ่งที่คุณจำเป็นต้อง
knittl

2
มีหลายขั้นตอนใช่ แต่แต่ละขั้นตอนนั้นไม่ซับซ้อนและง่ายต่อการทำ สิ่งนี้ใช้ได้สำหรับฉันและได้รับคะแนนของฉัน
OzBandit

5
นอกจากนี้คำตอบนี้ช่วยให้คุณสามารถเลือกการเปลี่ยนแปลงที่คุณตั้งใจ 'แก้ไข' เพื่อให้ค่าเพิ่มเติมบางอย่างในการรีเซ็ต git --soft HEAD @ {1} วิธี (ซึ่งแก้ปัญหาของฉัน BTW)
Wiebe Tijsma

2
คุณสามารถเลือกการเปลี่ยนแปลงด้วยวิธีการอ้างอิงได้เช่นกัน เพียงแค่ทำgit resetแทนแล้วทำgit reset --soft git add --patch
geekofalltrades

1
สิ่งนี้ยังคงเขียนประวัติและต้องการแรงผลักดัน ขึ้นอยู่กับสถานการณ์ของคุณว่าอาจจะมีหรือไม่มีปัญหา
Pajn

20

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


นี่คือหนึ่ง
atilkan

บันทึก แต่ฉัน ^^
engineercoding

14

อาจใช้git reflogเพื่อรับค่าคอมมิชชันสองค่าก่อนการแก้ไขและหลังจากการแก้ไข

จากนั้นใช้git diff before_commit_id after_commit_id > d.diffเพื่อรับความแตกต่างระหว่างก่อนการแก้ไขและหลังจากการแก้ไข

ใช้ครั้งต่อไปgit checkout before_commit_idเพื่อย้อนกลับก่อนคอมมิท

และใช้งานล่าสุดgit apply d.diffเพื่อนำการเปลี่ยนแปลงที่แท้จริงที่คุณทำ

ที่แก้ปัญหาของฉัน


11

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

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit

3
นี่เป็นกรณีพิเศษของคำถามทั่วไป แต่ครอบคลุมความต้องการของฉันในทันที
dmckee --- ผู้ดูแลอดีตลูกแมว

8

คุณสามารถทำด้านล่างเพื่อยกเลิกของคุณ git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

====================================

ตอนนี้การเปลี่ยนแปลงของคุณจะเป็นไปตามก่อนหน้านี้ ดังนั้นคุณจะทำกับการเลิกทำเพื่อgit commit —amend

ตอนนี้คุณสามารถทำได้git push origin <your_branch_name>เพื่อผลักดันให้สาขา


3

เกือบ 9 ปีที่ผ่านมา แต่ไม่เห็นการเปลี่ยนแปลงที่กล่าวถึงการทำสิ่งเดียวกัน (เป็นการรวมกันของบางอย่างคล้ายกับคำตอบยอดนิยม ( https://stackoverflow.com/a/1459264/4642530) ) .

ค้นหาหัวเดี่ยวที่แยกออกมาจากสาขา

git reflog show origin/BRANCH_NAME --date=relative

จากนั้นค้นหาแฮช SHA1

รีเซ็ตเป็น SHA1 เก่า

git reset --hard SHA1

จากนั้นดันกลับขึ้น

git push origin BRANCH_NAME

เสร็จสิ้น

สิ่งนี้จะเปลี่ยนคุณกลับสู่การกระทำแบบเดิมอย่างสิ้นเชิง

(รวมถึงวันที่หัวหน้าการมอบหมายที่ถูกเขียนทับก่อนหน้านี้)


ใช่ แต่โดยปกติฉันต้องการตั้งค่าใหม่--softเพื่อให้การเปลี่ยนแปลงของฉัน ฉันแค่ต้องการให้มันแยกจากกัน
Juan Mendes

2
  1. ชำระเงินไปที่สาขาชั่วคราวด้วยการกระทำครั้งสุดท้าย

    git branch temp HEAD@{1}

  2. รีเซ็ตการกระทำล่าสุด

    git reset temp

  3. ตอนนี้คุณจะมีไฟล์ทั้งหมดที่คอมมิทและการคอมมิชชันก่อนหน้า ตรวจสอบสถานะของไฟล์ทั้งหมด

    git status

  4. รีเซ็ตไฟล์คอมมิทของคุณจากขั้นตอนคอมไพล์

    git reset myfile1.js (เป็นต้น)

  5. ติดตั้งซ้ำกระทำนี้

    git commit -C HEAD@{1}

  6. เพิ่มและส่งไฟล์ของคุณเพื่อกระทำใหม่

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