Git - เลิกทำคอมมิชชันแล้ว


609

ฉันมีโครงการในที่เก็บระยะไกลที่ซิงโครไนซ์กับที่เก็บข้อมูลในพื้นที่ (การพัฒนา) และเซิร์ฟเวอร์หนึ่ง (prod) ฉันได้ทำการเปลี่ยนแปลงบางอย่างที่คอมมิตแล้วส่งไปยังรีโมตและดึงออกจากเซิร์ฟเวอร์ ตอนนี้ฉันต้องการยกเลิกการเปลี่ยนแปลงเหล่านั้น ดังนั้นฉันสามารถgit checkoutกระทำก่อนการเปลี่ยนแปลงและกระทำการเปลี่ยนแปลงใหม่ได้ แต่ฉันเดาว่าจะมีปัญหาในการผลักดันพวกเขาอีกครั้งให้ห่างไกล ข้อเสนอแนะใด ๆ เกี่ยวกับฉันควรดำเนินการอย่างไร


คำตอบ:


735

คุณสามารถย้อนกลับแต่ละการกระทำด้วย:

git revert <commit_hash>

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

git revert <oldest_commit_hash>..<latest_commit_hash>

มันย้อนกลับการกระทำระหว่างและรวมถึงการกระทำที่ระบุ

ดูหน้า man git-revertเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับgit revertคำสั่ง ดูคำตอบนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการคืนค่าคำมั่นสัญญา


22
กล่าวอีกนัยหนึ่งมันจะเปลี่ยนเป็น <oldest_commit_hash>;)
David

7
@mr_jigsaw Usegit log
gitaarik

2
ในเอกสาร git มันบอกว่าคำสั่งเปลี่ยนกลับเป็นคำสั่งย้อนกลับระหว่างคำสั่งแรกและคำสุดท้าย ดูเอกสารประกอบ
Onur Demir

4
@Aod ถูกต้องคำตอบนี้จำเป็นต้องได้รับการปรับปรุง API git ปัจจุบันสำหรับการเปลี่ยนกลับได้<oldest_commit_hash>ถูกรวมอยู่ในรายการการแปลงกลับ
JHixson

4
ด้วย git 2.17.2 revert <old> .. <ใหม่> ไม่รวมเก่า แต่รวม <new>
chingis

353

วิธีแก้ปัญหาที่ไม่เก็บร่องรอยของ "เลิกทำ"

หมายเหตุ: อย่าทำเช่นนี้หากมีคนดึงการเปลี่ยนแปลงของคุณ (ฉันจะใช้สิ่งนี้กับ repo ส่วนตัวของฉันเท่านั้น)

ทำ:

git reset <previous label or sha1>

นี่จะตรวจสอบการอัปเดตทั้งหมดในเครื่องอีกครั้ง (ดังนั้นสถานะ git จะแสดงรายการไฟล์ที่อัพเดททั้งหมด)

จากนั้นคุณ "ทำงานของคุณ" และยอมรับการเปลี่ยนแปลงอีกครั้ง (หมายเหตุ: ขั้นตอนนี้เป็นทางเลือก)

git commit -am "blabla"

ในขณะนี้ต้นไม้ท้องถิ่นของคุณแตกต่างจากระยะไกล

git push -f <remote-name> <branch-name>

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

!! ระวังแท็กบางอย่างอาจยังชี้ถูกนำออกไปกระทำ !! วิธีที่จะลบ-a-ระยะไกลแท็ก


4
- ไฟล์ที่ถูกติดตามทั้งหมดจะถูกคอมมิต
jo_

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

1
ฉันควรใช้ "ป้ายกำกับก่อนหน้าหรือ sha1" ใด ฉันควรจะป้อน "แก้ไข" ล่าสุดหรือหนึ่งก่อนหน้านั้นแล้วทำการเปลี่ยนแปลงทั้งหมดที่ทำโดยแก้ไขล่าสุดหรือไม่
elysch

3
ก่อนที่ความผิดพลาดจะเกิดขึ้น
jo_

1
สิ่งที่ฉันต้องการ ฉันผลักสาขาให้เชี่ยวชาญโดยไม่ได้ตั้งใจ และด้วยเหตุนี้ฉันจึงมีขยะมากมายในช่วงประวัติศาสตร์ ฉันเพิ่งทำgit push -fเพื่อการแก้ไขครั้งสุดท้ายและล้างประวัติระยะไกล! ขอบคุณ!
Anton Rybalko

