ย้อนกลับไปที่ Git เก่าที่กระทำใน repo สาธารณะ


802

ฉันจะย้อนกลับไปสู่การคอมมิทเฉพาะทางได้อย่างไร?

คำตอบที่ดีที่สุดที่ใครบางคนสามารถให้ฉันได้คือการใช้git revertX ครั้งจนกว่าฉันจะถึงความมุ่งมั่นที่ต้องการ

สมมุติว่าฉันต้องการกลับไปใช้ความมุ่งมั่นที่อายุ 20 คอมมิทฉันจะต้องรันมัน 20 ครั้ง

มีวิธีที่ง่ายกว่านี้หรือไม่?

ฉันไม่สามารถใช้รีเซ็ตได้เพราะพื้นที่เก็บข้อมูลนี้เป็นแบบสาธารณะ


1
git revert <commit> ไม่ทำงาน?
miku

8
ตามที่ระบุไว้ในคำถามของฉันสิ่งนี้ไม่ได้ช่วยฉันจริงๆถ้าฉันต้องการเปลี่ยนกลับไปใช้ 20 สิ่งที่ผ่านมาแล้ว
David

7
คำถามนี้ได้รับคำตอบค่อนข้างดีที่นี่stackoverflow.com/questions/4114095/…
user7610

4
ยังไม่ชัดเจนว่าคุณหมายถึงอะไรโดย "ย้อนกลับ" หมายความว่าคุณต้องการเปลี่ยนสำเนาการทำงานของคุณเป็นการชั่วคราวหรือไม่? หรือคุณต้องการที่จะย้อนกลับประวัติศาสตร์ของที่เก็บของคุณกลับไปเป็นการแก้ไขที่แน่นอน?

1
คุณควรยอมรับคำตอบและอาจโหวตคำตอบอื่น ๆ ที่คุณชอบ
นาบิลคาดิมิ

คำตอบ:


1194

ลองสิ่งนี้:

git checkout [revision] .

ที่[revision]เป็นกัญชากระทำ (ตัวอย่างเช่น: 12345678901234567890123456789012345678ab)

อย่าลืม.ตอนจบสิ่งที่สำคัญมาก สิ่งนี้จะนำการเปลี่ยนแปลงไปใช้กับต้นไม้ทั้งหมด คุณควรดำเนินการคำสั่งนี้ในรูทโครงการ git หากคุณอยู่ในไดเรกทอรีย่อยใด ๆ คำสั่งนี้จะเปลี่ยนไฟล์ในไดเรกทอรีปัจจุบันเท่านั้น จากนั้นทำและคุณควรจะดี

คุณสามารถยกเลิกได้โดย

git reset --hard 

ที่จะลบการแก้ไขทั้งหมดจากไดเรกทอรีการทำงานและพื้นที่การจัดเตรียม


7
@AlexReisner ช่วงเวลานั้นที่จุดสิ้นสุดที่ไดเรกทอรีที่คุณอยู่ในขณะนี้ซึ่งไม่จำเป็นต้องเป็นโครงการคอมไพล์ทั้งหมดถูกต้องหรือไม่ หากคุณต้องการใช้การเปลี่ยนแปลงกับโครงการทั้งหมดคุณจะใช้ ': /' เหมือนใน 'git add: /' แทนหรือไม่หากคุณไม่ได้อยู่ในรูทโครงการ git
MSpreij

10
หมายเหตุ: หากคุณเพิ่มไฟล์ใหม่ลงในโครงการของคุณตั้งแต่นั้นจะไม่ลบไฟล์ ดังนั้นเมื่อคุณไปสร้าง (ขึ้นอยู่กับแพลตฟอร์มของคุณ) คุณอาจได้รับข้อผิดพลาด ลบไฟล์ใหม่และคุณจะไปดี
TheWestIsThe ...

6
@MSpreij คุณควรดำเนินการคำสั่งนี้ในรูทโครงการ git หากคุณอยู่ในไดเรกทอรีย่อยใด ๆ คำสั่งนี้จะเปลี่ยนไฟล์ในไดเรกทอรีปัจจุบันเท่านั้น
volatilevar

