Làm thế nào để tìm một tập tin bị xóa trong lịch sử cam kết dự án?


1275

Ngày xửa ngày xưa, có một tập tin trong dự án của tôi mà bây giờ tôi muốn có thể lấy.

Vấn đề là: Tôi không biết khi nào tôi đã xóa nó và nó đã đi trên con đường nào.

Làm cách nào để xác định vị trí của tệp này khi nó tồn tại?


Câu hỏi tương tự ở đây: stackoverflow.com/questions/7093602/ từ
eckes

3
Bản sao có thể có của Tìm khi tệp bị xóa trong Git
Dan Dascalescu

13
Các câu trả lời ở đây hữu ích với tôi hơn các câu trả lời trong các bản sao .
Felipe Alvarez

5
đồng ý ... bất kể các bản sao ... họ đã không tìm thấy trong tìm kiếm của Google .... điều này đã làm ... tôi hy vọng chúng ta sẽ ngừng lãng phí thời gian để theo đuổi các bản sao ... chỉ có thời gian và thuật toán của google sẽ Cho biết câu hỏi nào là tốt nhất.
Tim Boland

Câu trả lời:


1601

Nếu bạn không biết đường dẫn chính xác bạn có thể sử dụng

git log --all --full-history -- "**/thefile.*"

Nếu bạn biết đường dẫn của tập tin, bạn có thể làm điều này:

git log --all --full-history -- <path-to-file>

Điều này sẽ hiển thị một danh sách các cam kết trong tất cả các chi nhánh đã chạm vào tệp đó. Sau đó, bạn có thể tìm phiên bản của tệp bạn muốn và hiển thị nó với ...

git show <SHA> -- <path-to-file>

Hoặc khôi phục nó vào bản sao làm việc của bạn với:

git checkout <SHA>^ -- <path-to-file>

Lưu ý ký hiệu dấu mũ ( ^), được kiểm tra trước khi xác định, vì tại thời điểm <SHA>cam kết tệp bị xóa, chúng ta cần xem xét cam kết trước đó để lấy nội dung của tệp đã bị xóa


2
Hãy thử sử dụng một đường dẫn tương đối thay vì một đường dẫn tuyệt đối (nếu bạn chưa có).
Amber

63
Nếu bạn không biết đường dẫn chính xác thì sao? Tất cả những gì bạn biết là tên tệp?
linh mục

17
@PedroMorteRolo git log -- <path>sẽ không có đầu ra khi bạn ở trên một nhánh trong đó tệp không bao giờ tồn tại. Bạn nên luôn luôn sử dụng git log --all -- <path>, để đảm bảo bạn không bỏ lỡ những thay đổi xảy ra trên các chi nhánh khác. Lệnh git log -- <path>có thể rất nguy hiểm nếu bạn có nhiều hơn một nhánh và có xu hướng quên các đường dẫn và nhánh (như tôi) và nó cũng nguy hiểm nếu bạn làm việc với các nhà phát triển khác.
hobs

4
@Amber, hãy xem xét thêm --all(cảm ơn Philip ) vào git logcâu trả lời của bạn để mọi người không bỏ lỡ các thay đổi và tệp trên các nhánh khác. Nó sẽ cứu những người hay quên như tôi rất nhiều đau buồn.
hobs

3
Như đã nêu trong câu trả lời bên dưới, việc khôi phục tệp phải là git checkout <SHA>^ -- <path-to-file>(lưu ý ký hiệu ^), vì tại thời điểm <SHA> cam kết tệp bị xóa, chúng ta cần xem xét cam kết trước đó để lấy nội dung của tệp đã bị xóa
kipelovets

393

Lấy danh sách các tệp đã xóa và sao chép toàn bộ đường dẫn của tệp đã xóa

git log --diff-filter=D --summary | grep delete

Thực hiện lệnh tiếp theo để tìm id xác nhận của cam kết đó và sao chép id xác nhận

git log --all -- FILEPATH

Hiển thị khác biệt của tập tin bị xóa

git show COMMIT_ID -- FILE_PATH

Hãy nhớ rằng, bạn có thể ghi đầu ra vào một tệp bằng cách sử dụng >như

git show COMMIT_ID -- FILE_PATH > deleted.diff

1
Mặc dù tôi đã tìm thấy đường dẫn với sự trợ giúp của bước đầu tiên, bước thứ hai ném lỗi này : unknown revision or path not in the working tree.
jvannistelrooy

6
Để xem các bảng băm cam kết cùng với các thao tác xóa, bạn có thể thực hiệngit log --diff-filter=D --summary | grep -E 'delete|^commit\s+\S+'
Chris Middleton

1
Bước 2 trả về không có gì. Bất kỳ ý tưởng tại sao nó có thể xảy ra? Tên tệp của tôi là chính xác.
Denis Kniazhev 24/07/2015

2
Để tìm kết hợp cả ba thành một hàm, hãy thêm hàm này vào .bashrc hoặc .zshrc: git-grep-latest(){ result_path=$(git log --diff-filter=D --summary | grep $1 | head -1 | awk '{print $4;}'); latest_commit=$(git log --all -- $result_path | head -1 | awk '{print $2;}'); git show $latest_commit -- $result_path; }và bây giờ bạn có thể thực hiện:git-grep-latest some_text
Randomor

1
@TylerJones bạn có thể cung cấp mọi thứ cho mọi thứ bằng linux bằng cách sử dụng ống dẫn - google linux pipes.. bạn sẽ thích điều đó.
John Hunt

37

Không thể chỉnh sửa phản hồi được chấp nhận để thêm nó làm câu trả lời ở đây,

để khôi phục tệp trong git, hãy sử dụng thông tin sau (lưu ý dấu '^' ngay sau SHA)

git checkout <SHA>^ -- /path/to/file