193

สิ่งที่ฉันทำในกรณีเหล่านี้คือ:

  • ในเซิร์ฟเวอร์เลื่อนเคอร์เซอร์กลับไปที่การคอมมิตที่รู้จักล่าสุด:

    git push -f origin <last_known_good_commit>:<branch_name>
    
  • ทำในพื้นที่เดียวกัน:

    git reset --hard <last_known_good_commit>
    #         ^^^^^^
    #         optional
    



ดูตัวอย่างเต็มรูปแบบในสาขาmy_new_branchที่ฉันสร้างขึ้นเพื่อจุดประสงค์นี้:

$ git branch
my_new_branch

นี่คือประวัติล่าสุดหลังจากเพิ่มบางสิ่งลงในmyfile.py:

$ git log
commit 80143bcaaca77963a47c211a9cbe664d5448d546
Author: me
Date:   Wed Mar 23 12:48:03 2016 +0100

    Adding new stuff in myfile.py

commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

ฉันต้องการกำจัดความมุ่งมั่นครั้งล่าสุดซึ่งถูกผลักไปแล้วดังนั้นฉันจึงเรียกใช้:

$ git push -f origin b4zad078237fa48746a4feb6517fa409f6bf238e:my_new_branch
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:me/myrepo.git
 + 80143bc...b4zad07 b4zad078237fa48746a4feb6517fa409f6bf238e -> my_new_branch (forced update)

ดี! ตอนนี้ฉันเห็นไฟล์ที่มีการเปลี่ยนแปลงในการกระทำที่myfile.pyแสดง( ) ใน "ไม่จัดฉากสำหรับการกระทำ":

$ git status
On branch my_new_branch
Your branch is up-to-date with 'origin/my_new_branch'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   myfile.py

no changes added to commit (use "git add" and/or "git commit -a")

เนื่องจากฉันไม่ต้องการการเปลี่ยนแปลงเหล่านี้ฉันเพียงแค่เลื่อนเคอร์เซอร์กลับไปข้างบนเช่นกัน:

$ git reset --hard b4zad078237fa48746a4feb6517fa409f6bf238e
HEAD is now at b4zad07 Initial commit

ดังนั้นตอนนี้ HEAD อยู่ในการคอมมิชชันก่อนหน้านี้, ทั้งใน local และ remote:

$ git log
commit b4zad078237fa48746a4feb6517fa409f6bf238e
Author: me
Date:   Tue Mar 18 12:46:59 2016 +0100

    Initial commit

10
นี่คือคำตอบที่ถูกต้อง! ตรงนี้เป็นสิ่งที่จำเป็น o ทำได้ในกรณีขอบคุณฉันได้เรียนรู้สิ่งใหม่ในวันนี้ :)
Egli Becerra

2
นี่คือคำตอบที่ถูกต้อง! มันเกี่ยวกับการผลัก (!)
powtac

3
หากคุณต้องการยกเลิกการเปลี่ยนแปลงอย่างแท้จริง (ราวกับว่าคุณไม่เคยผลักดัน) นี่คือคำตอบที่ถูกต้อง
Jacob

1
คำตอบที่สมบูรณ์แบบ ทำงานได้ดีอย่างที่คาดไว้!
RafiAlhamd

2
ใครบางคนซื้อเบียร์ชายคนนี้!
Jay Nebhwani

72

คุณสามารถย้อนกลับ (หรือคุณสามารถเรียกมันว่าลบ ) ทั้ง Git Commit ทั้งในประเทศและจากระยะไกลหากคุณทำตามขั้นตอนตามที่ระบุด้านล่างผ่านทางบรรทัดคำสั่ง git

รันคำสั่งต่อไปนี้เพื่อดูรหัสยืนยันที่คุณต้องการเปลี่ยนกลับ

git log --oneline --decorate --graph

คุณจะได้ภาพหน้าจอดังต่อไปนี้ ป้อนคำอธิบายรูปภาพที่นี่

หากคุณตรวจสอบระยะไกล(ผ่านทางเว็บอินเตอร์เฟส)คุณจะเห็นได้ว่าสิ่งนี้จะเหมือนกับที่แสดงด้านล่าง

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