3
มันยอดเยี่ยมเมื่อคุณสามารถโคลนโครงการในไดเรกทอรีอื่นและใช้ git checkout [revision] เพื่อกลับไปที่การแก้ไขที่เฉพาะเจาะจงและเปรียบเทียบกับโครงการเดียวกันในไดเรกทอรีอื่น ประหยัดเวลาได้มาก
Donato

4
Damnit ฉันลืม "." ฉันทำอะไรเสียหายกับที่เก็บของฉัน?
Owl

196

ในการย้อนกลับไปที่การคอมมิทเฉพาะ:

git reset --hard commit_sha

หากต้องการย้อนกลับ 10 คอมมิตย้อนกลับ:

git reset --hard HEAD~10

คุณสามารถใช้ "git revert" ได้ในโพสต์ต่อไปนี้หากคุณไม่ต้องการเขียนประวัติใหม่

จะแปลงที่เก็บ Git กลับเป็นการคอมมิชชันก่อนหน้าได้อย่างไร


4
ข้อแตกต่างระหว่างวิธีนี้กับ "ชำระเงิน git [การแก้ไข] เท่านั้น" เป็นที่หลังรักษาการแก้ไข
deeshank

53
คำตอบนี้ผิดเนื่องจาก OP ระบุว่า "ฉันไม่สามารถใช้การตั้งค่าใหม่ได้เพราะ repo นี้เป็นสาธารณะ"
Yarin

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

4
เป็นเรื่องที่ดีที่จะหลีกเลี่ยงการแยก HEAD! สิ่งที่ฉันกำลังมองหา
cyber-monk

1
ในกรณีของฉันนี้ใช้งานได้แล้วใช้ 'git pull' เพื่อกรอไปข้างหน้าอย่างรวดเร็วหลังจากคุณทดสอบการถดถอยแล้ว
Peter Quiring

86

ดีฉันเดาคำถามคือคุณหมายถึง 'ย้อนกลับ'? หากคุณไม่สามารถทำได้resetเพราะมันเป็นแบบสาธารณะและคุณต้องการเก็บประวัติการคอมมิชชันไว้คุณหมายความว่าคุณต้องการให้สำเนาการทำงานของคุณสะท้อนการกระทำที่เฉพาะเจาะจงหรือไม่? ใช้git checkoutและแฮชการกระทำ

แก้ไข: ดังที่ได้กล่าวไว้ในความคิดเห็นการใช้git checkoutโดยไม่ระบุสาขาจะทำให้คุณอยู่ในสถานะ "ไม่มีสาขา" ใช้git checkout <commit> -b <branchname>เพื่อชำระเงินเป็นสาขาหรือgit checkout <commit> .ชำระเงินเป็นสาขาปัจจุบัน


สิ่งนี้ไม่ได้นำคุณเข้าสู่สถานะ 'แปลก ๆ ในปัจจุบันไม่ได้อยู่ที่สาขา' ใช่หรือไม่? คุณยอมรับการเปลี่ยนแปลงเพื่อให้การย้อนกลับสมบูรณ์อย่างไร
Alex Reisner

ฉันแค่แนะนำให้ใช้git checkout- เขามีอิสระที่จะตรวจสอบสาขาใด ๆ (ปัจจุบันหรือใหม่) ที่เขาต้องการ ฉันจะอัปเดตคำตอบของฉันดังนั้นมันจึงไม่ชัดเจน
Ben

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

3
หากคุณอยู่ในไดเรกทอรีที่ใช้งานได้และอยู่ในระดับปริญญาโทคุณจะต้องgit resetลบไฟล์เหล่านั้นซึ่งคุณบอกว่าคุณไม่ต้องการทำ ลองทำมันแยกสาขา: git checkout <commit> -b <branchname>คุณจะไม่มีไฟล์นิ่งในสาขานั้น
Ben

2
ปัญหาของการใช้checkoutคือมันจะไม่ลบไฟล์ที่ถูกเพิ่มในการคอมมิชชันก่อนหน้า

