Cari kapan file dihapus di Git

1035

Saya memiliki repositori Git dengan n commit.

Saya punya file yang saya butuhkan, dan dulu di repositori, dan tiba-tiba saya mencari dan berpikir, "Oh! Kemana perginya file itu?"

Apakah ada (seri) perintah Git yang akan memberi tahu saya bahwa "file really_needed.txt telah dihapus di commit n-13"?

Dengan kata lain, tanpa melihat komit setiap individu, dan mengetahui bahwa repo Git saya memiliki setiap perubahan setiap file, dapatkah saya dengan cepat menemukan komit terakhir yang MEMILIKI file itu, sehingga saya bisa mendapatkannya kembali?

JohnMetta
sumber
5
Kemungkinan duplikat dari Bagaimana menemukan file yang dihapus dalam riwayat komit?
Pedro Rolo
2
Tautan yang dibagikan oleh Pedro memiliki jawaban untuk pertanyaan saya: bagaimana menemukan file yang dihapus ketika Anda tidak ingat jalurnya.
Gordon Bean

Jawaban:

1127

git log --full-history -- [file path] menunjukkan perubahan file, bekerja bahkan jika file itu dihapus.

Contoh:

git log --full-history  -- myfile

Jika Anda ingin melihat hanya komit terakhir, yang menghapus file gunakan -1 sebagai tambahan, misalnya, git log --full-history -1 -- [file path]

Lihat Komit mana yang menghapus file

