Câu hỏi Đặt lại hoặc hoàn nguyên tệp cụ thể về bản sửa đổi cụ thể bằng Git?


Tôi đã thực hiện một số thay đổi đối với tệp đã được cam kết vài lần như một phần của một nhóm tệp nhưng giờ đây bạn muốn đặt lại / hoàn nguyên các thay đổi trên tệp về phiên bản trước đó.

Tôi đã làm một git log cùng với một git diff để tìm bản sửa đổi tôi cần, nhưng chỉ không biết làm cách nào để đưa tệp trở về trạng thái trước đây của nó trong quá khứ.


3452
2017-10-18 23:34


gốc


Sau khi hoàn nguyên, đừng quên --cached khi kiểm tra git diff. liên kết - Geoffrey Hale
Tôi tìm thấy câu hỏi của bạn khi tôi googled tôi. Nhưng sau khi đọc giải pháp, tôi đã kiểm tra nhật ký của mình và phát hiện ra rằng tôi đã thực hiện các thay đổi của người phối ngẫu như một cam kết độc lập, vì vậy tôi đã thực hiện lại cho cam kết đó và mọi thứ khác vẫn như tôi muốn. Không phải là một giải pháp, chỉ là một cách khác để làm điều đó đôi khi. - sudo97


Các câu trả lời:


Giả sử băm của cam kết bạn muốn là c5f567:

git checkout c5f567 -- file1/to/restore file2/to/restore

Các git checkout trang người đàn ông cung cấp thêm thông tin.

Nếu bạn muốn hoàn nguyên về cam kết trước c5f567, thêm ~1 (làm việc với bất kỳ số nào):

git checkout c5f567~1 -- file1/to/restore file2/to/restore

Một lưu ý phụ, tôi luôn không thoải mái với lệnh này vì nó được sử dụng cho cả hai thứ bình thường (thay đổi giữa các nhánh) và những thứ bất thường, phá hoại (loại bỏ những thay đổi trong thư mục làm việc).


4672
2017-10-18 23:39



Nếu bạn nhầm lẫn trong "abbcdf" và muốn phiên bản ngay trước khi "abbcdf", bạn có thể làm git checkout "abbcdf~1" path/to/file. - shadowhand
@shadowhand: Có cách nào để đảo ngược điều đó, vì vậy đó là phiên bản ngay sau đó? - aliteralmind
@aliteralmind: Không, tiếc là ký hiệu phím tắt lịch sử Git chỉ quay ngược lại trong lịch sử. - Greg Hewgill
Nếu bạn định sử dụng tên chi nhánh cho abcde (ví dụ. develop) bạn sẽ muốn git checkout develop -- file/to/restore (lưu ý dấu gạch ngang kép) - Ohad Schneider
@aliteralmind: Trên thực tế, có, có một cách để làm điều đó: "git log --reverse -1 --ancestry-path yourgitrev..master" và sau đó sử dụng các tùy chọn thích hợp để chỉ nhận được git rev. --ancestry-path sẽ "vẽ một đường" giữa hai commit và -1 sẽ chỉ cho bạn một phiên bản, và --reverse sẽ đảm bảo mục nhập đầu tiên được phát ra là một phiên bản cũ nhất. - Chris Cogdon


Bạn có thể nhanh chóng xem lại các thay đổi được thực hiện cho một tệp bằng lệnh diff:

git diff <commit hash> <filename>

Sau đó, để hoàn nguyên một tệp cụ thể cho cam kết đó, hãy sử dụng lệnh đặt lại:

git reset <commit hash> <filename>

Bạn có thể cần phải sử dụng --hard tùy chọn nếu bạn có sửa đổi cục bộ.

Một quy trình làm việc tốt để quản lý các điểm tham chiếu là sử dụng thẻ để đánh dấu rõ ràng các điểm trong dòng thời gian của bạn. Tôi không thể hoàn toàn hiểu câu cuối cùng của bạn nhưng những gì bạn có thể muốn là phân kỳ một chi nhánh từ một điểm trước đó trong thời gian. Để thực hiện việc này, hãy sử dụng lệnh thanh toán tiện dụng:

git checkout <commit hash>
git checkout -b <new branch name>

Sau đó, bạn có thể rebase đối với đường chính của mình khi bạn đã sẵn sàng hợp nhất các thay đổi đó:

git checkout <my branch>
git rebase master
git checkout master
git merge <my branch>

508
2017-12-17 06:59