42

โปสเตอร์ต้นฉบับระบุ:

คำตอบที่ดีที่สุดที่ใครบางคนสามารถให้ฉันได้คือการใช้git revertX ครั้งจนกว่าฉันจะถึงความมุ่งมั่นที่ต้องการ

สมมุติว่าฉันต้องการกลับไปใช้ความมุ่งมั่นที่อายุ 20 คอมมิทฉันจะต้องรันมัน 20 ครั้ง

มีวิธีที่ง่ายกว่านี้หรือไม่?

ฉันใช้การรีเซ็ตไม่ได้เพราะ repo นี้เป็นแบบสาธารณะ

ไม่จำเป็นต้องใช้git revertX คูณ git revertสามารถยอมรับช่วงการยอมรับเป็นอาร์กิวเมนต์ดังนั้นคุณจะต้องใช้เพียงครั้งเดียวเพื่อเปลี่ยนช่วงของการกระทำ ตัวอย่างเช่นหากคุณต้องการเปลี่ยนการยอมรับ 20 ครั้งล่าสุด:

git revert --no-edit HEAD~20..

กระทำช่วงHEAD~20..สั้นสำหรับHEAD~20..HEADและวิธีการ "เริ่มต้นจาก 20 วันที่แม่ของ HEAD กระทำและย้อนกลับไปกระทำทั้งหมดหลังจากมันขึ้นอยู่กับหัว"

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

git revert -m 1 <merge-commit>

โปรดทราบว่าฉันได้ทดสอบด้วยช่วงgit revertโดยใช้ git เวอร์ชัน 1.9.0 หากคุณกำลังใช้คอมไพล์รุ่นเก่ากว่าการใช้ช่วงที่มีgit revertหรืออาจใช้ไม่ได้

ในกรณีนี้เป็นที่ต้องการมากกว่าgit revertgit checkout

หมายเหตุว่าแตกต่างจากคำตอบนี้ที่บอกว่าจะใช้git checkout , git revert จริงจะลบไฟล์ใด ๆ ที่ถูกเพิ่มเข้ามาในใด ๆ ของกระทำที่คุณกำลังย้อนกลับซึ่งทำให้นี้วิธีที่ถูกต้องเพื่อย้อนกลับไปช่วงของการแก้ไข

เอกสาร


หมายเหตุ : สิ่งนี้จะสร้างคอมมิทใหม่ด้วยการเปลี่ยนแปลงกลับคืน เหมาะสำหรับคำถามของ OP แต่ให้แน่ใจว่านั่นคือสิ่งที่คุณต้องการ (ตัวอย่างในเอกสารgit-revert doc ที่เชื่อมโยงกับด้านบนนั้นยอดเยี่ยม) หากคุณต้องการตรวจสอบการกระทำก่อนหน้า (เช่นก่อนที่จะเลือกสิ่งที่จะส่งกลับ) ให้ใช้ตัวเลือกการชำระเงินที่ระบุไว้ในคำตอบอื่น ๆ ทำเกี่ยวกับไฟล์ที่ถูกลบ
SherylHohman

@SherylHohman การย้อนกลับไปยังการคอมมิชชันก่อนหน้าไม่ได้สร้างการคอมมิทใหม่ ฉันนึกภาพไม่ออกว่าคุณหมายถึงอะไรที่นี่

27

ขั้นตอนที่ 1:ดึงรายการคอมมิท:

git log

คุณจะได้รับรายการเช่นในตัวอย่างนี้:

