Hoàn nguyên các thay đổi đối với một tệp trong một cam kết


126

Tôi chỉ muốn hoàn nguyên các thay đổi được thực hiện bởi một cam kết cụ thể đối với một tệp nhất định.

Tôi có thể sử dụng lệnh git revert cho việc đó không?

Bất kỳ cách đơn giản nào khác để làm điều đó?



Kỳ lạ ... tại sao lại thay đổi sau ngần ấy năm?
VonC

Câu trả lời:


222

Cách sạch sẽ nhất mà tôi từng thấy để làm việc này được mô tả ở đây

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

Tương tự như phản hồi của VonC nhưng sử dụng git showgit apply.


10
Tốt lắm. Giải pháp tập lệnh là quá mức cần thiết cho việc này. Tại sao không thể chỉ có git revert sha-1 filename?
Mark Edington

16
Này hoạt động trên máy Mac của tôi, nhưng trên Windows (dưới Cygwin) nó mang lại cho tôi:fatal: unrecognized input
Kedar Mhaswade

1
@MerhawiFissehaye: Tôi nghĩ rằng git checkout sẽ chỉ hoàn nguyên các thay đổi một lần nữa để trở lại trạng thái như đã cam kết. Tôi đã 'git thêm tên tệp; git commit --amend 'để xóa tệp khỏi cam kết.
ViFI

3
Chỉ là một mẹo nhỏ, tôi hầu như luôn phải thêm -3cờ để git áp dụng cho hợp nhất ba chiều khi bản vá không thành công, vì tôi thường sửa một chút thay đổi theo thời gian.
angularsen

2
Có lẽ hiển nhiên đối với hầu hết nhưng đảm bảo some_file.cbao gồm các con đường đến tập tin nếu có một nếu không bạn sẽ âm thầm vá gì :)
Warpling

35

Giả sử có thể thay đổi lịch sử cam kết, đây là quy trình làm việc để hoàn nguyên các thay đổi trong một tệp trong một cam kết trước đó:

Ví dụ: bạn muốn hoàn nguyên các thay đổi trong 1 tệp ( badfile.txt) trong cam kết aaa222:

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

Căn cứ vào cam kết cơ sở, sửa đổi cam kết vấn đề và tiếp tục.

1) Bắt đầu rebase tương tác:

git rebase -i aaa111

2) Đánh dấu cam kết vấn đề để chỉnh sửa trong trình chỉnh sửa bằng cách thay đổi pickthành e(để chỉnh sửa):

e aaa222
pick aaa333

3) Hoàn nguyên các thay đổi đối với tệp xấu:

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

4) Thêm các thay đổi và sửa đổi cam kết:

git add badfile.txt
git commit --amend

5) Hoàn thành rebase:

git rebase --continue

Chỉ muốn chỉ ra rằng điều này giả định rằng bạn có thể chỉnh sửa lịch sử git. Một số câu trả lời ở trên tạo một cam kết mới đảo ngược thay đổi cụ thể mà không cần chỉnh sửa lịch sử, điều này không phải lúc nào cũng có thể / được phép.
angularsen

Tuyệt diệu. Đây chính xác là những gì tôi đang tìm kiếm. Tôi đã có ý tưởng này rồi, nhưng đã bối rối khi thực hiện rebase tương tác mà các tệp khi thực hiện editkhông hiển thị như đã thay đổi. Tuy nhiên, git show -- badfile.txt | git apply -Rđã đưa ra câu trả lời tôi cần <3
mraxus

nếu tôi hiểu điều này git áp dụng -R loại bỏ cam kết trên tệp đó đặt nó trở lại trạng thái thay đổi ban đầu?
DaImTo

19

git revert là cho tất cả nội dung tệp trong một cam kết.

Đối với một tệp duy nhất, bạn có thể tập lệnh cho nó :

#!/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

(Từ các tiện ích git-shell-scripts từ smtlaissezfaire )


Ghi chú:

một cách khác được mô tả ở đây nếu bạn vẫn chưa thực hiện sửa đổi hiện tại của mình.

git checkout -- filename

git checkout có một số tùy chọn cho tệp, sửa đổi tệp từ HEAD, ghi đè thay đổi của bạn.


