Tìm khi tệp bị xóa trong Git


1035

Tôi có một kho Git với n cam kết.

Tôi có một tập tin mà tôi cần, và nó đã từng nằm trong kho lưu trữ, và tôi đột nhiên tìm kiếm và nghĩ "Ồ! Tập tin đó sẽ đi đâu?"

Có (một) lệnh Git nào sẽ cho tôi biết rằng "tập tin really_needed.txt đã bị xóa tại commit n-13" không?

Nói cách khác, không cần nhìn vào mọi cam kết cá nhân và biết rằng repo Git của tôi có mọi thay đổi của mỗi tệp, tôi có thể nhanh chóng tìm thấy cam kết cuối cùng mà ĐÃ có tệp đó không, vì vậy tôi có thể lấy lại được không?



2
Liên kết được chia sẻ bởi Pedro đã có câu trả lời cho câu hỏi của tôi: làm thế nào để tìm một tệp bị xóa khi bạn không nhớ đường dẫn.
Gordon Bean

Câu trả lời:


1127

git log --full-history -- [file path] hiển thị các thay đổi của tệp, hoạt động ngay cả khi tệp đã bị xóa.

Thí dụ:

git log --full-history  -- myfile

Nếu bạn chỉ muốn xem cam kết cuối cùng, đã xóa một tệp, hãy sử dụng -1, ví dụ: git log --full-history -1 -- [file path]

Xem cam kết nào đã xóa một tập tin