[Comp:Folder User$ git log
commit 54b11d42e12dc6e9f070a8b5095a4492216d5320
Author: author <author@gmail.com>
Date:   Fri Jul 8 23:42:22 2016 +0300

This is last commit message

commit fd6cb176297acca4dbc69d15d6b7f78a2463482f
Author: author <author@gmail.com>
Date:   Fri Jun 24 20:20:24 2016 +0300

This is previous commit message

commit ab0de062136da650ffc27cfb57febac8efb84b8d
Author: author <author@gmail.com>
Date:   Thu Jun 23 00:41:55 2016 +0300

This is previous previous commit message
...

ขั้นตอนที่ 2:คัดลอกข้อมูลที่จำเป็นแฮชและวางเพื่อชำระเงิน:

git checkout fd6cb176297acca4dbc69d15d6b7f78a2463482f

นั่นคือทั้งหมดที่


11
git read-tree -um @ $commit_to_revert_to

จะทำมัน มันเป็น "เช็คเอาต์คอมไพล์" แต่ไม่มีการอัปเดต HEAD

คุณสามารถบรรลุผลเช่นเดียวกันกับ

git checkout $commit_to_revert_to
git reset --soft @{1}

ถ้าคุณชอบคำสั่งอำนวยความสะดวกคบกัน

เหล่านี้ทำให้คุณมี worktree และดัชนีคุณอยู่ในสถานะที่ต้องการคุณก็สามารถgit commitที่จะเสร็จสิ้น


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

6

ต้องการโหมดแยกส่วนหัวหรือไม่

หากคุณต้องการย้อนเวลา X ให้กับการกระทำบางอย่างด้วย DETACHED HEAD (หมายถึงคุณไม่สามารถเลอะเทอะ) จากนั้นใช้วิธีดังต่อไปนี้:

(แทนที่ X ด้วยจำนวนที่คุณต้องการย้อนกลับ)

git checkout HEAD~X

IE เพื่อย้อนกลับไปหนึ่งคอมมิท:

git checkout HEAD~1

1
ฉันจะลบส่วนที่มี... ยากที่จะเชื่อ ...ดูเหมือนเป็นเรื่องส่วนตัวและมีคนพูดถึงมันในความคิดเห็นด้านบนและใน @ken ด้วยเช่นกันในคำตอบของเขา
meJustAndrew

@ meJustAndrew มันเป็นคำตอบมากมายสำหรับ SO ที่เพิ่งสร้างความสับสนให้กับคนมันน่ารำคาญมาก
Karl Morrison

ช่างเป็นคำตอบที่ง่ายและตรงไปตรงมา
Ammad

2

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

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 .

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

git checkout 792d9294f652d753514dc2033a04d742decb82a5 .

และเช็คเอาต์ไฟล์เฉพาะก่อนที่มันจะทำให้เกิดข้อผิดพลาด (ในกรณีของฉันฉันใช้ตัวอย่าง Gemfile.lock):

git checkout 8a0fe5191b7dfc6a81833bfb61220d7204e6b0a9 -- /projects/myproject/Gemfile.lock

และนี่คือวิธีหนึ่งในการจัดการข้อผิดพลาดที่คุณสร้างขึ้นในการกระทำโดยไม่ตระหนักถึงข้อผิดพลาดจนกระทั่งในภายหลัง


2

คุณสามารถค้นหารหัสการกระทำที่เกี่ยวข้องกับแต่ละการกระทำได้ในส่วนการกระทำของ GitHub / BitBucket / Gitlab มันง่ายมากสมมติว่ารหัสคอมมิชชันของคุณคือ5889575ถ้าคุณต้องการกลับไปที่ส่วนนี้ในรหัสของคุณคุณก็ต้องพิมพ์

git checkout 5889575 .

สิ่งนี้จะนำคุณไปสู่จุดนั้นในรหัสของคุณ


1

ผมไม่แน่ใจว่าสิ่งที่เปลี่ยนแปลง --detachแต่ฉันไม่สามารถชำระเงินที่เฉพาะเจาะจงกระทำการโดยไม่เลือกที่ คำสั่งเต็มรูปแบบที่ทำงานสำหรับฉันคือ: git checkout --detach [commit hash]

ในการกลับจากสถานะเดี่ยวฉันต้องเช็คเอ้าท์สาขาในพื้นที่ของฉัน: git checkout master


การตรวจสอบmasterแก้ไขปัญหาการแยกออกที่เหลือในขณะที่ทำงานgit reset --hardหรือgit checkout -- .ทำงาน แต่ยังคงแยกออก
DarkCygnus

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