Lệnh 'git checkout <commit hash>' đã cho tôi trở lại phiên bản cũ của dự án chính xác điều này mà tôi đang tìm kiếm Cảm ơn Chris. - vidur punj
'git reset <commit hash> <filename>' không thay đổi tệp cụ thể của tôi mà tôi muốn thay đổi. Có cách nào để kiểm tra phiên bản của tệp, cụ thể và không thanh toán toàn bộ dự án không? - Danny
Để hoàn nguyên tệp git checkout <commit hash> <filename> làm việc tốt hơn tôi git reset - Motti Strom
không thể sử dụng git reset để đặt lại tệp đơn, bạn sẽ gặp lỗi fatal: Cannot do hard reset with paths - slier
Slier nói gì: bạn không thể git reset --hard <commit hash> <filename>. Điều này sẽ xảy ra lỗi với fatal: Cannot do hard reset with paths. Những gì Motti Strom nói: sử dụng git checkout <commit hash> <filename> - Hawkeye Parker


Bạn có thể sử dụng bất kỳ tham chiếu nào đến cam kết git, bao gồm cả SHA-1 nếu điều đó thuận tiện nhất. Vấn đề là lệnh này trông như thế này:

git checkout [commit-ref] -- [filename]


306
2018-04-07 21:48



Sự khác biệt giữa câu trả lời này là gì --và cái được chấp nhận không? - 2rs2ts
Trong git, một '-' trước khi danh sách tập tin nói với git rằng tất cả các đối số tiếp theo nên được hiểu là tên tập tin, không phải là tên chi nhánh hay bất cứ thứ gì khác. Đôi khi nó là một người gây hiểu biết hữu ích. - foxxtrot
Các '-' không chỉ là một quy ước git, nhưng một cái gì đó bạn tìm thấy ở những nơi khác nhau trong trên dòng lệnh * nix. rm -- -f(xóa tệp có tên -f) dường như là ví dụ kinh điển. Thêm chi tiết tại đây - Hawkeye Parker
Chỉ cần thêm vào những gì @HawkeyeParker đã nói, rm lệnh sử dụng getopt (3) để phân tích đối số của nó. getopt là lệnh để phân tích đối số lệnh. gnu.org/software/libc/manual/html_node/Getopt.html - Devy
@ Honey Vâng, đó là điều tôi muốn nói, và vâng, có lẽ không phổ biến chút nào. Tôi đã thấy ví dụ đó ở những nơi khác nhau, có thể chỉ để làm cho nó đáng nhớ: rm -f nổi tiếng là đáng sợ / nguy hiểm. Tuy nhiên, vấn đề là, trong * nix một tên tệp có thể bắt đầu với một '-', và điều này sẽ gây nhầm lẫn các thông dịch viên dòng lệnh khác nhau, khi họ nhìn thấy một '-', mong đợi một tùy chọn lệnh để làm theo. Nó có thể là bất kỳ tập tin nào bắt đầu bằng '-'; ví dụ: "-mySpecialFile". - Hawkeye Parker


git checkout -- foo

Điều đó sẽ đặt lại foo đến HEAD. Bạn cũng có thể:

git checkout HEAD^ foo

cho một lần sửa đổi, v.v.


244
2017-08-29 20:56



Tôi khuyên bạn nên sử dụng cú pháp git checkout -- foo để tránh bất kỳ sai lầm nào nếu foo là bất cứ điều gì đặc biệt (như một thư mục hoặc một tệp gọi là -f). Với git, nếu bạn không chắc chắn, luôn luôn tiền tố tất cả các tệp và thư mục với đối số đặc biệt --. - Mikko Rantalainen
Một lưu ý bổ sung cho nhận xét của Mikko: -- không phải là lệnh git và không đặc biệt với git. Nó là một bash built-in để biểu thị sự kết thúc của các tùy chọn lệnh. Bạn có thể sử dụng nó với nhiều lệnh bash khác. - matthaeus
@matthaeus nó cũng không cụ thể để bash cũng không phải là một tính năng vỏ nào cả. Đó là một quy ước được thực hiện trong nhiều lệnh khác nhau (và được hỗ trợ bởi getopt). - Greg Hewgill


Và để trở lại phiên bản cam kết cuối cùng, thường xuyên nhất cần thiết, bạn có thể sử dụng lệnh đơn giản này.

git checkout HEAD file/to/restore

106
2018-01-14 06:15



sự khác biệt giữa điều này (git checkout HEAD file / to / restore) và git reset --hard file / to / restore ??? - Motti Shneor
1) dễ nhớ hơn cách tổng quát 2) không cần phải nhấn Enter trước khi nhập tên tập tin - Roman Susi


Tôi vừa gặp vấn đề và tôi đã tìm thấy câu trả lời này dễ hiểu nhất (commit-ref là giá trị SHA của thay đổi trong nhật ký bạn muốn quay lại):

git checkout [commit-ref] [filename]

Điều này sẽ đặt phiên bản cũ trong thư mục làm việc của bạn và từ đó bạn có thể cam kết nếu bạn muốn.


100
2018-05-27 17:52





Nếu bạn biết số lượng cam kết bạn cần quay lại, bạn có thể sử dụng:

git checkout master~5 image.png

Điều này giả định rằng bạn đang ở trên master chi nhánh và phiên bản bạn muốn là 5 cam kết trở lại.


85
2018-04-07 14:03





