เปลี่ยนกลับการเปลี่ยนแปลงเป็นไฟล์ในคอมมิต


126

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

ฉันสามารถใช้คำสั่ง git revert ได้หรือไม่

วิธีง่ายๆอื่น ๆ ที่จะทำ?



แปลก ... ทำไมการเปลี่ยนแปลงหลังจากหลายปีที่ผ่านมา?
VonC

คำตอบ:


222

วิธีที่สะอาดที่สุดที่ฉันเคยเห็นมีอธิบายไว้ที่นี่

git show some_commit_sha1 -- some_file.c | git apply -R

คล้ายกับการตอบสนองของ VonC แต่ใช้git showและgit apply.


10
ทำได้ดีมาก โซลูชันสคริปต์เกินความจำเป็นสำหรับสิ่งนี้ เหตุใดจึงไม่มีเพียงแค่ git เปลี่ยนชื่อไฟล์ sha-1
Mark Edington

16
สิ่งนี้ใช้ได้กับ Mac ของฉัน แต่บน Windows (ภายใต้ Cygwin) มันให้ฉัน:fatal: unrecognized input
Kedar Mhaswade

1
@MerhawiFissehaye: ฉันคิดว่าการชำระเงิน git จะย้อนกลับการเปลี่ยนแปลงอีกครั้งเพื่อถอยกลับไปสู่สถานะสิ่งที่กระทำ ฉันทำ 'git เพิ่มชื่อไฟล์; git คอมมิต --amend 'เพื่อลบไฟล์ออกจากคอมมิต
ViFI

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

2
อาจจะชัดเจนสำหรับคนส่วนใหญ่ แต่ตรวจสอบให้แน่ใจว่าsome_file.cมีพา ธไปยังไฟล์หากมีอย่างอื่นคุณจะไม่ทำการแก้ไขอะไรเลย :)
Warpling

35

สมมติว่าสามารถเปลี่ยนประวัติการคอมมิตได้นี่คือเวิร์กโฟลว์เพื่อเปลี่ยนกลับการเปลี่ยนแปลงในไฟล์เดียวในคอมมิตก่อนหน้านี้:

ตัวอย่างเช่นคุณต้องการยกเลิกการเปลี่ยนแปลงใน 1 ไฟล์ ( badfile.txt) ในการกระทำaaa222:

aaa333 Good commit
aaa222 Problem commit containing badfile.txt
aaa111 Base commit

สร้างฐานใหม่บนฐานการกระทำแก้ไขปัญหาและดำเนินการต่อ

1) เริ่ม rebase แบบโต้ตอบ:

git rebase -i aaa111

2) ทำเครื่องหมายที่ปัญหาเพื่อแก้ไขในตัวแก้ไขโดยเปลี่ยนpickเป็นe(สำหรับแก้ไข):

e aaa222
pick aaa333

3) ยกเลิกการเปลี่ยนแปลงไปยังไฟล์ที่ไม่ถูกต้อง:

git show -- badfile.txt | git apply -R

4) เพิ่มการเปลี่ยนแปลงและแก้ไขการกระทำ:

git add badfile.txt
git commit --amend

5) เสร็จสิ้น rebase:

git rebase --continue

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

น่าอัศจรรย์ นี่คือสิ่งที่ฉันกำลังมองหา ฉันมีความคิดนี้แล้ว แต่สับสนเมื่อทำ rebase แบบโต้ตอบที่ไฟล์เมื่อทำeditไม่ได้แสดงว่ามีการเปลี่ยนแปลง แต่git show -- badfile.txt | git apply -Rคำตอบที่ฉันต้องการ <3
mraxus

ถ้าฉันเข้าใจ git นี้ใช้ -R จะลบคอมมิตของไฟล์ที่ตั้งค่าให้กลับสู่สถานะเดิมที่เปลี่ยนไป?
DaImTo

19

git revert มีไว้สำหรับเนื้อหาไฟล์ทั้งหมดภายในคอมมิต

สำหรับไฟล์เดียวคุณสามารถเขียนสคริปต์ได้ :

#!/bin/bash

function output_help {
    echo "usage: git-revert-single-file <sha1> <file>"
}

sha1=$1
file=$2

if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi

(จากยูทิลิตี้git-shell-scriptsจากsmtlaissezfaire )


บันทึก:

มีการอธิบายวิธีอื่นไว้ที่นี่หากคุณยังไม่ได้ทำการแก้ไขปัจจุบัน

git checkout -- filename

git checkout มีตัวเลือกบางอย่างสำหรับไฟล์การแก้ไขไฟล์จาก HEAD เขียนทับการเปลี่ยนแปลงของคุณ


Drop On Capricaกล่าวถึงในความคิดเห็น :

คุณสามารถเพิ่มนามแฝงในคอมไพล์เพื่อให้คุณสามารถทำgit revert-file <hash> <file-loc>และเปลี่ยนไฟล์นั้นได้
ดูส่วนสำคัญนี้