16
Có thể tìm kiếm các mẫu? Tôi quên toàn bộ tên của tệp = (có thể lấy nhật ký của tất cả các lần xóa?
wutzebaer

6
tìm thấy nó ở đây: stackoverflow.com/questions/6017987/
Ấn

6
Xin lưu ý, nếu bạn đang sử dụng PowerShell, các dấu gạch nối phải được thoát: git log '-' [đường dẫn tệp]. Hy vọng rằng điều này có thể cùng một số người khác nghiến răng.
A. Wilson

68
Tôi đã có thể tìm kiếm bằng cách git log -- */<<filename>>.<<file extension>>không biết toàn bộ đường dẫn tập tin.
Tom Howard

2
Dấu ngoặc vuông @merose có ở đó như một trình giữ chỗ cho đường dẫn tệp thực.
Emile Bergeron

229

Câu trả lời ngắn:

git log --full-history -- your_file

sẽ hiển thị cho bạn tất cả các cam kết trong lịch sử của bạn, bao gồm các cam kết hợp nhất, đã được chạm vào your_file. Cái cuối cùng (trên cùng) là cái đã xóa tệp.

Một số giải thích:

Các --full-historylá cờ ở đây là rất quan trọng. Không có nó, Git thực hiện "đơn giản hóa lịch sử" khi bạn yêu cầu nó cho nhật ký của một tệp. Các tài liệu rất nhẹ về các chi tiết về chính xác cách thức hoạt động của nó và tôi thiếu sự can đảm và can đảm cần phải cố gắng tìm ra nó từ mã nguồn, nhưng các tài liệu git-log có nhiều điều để nói:

Chế độ mặc định

Đơn giản hóa lịch sử đến lịch sử đơn giản nhất giải thích trạng thái cuối cùng của cây. Đơn giản nhất vì nó cắt tỉa một số nhánh bên nếu kết quả cuối cùng là giống nhau (nghĩa là hợp nhất các nhánh có cùng nội dung)

Điều này rõ ràng liên quan đến khi tệp có lịch sử chúng ta muốn bị xóa , vì lịch sử đơn giản nhất giải thích trạng thái cuối cùng của tệp bị xóa là không có lịch sử . Có rủi ro mà git logkhông có --full-historyđơn giản sẽ tuyên bố rằng tập tin không bao giờ được tạo ra? Không may là đúng vậy. Đây là một minh chứng:

mark@lunchbox:~/example$ git init
Initialised empty Git repository in /home/mark/example/.git/
mark@lunchbox:~/example$ touch foo && git add foo && git commit -m "Added foo"
[master (root-commit) ddff7a7] Added foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 foo
mark@lunchbox:~/example$ git checkout -b newbranch
Switched to a new branch 'newbranch'
mark@lunchbox:~/example$ touch bar && git add bar && git commit -m "Added bar"
[newbranch 7f9299a] Added bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git rm foo && git commit -m "Deleted foo"
rm 'foo'
[master 7740344] Deleted foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 foo
mark@lunchbox:~/example$ git checkout newbranch
Switched to branch 'newbranch'
mark@lunchbox:~/example$ git rm bar && git commit -m "Deleted bar"
rm 'bar'
[newbranch 873ed35] Deleted bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git merge newbranch
Already up-to-date!
Merge made by the 'recursive' strategy.
mark@lunchbox:~/example$ git log -- foo
commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log -- bar
mark@lunchbox:~/example$ git log --full-history -- foo
commit 2463e56a21e8ee529a59b63f2c6fcc9914a2b37c
Merge: 7740344 873ed35
Author: Mark Amery 
Date:   Tue Jan 12 22:51:36 2016 +0000

    Merge branch 'newbranch'

commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log --full-history -- bar
commit 873ed352c5e0f296b26d1582b3b0b2d99e40d37c
Author: Mark Amery 
Date:   Tue Jan 12 22:51:29 2016 +0000

    Deleted bar

commit 7f9299a80cc9114bf9f415e1e9a849f5d02f94ec
Author: Mark Amery 
Date:   Tue Jan 12 22:50:38 2016 +0000

    Added bar

Lưu ý làm thế nào git log -- bartrong bãi chứa thiết bị đầu cuối ở trên dẫn đến không có đầu ra theo nghĩa đen; Git đang "đơn giản hóa" lịch sử thành một tiểu thuyết barkhông bao giờ tồn tại. git log --full-history -- barmặt khác, cung cấp cho chúng tôi cam kết đã tạo barvà cam kết đã xóa nó.

Để rõ ràng: vấn đề này không chỉ là lý thuyết. Tôi chỉ nhìn vào các tài liệu và phát hiện ra --full-historycờ vì git log -- some_filethất bại đối với tôi trong một kho lưu trữ thực sự nơi tôi đang cố gắng theo dõi một tệp đã bị xóa. Lịch sử đơn giản hóa đôi khi có thể hữu ích khi bạn đang cố gắng tìm hiểu làm thế nào một hiện tồn tại từ tập tin đến được ở trạng thái hiện tại của nó, nhưng khi cố gắng để theo dõi xuống một tập tin xóa nó nhiều khả năng vít bạn hơn bằng cách ẩn các cam kết mà bạn quan tâm . Luôn luôn sử dụng --full-historycờ cho trường hợp sử dụng này.


4
Lưu ý rằng điều này chỉ tìm kiếm lịch sử liên quan đến nhánh hiện tại (không phải 'toàn bộ lịch sử repo') ... tức là nếu tệp chưa bị xóa trong nhánh hiện tại nhưng đã ở nhánh khác, điều này sẽ không tìm thấy cam kết xóa. Bạn phải ở bất kỳ chi nhánh nào mà tập tin đã bị xóa . Có thể là rõ ràng khi nghĩ về nó, nhưng nó đã bắt gặp tôi lúc đầu.
Anentropic

1
Câu trả lời này hoạt động. Nhưng từ git logđầu ra, rõ ràng là lần cam kết cuối cùng đã xóa tệp. Tôi cũng đã thử git log --name-status --full-history -- file_namegit log -p --stat --full-history -- file_name, nhưng không chỉ ra rõ ràng rằng tệp đã bị xóa trong cam kết mới nhất. Điều này có vẻ như một lỗi.
Martin_W

@Martin_ATS mkdir somedir && cd somedir && git init && touch foo && git add foo && git commit -m "Added foo" && git checkout -b newbranch && touch bar && git add bar && git commit -m "Added bar" && git checkout master && git rm foo && git commit -m "Deleted foo" && git checkout newbranch && git rm bar && git commit -m "Deleted bar" && git checkout master && git merge newbranch && git log --name-status --full-history -- barbao gồm D barA barcho tôi trong đầu ra nhật ký với Git 2.12.2. Bạn không thấy những dòng trong đầu ra? Bạn có phiên bản nào?
Đánh dấu Amery

git version 2.15.1Có, chuỗi lệnh của bạn không báo cáo D barA bar. Có lẽ vấn đề của tôi là đặc biệt đối với lịch sử tập tin của tôi. Tôi đã theo dõi lịch sử của một .htaccesstập tin đã bị xóa và xóa. Cuối cùng tôi đã tìm ra và thêm tập tin trở lại. Khi tôi đưa --name-statusvào git loglệnh, tôi thấy hai A .htaccessmục (vì tôi đã thêm nó trở lại trong cam kết mới nhất) nhưng không D .htaccess. Vì vậy, dường như trong một số trường hợp, mặc dù một tệp đã bị xóa khỏi kho lưu trữ, git logsẽ không hiển thị một D file_namemục rõ ràng .
Martin_W

@Martin_ATS Tò mò. Tôi tự hỏi nếu có lẽ .htaccessđã được thêm vào một cam kết X nhưng sau đó không được bao gồm trong cam kết hợp nhất đã đưa X lên chủ? Đó là điều duy nhất tôi có thể nghĩ rằng tôi có thể tranh luận nên trông giống như một tập tin đã được thêm vào và không bao giờ bị xóa và vẫn không có mặt. Sẽ rất thú vị khi thử và tìm ra một MCVE, sau đó tìm hiểu xem đó có phải là lỗi Git hay không, và nếu không, liệu có thể điều chỉnh câu trả lời của tôi để xử lý trường hợp của bạn hay không.
Đánh dấu Amery

84

Nhật ký Git nhưng bạn cần tiền tố đường dẫn với --

Ví dụ:

dan-mac:test dani$ git log file1.txt
fatal: ambiguous argument 'file1.txt': unknown revision or path not in the working tree.

dan-mac:test dani$ git log -- file1.txt
 commit 0f7c4e1c36e0b39225d10b26f3dea40ad128b976
 Author: Daniel Palacio <danpal@gmail.com>
 Date:   Tue Jul 26 23:32:20 2011 -0500

 foo

31

Tôi vừa mới thêm một giải pháp ở đây (có cách nào trong git để liệt kê tất cả các tệp đã xóa trong kho lưu trữ không?) Để tìm các cam kết của các tệp đã xóa bằng cách sử dụng biểu thức chính quy:

git log --diff-filter=D --summary | sed -n '/^commit/h;/\/some_dir\//{G;s/\ncommit \(.*\)/ \1/gp}'

Điều này trả về mọi thứ đã bị xóa trong một thư mục có tên some_dir(xếp tầng). Bất kỳ sed regrec ở đó \/some_dir\/sẽ làm ở đâu.

OSX (cảm ơn @triplee và @keif)

git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }

1
Đẹp. Một số điểm không phù hợp với bash trong OS X:sed: 1: "/^commit/h;/\/some_dir\ ...": bad flag in substitute command: '}'
Brent Faust

@BrentFoust Thật đáng tiếc tôi không thể kiểm tra rằng ... hãy thử thêm một khoảng trắng ở cuối (sau khi niềng răng nhưng trước trích dẫn duy nhất), trang người đàn ông trực tuyến không rõ về điều đó ...
estani

Đề nghị tốt đẹp. Nhưng thêm một khoảng trắng trước trích dẫn không giúp được gì. Không có một không gian trước khi kết thúc cú đúp.
Brent Faust

1
BSD / OSX sedrõ ràng không phải lúc nào cũng tốt với dấu chấm phẩy như dấu phân cách lệnh. Hãy thử thay đổi chúng thành dòng mới hoặc chuyển sangsed -n -e '/^commit/h' -e '\:/some_dir/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
tripleee

1
Tôi đã thử nghiệm nó và git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }làm việc cho tôi trên OSX.
keif

21

Bạn có thể tìm thấy cam kết cuối cùng đã xóa tệp như sau:

git rev-list -n 1 HEAD -- [file_path]

Thông tin chi tiết có sẵn ở đây


11
Giải pháp nâng cấp chính không hiệu quả với tôi, nhưng giải pháp này đã làm được.
Nick Heiner

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.