Tôi không hiểu tại sao bạn muốn ^. Tệp nằm trong cam kết với SHA đó ... tại sao bạn muốn quay lại cam kết khác từ đó?
Tony K.

19
Đó là trong cam kết với sha đó là "đã xóa" có nghĩa là nó vẫn không tồn tại. Bạn phải đi đến cam kết trước đó để thực sự lấy lại.
tandrewnichols

6
@tandrewnichols, điều đó chỉ có nghĩa là bạn đang sử dụng sai SHA - bạn muốn cam kết cho phiên bản của tệp bạn muốn ... có thể không phải là phiên bản mà tệp bị xóa.
Amber

6
@Amber và cam kết mà bạn muốn có khả năng là lần gần đây nhất trước khi nó bị xóa, do đó câu trả lời này.
Người giữ Sam

1
@AlexR: <SHA>~1nên hoạt động như nhau mà không cần phải bọc nó bằng dấu ngoặc kép.
CodeManX

37

Giả sử bạn muốn khôi phục một tệp được gọi MyFile, nhưng không chắc chắn về đường dẫn của nó (hoặc phần mở rộng của nó, cho vấn đề đó):

Sơ bộ: Tránh nhầm lẫn bằng cách bước đến gốc git

Một dự án không cần thiết có thể có nhiều thư mục có tên tương tự hoặc giống hệt nhau.

> cd <project-root>
  1. Tìm đường dẫn đầy đủ

    nhật ký git --diff-filter = D --summary | xóa grep | grep MyFile

    delete mode 100644 full/path/to/MyFile.js

full/path/to/MyFile.js là đường dẫn và tập tin bạn đang tìm kiếm.

  1. Xác định tất cả các cam kết ảnh hưởng đến tệp đó

    git log --oneline --follow - full / path / to / MyFile.js

    bd8374c Some helpful commit message

    ba8d20e Another prior commit message affecting that file

    cfea812 The first message for a commit in which that file appeared.

  2. Kiểm tra tập tin

Nếu bạn chọn cam kết được liệt kê đầu tiên (theo trình tự thời gian cuối cùng, ở đây bd8374c), tệp sẽ không được tìm thấy, vì nó đã bị xóa trong cam kết đó.

> git checkout bd8374c -- full/path/to/MyFile.js

`error: pathspec 'full/path/to/MyFile.js' did not match any file(s) known to git.`

Chỉ cần chọn cam kết trước (nối thêm dấu mũ):

> git checkout bd8374c^ -- full/path/to/MyFile.js

3
Điều này rõ ràng hơn nhiều so với câu trả lời được chấp nhận
Pouyan Khodabakhsh

đối với bảng điều khiển windows (cmd), hãy sử dụng find thay vì grep ở bước 2: git log --diff-filter=D --summary | find "delete" | find "MyFile"Và bước 3 , lưu ý các trích dẫn xung quanh hàm băm:git checkout "bd8374c^" -- full/path/to/MyFile.js
user5542121

30

@Amber đã trả lời đúng! Chỉ cần thêm một lần nữa, nếu bạn không biết đường dẫn chính xác của tệp, bạn có thể sử dụng ký tự đại diện! Điều này làm việc cho tôi.

git log --all -- **/thefile.*

4
@PedroMorteRolo Hmm. Tôi không biết tôi cảm thấy thế nào về việc sao chép một câu trả lời hiện có vào câu trả lời hàng đầu: / Câu trả lời này cũng hữu ích; một upvote có thể là đủ?
Clément

1
Điều này không tìm thấy tệp nếu nó nằm trong thư mục gốc của dự án (được thử nghiệm trong Cygwin).
wortwart

19

Dưới đây là một lệnh đơn giản, trong đó một người dùng dev hoặc git có thể chuyển tên tệp đã bị xóa khỏi thư mục gốc của kho lưu trữ và lấy lịch sử:

git log --diff-filter=D --summary | grep filename | awk '{print $4; exit}' | xargs git log --all -- 

Nếu ai, có thể cải thiện lệnh, xin vui lòng làm.


1
Thật sự cảm ơn! Có vẻ như tập tin của tôi chưa bao giờ tồn tại, nhưng đó là một vấn đề

đảm bảo bạn chạy tệp này từ thư mục gốc của kho lưu trữ nếu tệp của bạn dường như bị 'mất tích'
samaspin

Cảm ơn @samaspin đã cập nhật câu trả lời.
Jason

18

Hãy thử sử dụng một trong những người xem, chẳng hạn như gitkđể bạn có thể duyệt qua lịch sử để tìm tệp được nhớ một nửa. (sử dụng gitk --allnếu cần cho tất cả các chi nhánh)


4
--allTùy chọn đó rất quan trọng cho cả câu trả lời của bạn và câu trả lời được chấp nhận.
hobs

3
Duyệt qua lịch sử sẽ mất một lượng thời gian đặc biệt cho hầu hết các dự án.
mikemaccana

5

Tóm lược:

  1. Bước 1

Bạn tìm kiếm đường dẫn tập tin đầy đủ của bạn trong lịch sử của các tập tin bị xóa git log --diff-filter=D --summary | grep filename

  1. Bước 2

Bạn khôi phục tệp của bạn từ cam kết trước khi nó bị xóa

restore () {
  filepath="$@"
  last_commit=$(git log --all --full-history -- $filepath | grep commit | head -1 | awk '{print $2; exit}')
  echo "Restoring file from commit before $last_commit"
  git checkout $last_commit^ -- $filepath
}

restore my/file_path

0

Đây là giải pháp của tôi:

git log --all --full-history --oneline -- <RELATIVE_FILE_PATH>
git checkout <COMMIT_SHA>^ -- <RELATIVE_FILE_PATH>
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.