vogella
sumber
16
apakah mungkin mencari pola? Saya lupa seluruh nama file = (mungkin mungkin untuk mendapatkan log dari semua penghapusan?
wutzebaer
6
menemukannya di sini: stackoverflow.com/questions/6017987/…
wutzebaer
6
Harap dicatat, jika Anda menggunakan PowerShell, tanda hubung harus diloloskan: git log '-' [path file]. Semoga ini bisa menyamai gigitan orang lain.
A. Wilson
68
Saya dapat mencari menggunakan git log -- */<<filename>>.<<file extension>>tidak mengetahui seluruh jalur file.
Tom Howard
2
@MERose tanda kurung siku ada sebagai pengganti untuk path file nyata.
Emile Bergeron
229

Jawaban singkat:

git log --full-history -- your_file

akan menunjukkan semua komit dalam riwayat repo Anda, termasuk gabungan komit, yang tersentuh your_file. Yang terakhir (atas) adalah yang menghapus file.

Beberapa penjelasan:

The --full-historybendera di sini adalah penting. Tanpa itu, Git melakukan "penyederhanaan riwayat" ketika Anda meminta log file. Dokumen ringan tentang detail cara kerjanya dan saya tidak memiliki grit dan keberanian yang diperlukan untuk mencoba mencari tahu dari kode sumber, tetapi dokumen git-log memiliki banyak hal untuk dikatakan:

Mode standar

Sederhanakan sejarah ke sejarah paling sederhana yang menjelaskan kondisi akhir pohon. Paling sederhana karena memangkas beberapa cabang samping jika hasil akhirnya sama (yaitu menggabungkan cabang dengan konten yang sama)

Ini jelas memprihatinkan ketika file yang riwayatnya kita inginkan dihapus , karena riwayat paling sederhana yang menjelaskan status akhir dari file yang dihapus bukanlah riwayat . Apakah ada risiko bahwa git logtanpa --full-historyakan dengan mudah mengklaim bahwa file itu tidak pernah dibuat? Sayangnya ya. Ini sebuah demonstrasi:

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

Perhatikan bagaimana git log -- barpembuangan terminal di atas menghasilkan benar-benar tidak ada output; Git "menyederhanakan" sejarah menjadi sebuah fiksi di mana bartidak pernah ada. git log --full-history -- bar, di sisi lain, memberi kita komit yang dibuat bardan komit yang menghapusnya.

Agar lebih jelas: masalah ini bukan hanya teoretis. Saya hanya melihat ke dokumen dan menemukan --full-historybendera karena git log -- some_filegagal bagi saya di repositori nyata di mana saya mencoba untuk melacak file yang dihapus. Penyederhanaan riwayat kadang-kadang bisa membantu ketika Anda mencoba memahami bagaimana file yang saat ini ada dalam keadaan saat ini, tetapi ketika mencoba melacak penghapusan file, itu lebih cenderung untuk mengacaukan Anda dengan menyembunyikan komit yang Anda pedulikan. . Selalu gunakan --full-historybendera untuk use case ini.

Mark Amery
sumber
4
Perhatikan bahwa ini hanya mencari riwayat yang relevan dengan cabang saat ini (bukan 'seluruh riwayat repo') ... yaitu jika file belum dihapus di cabang saat ini tetapi telah di cabang lain, ini tidak akan menemukan komit penghapusan. Anda harus berada di cabang mana pun di mana file telah dihapus . Mungkin sudah jelas ketika memikirkannya, tapi itu membuat saya tersadar pada awalnya.
Anentropic
1
Jawaban ini berhasil. Tetapi dari git logoutput itu sendiri, sama sekali tidak jelas bahwa komit terakhir telah menghapus file. Saya juga mencoba git log --name-status --full-history -- file_namedan git log -p --stat --full-history -- file_name, tetapi keduanya tidak secara eksplisit menunjukkan bahwa file itu dihapus di komit terbaru. Ini seperti bug.
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 -- bartermasuk D bardan A barbagi saya dalam keluaran log dengan Git 2.12.2. Apakah Anda tidak melihat garis-garis di output? Versi apa yang kau miliki?
Mark Amery
git version 2.15.1Ya, urutan perintah Anda melaporkan D bardan A bar. Mungkin masalah saya khusus untuk riwayat file saya. Saya sedang menelusuri sejarah .htaccessfile yang gitignor dan dihapus. Saya akhirnya menemukan itu dan menambahkan file kembali. Ketika saya memasukkan --name-statusdalam git logperintah, saya melihat dua A .htaccessentri (karena saya menambahkannya kembali di komit terbaru) tetapi tidak D .htaccess. Jadi sepertinya dalam beberapa kasus, meskipun file telah dihapus dari repositori, git logtidak akan menampilkan D file_nameentri eksplisit .
Martin_W
@Martin_ATS Ingin tahu. Saya ingin tahu apakah mungkin .htaccessditambahkan dalam komit X tapi kemudian tidak termasuk dalam komit gabungan yang membawa X ke master? Itulah satu-satunya hal yang dapat saya pikirkan bahwa saya mungkin bisa berdebat seharusnya terlihat seperti file yang telah ditambahkan dan tidak pernah dihapus tetapi masih tidak ada. Akan menarik untuk mencoba dan mencari MCVE, lalu mencari tahu apakah itu bug Git, dan jika tidak, apakah mungkin untuk mengubah jawaban saya untuk menangani kasus Anda.
Mark Amery
84

Git log tetapi Anda harus awalan path dengan --

Misalnya:

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 <[email protected]>
 Date:   Tue Jul 26 23:32:20 2011 -0500

 foo
daniel
sumber
31

Saya baru saja menambahkan solusi di sini (adakah cara di git untuk membuat daftar semua file yang dihapus di repositori?) Untuk menemukan commit dari file yang dihapus dengan menggunakan regexp:

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

Ini mengembalikan semua yang dihapus dalam direktori bernama some_dir(cascading). Sed sed regexp ada di mana \/some_dir\/akan dilakukan.

OSX (terima kasih kepada @triplee dan @keif)

git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
estani
sumber
1
Bagus. Beberapa ketidakcocokan di bawah bash di OS X:sed: 1: "/^commit/h;/\/some_dir\ ...": bad flag in substitute command: '}'
Brent Faust
@ BrentFoust Sayang sekali aku tidak bisa menguji itu ... coba tambahkan spasi di akhir (setelah kawat gigi tapi sebelum kutipan tunggal), halaman manual online tidak jelas tentang itu ...
estani
Saran yang bagus. Tetapi menambahkan spasi sebelum kutipan tunggal tidak membantu. Juga tidak ada ruang sebelum penjepit penutupan.
Brent Faust
1
BSD / OSX sedtampaknya tidak selalu baik dengan titik koma sebagai pemisah perintah. Coba ubah menjadi baris baru, atau alihkan kesed -n -e '/^commit/h' -e '\:/some_dir/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
tripleee
1
Saya mengujinya, dan git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }bekerja untuk saya di OSX.
keif
21

Anda dapat menemukan komit terakhir yang menghapus file sebagai berikut:

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

Informasi lebih lanjut tersedia di sini

Akif
sumber
11
Solusi utama yang dibatalkan tidak bekerja untuk saya, tetapi yang ini berhasil.
Nick Heiner
0

Mencoba:

git log --stat | grep file
Eric Woodruff
sumber