[alias]
  revert-file = !sh /home/some-user/git-file-revert.sh

เพียงเพิ่มในการสนทนาที่นี่คุณสามารถเพิ่มนามแฝงในคอมไพล์เพื่อให้คุณสามารถทำgit revert-file <hash> <file-loc>และเปลี่ยนไฟล์นั้นได้ ฉันยกจากคำตอบนี้ (แม้ว่าฉันจะต้องทำการแก้ไขสองสามครั้งเพื่อให้ทำงานได้อย่างถูกต้อง) คุณสามารถค้นหาสำเนาของ.gitconfigสคริปต์ของฉันและแก้ไขได้ที่นี่: gist.github.com/droppedoncaprica/5b67ec0021371a0ad438
AlbertEngelB

@ ลดลง On Caprica จุดดี ฉันได้รวมไว้ในคำตอบเพื่อให้มองเห็นได้มากขึ้น
VonC

12

ฉันจะใช้--no-commitตัวเลือกในการgit-revertแล้วลบไฟล์ที่คุณไม่ต้องการเปลี่ยนกลับจากดัชนีก่อนที่จะดำเนินการในที่สุด นี่คือตัวอย่างที่แสดงวิธีการเปลี่ยนกลับเฉพาะการเปลี่ยนแปลงของ foo.c อย่างง่ายดายในการกระทำล่าสุดอันดับสอง:

$ git revert --no-commit HEAD~1
$ git reset HEAD
$ git add foo.c
$ git commit -m "Reverting recent change to foo.c"
$ git reset --hard HEAD

git-reset"unstages" ไฟล์แรกทั้งหมดเพื่อให้เราสามารถเพิ่มกลับเพียงไฟล์เดียวที่เราต้องการเปลี่ยนกลับ ขั้นสุดท้ายgit-reset --hardจะกำจัดไฟล์ที่เหลือซึ่งเราไม่ต้องการเก็บไว้


9

ง่ายกว่ามาก:

git reset HEAD^ path/to/file/to/revert

แล้วก็

git commit --amend   

แล้ว

git push -f

ไฟล์หายไปและคอมมิตแฮชข้อความและอื่น ๆ เหมือนกัน


เพื่อความสมบูรณ์ต้องมีgit checkout -- path/to/file/to/revertขั้นตอนหรือไม่? นอกจากนี้มันไม่จริงที่แฮชจะเหมือนกันในภายหลังใช่มั้ย? ประโยคสุดท้ายอาจจะดีกว่าเช่น: "ผลลัพธ์คือการกระทำสุดท้ายจะถูกแทนที่ด้วยอันใหม่ที่แตกต่างกันเฉพาะที่ไม่มีการเปลี่ยนแปลงในไฟล์ที่กลับด้าน"
Kevin

@ เควินคุณคงพูดถูก ฉันจะต้องตรวจสอบบรรทัดสุดท้ายอีกครั้ง แต่เมื่อมองย้อนกลับไปเมื่อสองสามปีก่อนฉันจะแปลกใจถ้าแฮชคอมมิตไม่เปลี่ยนแปลง
Forrest

6
git reset HEAD^ path/to/file/to/revert/in/commit

คำสั่งดังกล่าวจะนำไฟล์ออกจากการกระทำ git statusแต่มันจะสะท้อนให้เห็นถึง

git checkout path/to/file/to/revert/in/commit

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

git commit

(ผ่าน--amendเพื่อแก้ไขข้อผูกพัน)

git push

ด้วยวิธีนี้ไฟล์ที่อยู่ในคอมมิตจะถูกลบออกและเปลี่ยนกลับ

ควรปฏิบัติตามขั้นตอนข้างต้นจากสาขาที่มีการคอมมิต


5

คุณสามารถทำตามขั้นตอนนี้:

  1. git revert -n <*commit*>( -nเปลี่ยนกลับการเปลี่ยนแปลงทั้งหมด แต่จะไม่คอมมิต)
  2. git add <*filename*> (ชื่อไฟล์ที่คุณต้องการเปลี่ยนกลับและคอมมิต)
  3. git commit -m 'reverted message' (เพิ่มข้อความสำหรับการเปลี่ยนกลับ)
  4. หลังจากทำการละทิ้งไฟล์อื่น ๆ จะมีการเปลี่ยนแปลงเพื่อให้ไฟล์ได้รับการอัปเดตตามการเปลี่ยนแปลงที่คุณกระทำก่อนที่จะเปลี่ยนกลับ

1

หากคุณต้องการรีเซ็ตการเปลี่ยนแปลงในไฟล์จากคอมมิตล่าสุดของคุณนี่คือสิ่งที่ฉันมักจะใช้ ฉันคิดว่านี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุด

โปรดสังเกตว่าไฟล์จะถูกเพิ่มลงในพื้นที่จัดเตรียม

git checkout <prev_commit_hash> -- <path_to_your_file>

หวังว่าจะช่วยได้ :)

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