Tôi nghĩ rằng tôi đã tìm thấy nó .... từ http://www-cs-students.stanford.edu/~blynn/gitmagic/ch02.html

Đôi khi bạn chỉ muốn quay lại và quên đi mọi thay đổi trong một thời điểm nhất định bởi vì tất cả đều sai.

Bắt đầu với:

$ git log

trong đó cho bạn thấy một danh sách các cam kết gần đây và băm SHA1 của chúng.

Tiếp theo, gõ:

$ git reset --hard SHA1_HASH

để khôi phục trạng thái về một cam kết đã cho và xóa tất cả các cam kết mới hơn khỏi bản ghi vĩnh viễn.


75
2017-12-17 06:53



Git không bao giờ loại bỏ bất cứ điều gì. Các cam kết cũ của bạn vẫn ở đó nhưng trừ khi có một nhánh chi nhánh chỉ vào chúng, chúng không thể truy cập được nữa. git reflog sẽ vẫn hiển thị chúng cho đến khi bạn dọn sạch kho lưu trữ của mình bằng git-gc. - Bombe
@ Bombe: Cảm ơn bạn đã cung cấp thông tin. Tôi đã kiểm tra một phiên bản cũ của một tập tin. Sau khi đọc nhận xét của bạn, tôi đã có thể sử dụng "gitref" để tra cứu hàm băm SHA1 một phần và sử dụng "checkout" để quay lại phiên bản mới nhất. Những người dùng git khác có thể thấy thông tin này hữu ích. - Winston C. Yang
có thể theo sau bởi một git push --force - bshirley
Nếu bạn có những thay đổi không được cam kết, bạn sẽ thua chúng nếu làm git reset --hard - Boklucius
@ Bombe - "Git không bao giờ loại bỏ bất cứ điều gì. Các cam kết cũ của bạn vẫn ở đó nhưng trừ khi có một mẹo chi nhánh chỉ vào họ, họ không thể truy cập được nữa." - nhưng cam kết như thế này được cắt tỉa sau một số thời gian đặt, vì vậy "Git không bao giờ loại bỏ bất cứ điều gì" là không đúng sự thật. - Bulwersator


Điều này làm việc cho tôi:

git checkout <commit hash> file

Sau đó, cam kết thay đổi:

git commit -a

59
2017-08-25 22:12





Bạn phải cẩn thận khi bạn nói "rollback". Nếu bạn đã từng có một phiên bản của một tập tin trong cam kết $ A, và sau đó thực hiện hai thay đổi trong hai cam kết riêng biệt $ B và $ C (vì vậy những gì bạn đang thấy là lần lặp thứ ba của tệp), và nếu bạn nói " Tôi muốn quay trở lại cái đầu tiên ", bạn có thực sự có ý đó không?

Nếu bạn muốn loại bỏ các thay đổi cả lần lặp thứ hai và thứ ba, nó rất đơn giản:

$ git checkout $A file

và sau đó bạn cam kết kết quả. Lệnh hỏi "Tôi muốn kiểm tra các tập tin từ tiểu bang ghi lại bởi cam kết $ A".

Mặt khác, ý của bạn là loại bỏ sự thay đổi lần lặp thứ hai (tức là $ b) được đưa vào, trong khi vẫn giữ nguyên $ C đã làm cho tệp, bạn sẽ muốn hoàn nguyên $ B

$ git revert $B

Lưu ý rằng bất kỳ ai tạo cam kết $ B có thể không có kỷ luật và có thể đã cam kết thay đổi hoàn toàn không có liên quan trong cùng một cam kết, và việc hoàn nguyên này có thể chạm vào các tệp khác tập tin bạn thấy những thay đổi vi phạm, vì vậy bạn có thể muốn kiểm tra kết quả một cách cẩn thận sau khi làm như vậy.


53
2018-01-11 08:13



Tôi đã làm điều này, nhưng sau đó một "tập tin đăng nhập git" sẽ nói rằng tôi đã ở trên cam kết ban đầu, HEAD. Dường như "git checkout" đã thất bại. Tuy nhiên, trạng thái git cho thấy tệp đã được thay đổi và tệp "git diff --staged" sẽ hiển thị các thay đổi thực tế. Ngoài ra, "trạng thái git" cũng cho thấy tệp đã thay đổi. Vì vậy, không sử dụng "git log" ở đây để theo dõi các tập tin đã thay đổi. - Frederick Ollinger


Ngạc nhiên thay, 'git checkout foo' sẽ không hoạt động nếu bản sao làm việc nằm trong thư mục có tên foo; tuy nhiên, cả 'git checkout HEAD foo' và 'git checkout ./foo' sẽ:

$ pwd
/Users/aaron/Documents/work/foo
$ git checkout foo
D   foo
Already on "foo"
$ git checkout ./foo
$ git checkout HEAD foo

35
2017-08-29 21:26



hoặc là git checkout -- foo - knittl