Dropped.on.Caprica đề cập trong các bình luận :

Bạn có thể thêm bí danh vào git để có thể thực hiện git revert-file <hash> <file-loc>và yêu cầu hoàn nguyên tệp cụ thể đó.
Xem ý chính này .

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

Chỉ để thêm vào cuộc thảo luận ở đây, bạn có thể thêm bí danh vào git để bạn có thể thực hiện git revert-file <hash> <file-loc>và yêu cầu hoàn nguyên tệp cụ thể đó. Tôi đã loại bỏ câu trả lời này (mặc dù tôi đã phải thực hiện một vài chỉnh sửa để hoạt động chính xác). Bạn có thể tìm bản sao .gitconfigtập lệnh của tôi và đã chỉnh sửa tại đây: gist.github.com/droppedoncaprica/5b67ec0021371a0ad438
AlbertEngelB

@ Dropped.on.Caprica điểm tốt. Tôi đã đưa nó vào câu trả lời để dễ nhìn hơn.
VonC

12

Tôi chỉ cần sử dụng --no-committùy chọn để git-revertvà sau đó xóa các tệp bạn không muốn hoàn nguyên khỏi chỉ mục trước khi cuối cùng cam kết nó. Dưới đây là một ví dụ cho thấy cách dễ dàng hoàn nguyên các thay đổi đối với foo.c trong lần cam kết gần đây nhất thứ hai:

$ 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

Đầu tiên git-reset"loại bỏ" tất cả các tệp, để sau đó chúng tôi có thể thêm lại chỉ một tệp mà chúng tôi muốn hoàn nguyên. Cuối cùng git-reset --hardloại bỏ các hoàn nguyên tệp còn lại mà chúng tôi không muốn giữ lại.


9

Đơn giản hơn nhiều:

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

sau đó

git commit --amend   

và sau đó

git push -f

tệp đã biến mất và cam kết băm, thông báo, v.v. vẫn như cũ.


Để hoàn chỉnh, bạn có cần một git checkout -- path/to/file/to/revertbước? Ngoài ra, việc băm sau đó cũng không đúng, đúng không? Câu cuối cùng có thể tốt hơn như: "Kết quả là cam kết cuối cùng được thay thế bằng một cam kết mới chỉ khác ở chỗ nó không chứa các thay đổi đối với tệp được hoàn nguyên."
Kevin

@Kevin có lẽ bạn đúng. Tôi sẽ phải kiểm tra lại dòng cuối cùng đó, nhưng nhìn lại điều này từ vài năm trước, tôi sẽ ngạc nhiên nếu hàm băm cam kết không thay đổi.
Forrest

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

Lệnh trên sẽ đưa tệp ra khỏi cam kết, nhưng nó sẽ phản ánh trong git status.

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

Lệnh trên sẽ hoàn nguyên các thay đổi (kết quả là bạn nhận được tệp giống như HEAD).

git commit

(Vượt qua --amendđể sửa đổi cam kết.)

git push

Với điều này, tệp đã có trong cam kết sẽ bị xóa và hoàn nguyên.

Các bước trên phải được thực hiện từ nhánh nơi thực hiện cam kết.


5

Bạn có thể làm theo quy trình sau:

  1. git revert -n <*commit*>( -nhoàn nguyên tất cả các thay đổi nhưng sẽ không thực hiện chúng)
  2. git add <*filename*> (tên của / các tệp bạn muốn hoàn nguyên và cam kết)
  3. git commit -m 'reverted message' (thêm tin nhắn để hoàn nguyên)
  4. sau khi cam kết, loại bỏ các thay đổi tệp khác để các tệp luôn được cập nhật với những thay đổi bạn đã cam kết trước khi hoàn nguyên

1

Nếu bạn muốn đặt lại các thay đổi trên tệp từ lần cam kết cuối cùng của mình, đây là những gì tôi thường sử dụng. Tôi nghĩ đây là giải pháp đơn giản nhất.

Xin lưu ý rằng tệp sẽ được thêm vào khu vực tổ chức.

git checkout <prev_commit_hash> -- <path_to_your_file>

Hy vọng nó giúp :)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.