ตามภาพหน้าจอปัจจุบันคุณกำลังใช้งาน id e110322แต่คุณต้องการเปลี่ยนกลับเป็น030bbf6ทั้งในประเทศและในระยะไกล

ทำตามขั้นตอนต่อไปนี้เพื่อลบ / ย้อนกลับคอมมิชชันภายใน + จากระยะไกล


การย้อนกลับภายในเครื่องเพื่อยอมรับ ID 030bbf6

git reset --hard 030bbf6

ติดตามโดย

git clean -f -d

คำสั่งสองคำสั่งเหล่านี้สะอาดกำลังรีเซ็ตเพื่อยอมรับสเตจ030bbf6ดังที่แสดงด้านล่างในสแน็ปช็อต

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

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

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

git fetch --all

เมื่อคุณทำเสร็จแล้วคุณจะต้องผลักดันการกระทำนี้อย่างแข็งขันโดยใช้สัญลักษณ์+ด้านหน้าของสาขาดังแสดงด้านล่าง ฉันใช้ที่นี่เป็นสาขาหลักคุณสามารถแทนที่ด้วยใด ๆ

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

git push -u origin +master

ตอนนี้ถ้าคุณเห็นเว็บอินเตอร์เฟสของรีโมทแล้วคอมมิชชันก็ควรย้อนกลับมาเช่นกัน

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


61

สิ่งนี้จะลบการกระทำที่คุณผลักไว้

git reset --hard 'xxxxx'

git clean -f -d

git push -f

7
วิธีนี้อย่างถูกต้องเขียนประวัติเพื่อลบการกระทำ ยอดเยี่ยม
Jesse Reza Khorasanee

2
คำตอบนี้คือ el magnifeco!
trueadjustr

3
รักคำตอบขอบคุณ :)
Dzenis H.

1
เพียงเพื่อให้ชัดเจน (ฉันไม่แน่ใจ): ความมุ่งมั่นจะเป็นความมุ่งมั่นในปัจจุบันหลังจากการดำเนินการ ไม่ใช่คนสุดท้ายที่จะลบ
Maik639

21
git revert HEAD -m 1

ในบรรทัดรหัสข้างต้น "อาร์กิวเมนต์สุดท้ายแสดงถึง"

  • 1 - แปลงหนึ่งคอมมิต

  • 2 - แปลงการกระทำสองครั้งล่าสุด

  • n - แปลง n ครั้งล่าสุดที่กระทำ

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


ใช้ในภายหลังgit commit -am "COMMIT_MESSAGE" แล้วgit pushหรือgit push -f


8
สิ่งนี้ไม่เป็นความจริง - พารามิเตอร์ -m ระบุจำนวนพาเรนต์ที่จะเปลี่ยนกลับเป็น (โดยทั่วไปคือ 1 หากคุณต้องการเปลี่ยนกลับมาเป็น "ของพวกเขา" การเปลี่ยนแปลงซึ่งตรงข้ามกับ 2 สำหรับการรวมไปยังการเปลี่ยนแปลง "ของเรา" - สำหรับการรวม 2 กระทำ) ไม่มีอะไรเกี่ยวข้องกับจำนวนการกระทำที่ถูกย้อนกลับ - หากคุณต้องการเปลี่ยนช่วงการยอมรับให้ใช้git revert ref1..ref2
Null Reference

1
ไม่มีผลตามที่ต้องการ
Sam Tuke

2

2563 วิธีง่าย ๆ :

git reset <commit_hash>

(แฮชของการกระทำครั้งสุดท้ายที่คุณต้องการเก็บไว้)

คุณจะเก็บการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดไว้ในเครื่อง

หากคุณต้องการที่จะผลักดันอีกครั้งคุณต้องทำ:

git push -f

0

นี่คือวิธีของฉัน:

developสมมติว่าชื่อสาขาคือ

# Create a new temp branch based on one history commit
git checkout <last_known_good_commit_hash>
git checkout -b develop-temp

# Delete the original develop branch and 
# create a new branch with the same name based on the develop-temp branch
git branch -D develop
git checkout -b develop

# Force update this new branch
git push -f origin develop

# Remove the temp branch
git branch -D develop-temp

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