Tôi có thể hoàn nguyên một phần trong GIT không


156

Có thể chỉ hoàn nguyên một tệp duy nhất hoặc một số thay đổi nhất định trong một tệp trong cam kết nhiều tệp không?

Câu chuyện đầy đủ tôi cam kết một loạt các tập tin. Một số cam kết sau đó một người nào đó sẽ vẫn không tên (JACK !!!) đã sao chép một tệp vào kho lưu trữ của mình và cam kết một số tệp, ghi đè một số thay đổi tôi đã thực hiện. Tôi muốn hoàn nguyên một tệp đã bị ghi đè hoặc tốt hơn, hãy truy cập và hoàn nguyên hai thay đổi trong tệp đó. Đây sẽ phải là một cam kết hoàn nguyên riêng biệt kể từ khi nó được kéo và đẩy.


Brian đã đưa tôi đi đúng hướng. Tôi đã kết thúc bằng git add --patch sau đó sử dụng chức năng chỉnh sửa trong bản vá để có được thứ tôi muốn.
Ly hợp

2
Tôi đến trò chơi khá muộn, nhưng tôi nghĩ rằng tôi đã tìm thấy câu trả lời "đúng" .
ntc2

@ ntc2 Kỳ lạ thay, câu trả lời được chấp nhận làm việc cho tôi tốt hơn nhiều so với câu trả lời mà bạn đã liên kết - nó tạo ra xung đột hợp nhất để tôi giải quyết, thay vì chỉ không áp dụng các bản vá.
Iiridayn

@liridayn Bạn đã đọc toàn bộ câu trả lời của tôi chưa? Trong phần "biến thể", tôi khẳng định rằng việc thêm --3waykết quả vào xung đột hợp nhất thay vì không áp dụng các bản vá.
ntc2

Câu trả lời:


204

Bạn có thể hoàn nguyên cam kết mà không cần tạo một cam kết mới bằng cách thêm tùy chọn '--no-commit'. Điều này để lại tất cả các tập tin hoàn nguyên trong khu vực tổ chức. Từ đó, tôi sẽ thực hiện thiết lập lại mềm và thêm vào những thay đổi tôi thực sự muốn. Đối với một quy trình làm việc ví dụ:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit

42
Sau khi thiết lập lại mềm, bạn cũng có thể làm git add -pđể bắt đầu một phiên tương tác cho phép bạn chọn lọc thêm các khối tệp, thay vì toàn bộ tệp. (Cũng git reset -pcó những thay đổi có chọn lọc trong giai đoạn. Rất tốt để biết, nhưng có lẽ không phải là điều bạn muốn trong kịch bản này.)
Stéphan Kochen

1
Đây chính xác là những gì tôi đang tìm kiếm: Hoàn nguyên thành bản sao làm việc, chọn người tương tác, cam kết. Bạn xứng đáng với một người đàn ông to lớn, mặn mà vì điều đó: *
das_weezul

Một giải pháp lấy cảm hứng từ một này sẽ được revert, reset, stash -p(stash "hủy bỏ mà tôi không muốn làm actualy"), addphần còn lại,commit
Cyril Chapon

82

Bạn có thể tương tác áp dụng phiên bản cũ của một tệp bằng checkoutlệnh.

Ví dụ: nếu bạn biết COMMITnơi mã để thêm lại bị xóa, bạn có thể chạy lệnh sau:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git sẽ nhắc bạn thêm lại các hunk bị thiếu trong phiên bản hiện tại của tệp. Bạn có thể sử dụng eđể tạo một bản vá của thay đổi trước khi áp dụng lại.


Rất hữu ích nếu bạn chỉ muốn hoàn nguyên một phần của tập tin! Về cơ bản, để có được khối từ đầu,git checkout -p path/to/file
falstaff

40

Bạn chỉ có thể kiểm tra thủ công các nội dung cũ, tốt của các tệp bạn muốn hoàn nguyên bằng cách sử dụng git checkout. Chẳng hạn, nếu bạn muốn trở lại my-important-filephiên bản đã có trong phiên bản abc123, bạn có thể làm

git checkout abc123 -- my-important-file

Bây giờ bạn có nội dung cũ my-important-filevà thậm chí có thể chỉnh sửa chúng nếu bạn muốn và cam kết như bình thường để thực hiện một cam kết sẽ hoàn nguyên các thay đổi mà anh ấy đã thực hiện. Nếu chỉ có một số phần trong cam kết của anh ta mà bạn muốn hoàn nguyên, hãy sử dụng git add -pđể chỉ chọn một vài người trong số các bản vá mà bạn đang cam kết.


19
Đây không phải là revert, bạn chỉ lấy lại một phiên bản cũ của tệp. Một revertsửa đổi phù hợp sẽ loại bỏ các sửa đổi cam kết xấu trong tệp, ngay cả khi nó đã được sửa đổi nhiều lần kể từ lần cam kết xấu đó và bạn không muốn mất các sửa đổi đó.
Totor

2
Totor, xem câu trả lời của tôi. Bạn có thể sử dụng '-p' để lưu các sửa đổi. Câu trả lời rất gần với cái này thực sự.
cmcginty

1
Hoặc bạn có thể kết hợp điều này vào git checkout -p.
Léo Lam

31

Tôi tìm thấy một cách để làm điều này trong danh sách gửi thư Git:

git show <commit> -- <path> | git apply --reverse

Nguồn: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

Biến thể

Lệnh đó không thành công (không gây ra thay đổi) nếu bản vá không được áp dụng sạch, nhưng --3waythay vào đó, bạn gặp phải xung đột mà sau đó bạn có thể giải quyết bằng tay (trong trường hợp này câu trả lời của Casey có thể thực tế hơn):

git show <commit> -- <path> | git apply --reverse --3way

Bạn cũng có thể sử dụng điều này để hoàn nguyên một phần nhiều cam kết, ví dụ:

git log -S<string> --patch | git apply --reverse

để hoàn nguyên các tệp có thay đổi khớp <string>trong bất kỳ cam kết nào. Đây chính xác là những gì tôi cần trong trường hợp sử dụng của mình (một vài cam kết riêng biệt đã đưa ra các thay đổi tương tự cho các tệp khác nhau, cùng với các thay đổi các tệp khác theo những cách không liên quan mà tôi không muốn hoàn nguyên).

Nếu bạn đã diff.noprefix=truethiết lập ~/.gitconfigthì bạn cần thêm -p0vào git applylệnh, vd

git show <commit> -- <path> | git apply -p0 --reverse

Câu trả lời này tốt hơn nhiều so với câu trả lời: "tốt hơn hết, hãy truy cập và hoàn nguyên hai thay đổi trong tệp đó".
viết lại

Tôi chỉ muốn hoàn nguyên một phần của một cam kết, vì vậy tôi đã thực hiện: (1) git show ... > foo.txt (2) chỉnh sửa foo.txtđể loại bỏ các khác biệt mà tôi muốn không hoàn nguyên (3) git apply --reverse foo.txt để hoàn nguyên các khác biệt vẫn được liệt kê trong foo.txt.
cxw

Thêm --binary --full-index vào phần hiển thị git cũng có thể là một biến thể hữu ích
Laurynas Biveinis
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.