Bagaimana cara "menyalahkan git" baris yang dihapus?

506

git blamebagus untuk baris yang dimodifikasi dan ditambahkan, tetapi bagaimana saya bisa menemukan ketika garis yang ada di komit sebelumnya tertentu akhirnya dihapus. Aku sedang berpikir bisect, tapi aku berharap sesuatu yang lebih baik.

(Sebelum Anda bertanya: dalam hal ini, saya baru saja melakukan git log -pdan mencari-cari baris kode dan (a) beberapa idiot baru saja menghapus garis vital pada komit sebelumnya dan (b) saya idiot itu.)

Malvolio
sumber
4
Ada tindak lanjut dengan jawaban yang mengklarifikasi yang git log -S<string> /path/to/fileingin -catau -ccjuga menunjukkan penghapusan selama penggabungan (konflik)
cfi
3
Seharusnya -cdan --cc. @Steen: Benar, terima kasih telah menunjukkan! Pengawasan yang bodoh. Seandainya saya bisa mengedit komentar. Menambahkan yang baru, lalu menghapus milikku, maka kamu menghapus milikmu terlalu rumit kurasa :)
cfi
4
Saya berharap git blamememiliki opsi untuk menampilkan baris yang dihapus (dengan mungkin dicoret atau teks merah) dengan revisi di mana mereka dihapus.
Craig McQueen
Apakah itu sulit untuk ditulis? Saya tidak tahu banyak tentang Git internal.
Malvolio

Jawaban:

636

Jika Anda tahu konten baris, ini adalah kasus penggunaan yang ideal untuk:

git log -S <string> path/to/file

yang menunjukkan Anda melakukan yang memperkenalkan atau menghapus instance string itu. Ada juga -G<regex>yang melakukan hal yang sama dengan ekspresi reguler! Lihat man git-logdan cari opsi -Gdan -S, atau beliung (nama yang ramah untuk fitur ini) untuk informasi lebih lanjut.

The -Spilihan sebenarnya disebutkan dalam header dari git-blamemanualnya juga, di bagian description, di mana ia memberi contoh dengan menggunakan git log -S....

Cascabel
sumber
Cemerlang ... hanya apa yang saya butuhkan dalam pekerjaan porting ini saya kerjakan +1
jkp
37
Setelah menggunakan Git selama 1+ tahun, saya masih heran melihat bahwa Git selalu memiliki perintah / opsi di suatu tempat untuk mengatasi hampir semua skenario penggunaan yang saya miliki. Terima kasih telah berbagi yang ini, itulah yang saya butuhkan sekarang!
Pascal Bourque
22
Metode ini telah bekerja untuk saya sebelumnya, tetapi baru saja saya melihat kasus di mana tidak menemukan komit di mana garis itu dihapus. Ternyata baris yang dimaksud dihapus dalam gabungan komit - akankah itu menjelaskan kegagalannya? ( git blame --reverseMetode menemukan itu.)
Antinome
9
@antinome Untuk menunjukkan komit dari penggabungan, gunakan -copsi tambahan.
yunzen
2
Saya melakukan ctrl + f pada "-s" di halaman manual dan tidak menemukan apa pun. Di mana pada halaman yang Anda lihat itu ?? Saya menggunakan git 1.8.5.2
temporary_user_name
135

Saya pikir apa yang Anda inginkan sebenarnya

git blame --reverse START..END filename

Dari halaman manual :

Berjalan sejarah ke depan, bukan ke belakang. Alih-alih menunjukkan revisi di mana garis muncul, ini menunjukkan revisi terakhir di mana garis telah ada. Ini memerlukan serangkaian revisi seperti MULAI..END di mana jalan untuk disalahkan ada di MULAI.

Dengan git blame reverse, Anda dapat menemukan komit terakhir di mana baris tersebut muncul. Anda masih perlu mendapatkan komit yang muncul setelahnya.

Anda dapat menggunakan perintah berikut untuk menampilkan log git terbalik. Komit pertama yang diperlihatkan akan menjadi yang terakhir kali baris tersebut muncul, dan komit berikutnya adalah ketika diubah atau dihapus.

git log --reverse --ancestry-path COMMIT^..master
Kronologis
sumber
14
Jika ada beberapa penggabungan dari cabang tempat garis ditambahkan ke cabang tempat garis tersebut hilang (atau kasus lain di mana ada beberapa jalur dalam garis keturunan dari START hingga END), git blame --reverseakan menampilkan revisi sebelum penggabungan yang secara kronologis terakhir, bukan revisi sebelum penggabungan awal di mana keputusan dibuat untuk tidak mengambil garis. Apakah ada cara untuk menemukan revisi paling awal di mana garis berhenti ada daripada yang terbaru?
rakslice
2
@rakslice, untuk itu Anda dapat menggunakan menyalahkan --reverse --first-parent, ini sedikit lebih baik.
maks 630
17

Hanya untuk melengkapi jawaban Cascabel :

git log --full-history -S <string> path/to/file

Saya memiliki masalah yang sama dengan yang disebutkan di sini, tetapi ternyata garis itu hilang, karena komit gabungan dari cabang dikembalikan dan kemudian bergabung kembali ke dalamnya, secara efektif menghilangkan garis yang dipertanyakan. The --full-historymencegah bendera melewatkan mereka komit.

estani
sumber
9

git menyalahkan --reverse dapat membuat Anda dekat dengan tempat garis dihapus. Tetapi sebenarnya tidak menunjuk ke revisi di mana garis dihapus. Ini menunjuk ke revisi terakhir di mana garis itu ada . Kemudian jika revisi berikut ini adalah komit sederhana, Anda beruntung dan Anda mendapat revisi penghapusan. OTOH, jika revisi berikut adalah gabungan komit , maka semuanya bisa menjadi sedikit liar.

Sebagai bagian dari upaya membuat difflame, saya menangani masalah ini jadi jika Anda sudah menginstal Python di komputer Anda dan Anda bersedia mencobanya, maka jangan menunggu lagi dan biarkan saya tahu bagaimana hasilnya.

https://github.com/eantoranz/difflame

eftshift0
sumber
0

Untuk perubahan yang disembunyikan dalam gabungan komitmen

Menggabungkan komit secara otomatis menyembunyikan perubahannya dari output log Git. Baik beliung dan sebaliknya-menyalahkan tidak menemukan perubahan. Jadi baris yang saya inginkan telah ditambahkan dan kemudian dihapus dan saya ingin menemukan gabungan yang menghapusnya. git log -p -- path/fileRiwayat file hanya menunjukkan itu ditambahkan. Inilah cara terbaik yang saya temukan untuk menemukannya:

git log -p -U9999 -- path/file

Cari perubahannya, lalu cari mundur untuk "^ commit" - yang pertama "^ commit" adalah komit di mana file terakhir memiliki baris itu. "^ Commit" kedua adalah setelah menghilang. Komit kedua mungkin adalah yang menghapusnya. Ini -U9999dimaksudkan untuk menampilkan seluruh isi file (setelah setiap kali file diubah), dengan asumsi file Anda semuanya maks 9999 baris.

Menemukan gabungan yang terkait melalui brute force (bedakan setiap kemungkinan gabungan komit dengan induk pertamanya, jalankan terhadap ton komit)

git log --merges --pretty=format:"git diff %h^...%h | grep target_text" HEAD ^$(git merge-base A B) | sh -v 2>&1 | less

(Saya mencoba membatasi filter revisi lebih banyak, tetapi saya mengalami masalah dan tidak merekomendasikan ini. Perubahan penambahan / penghapusan yang saya cari ada di cabang berbeda yang digabung pada waktu yang berbeda dan A ... B tidak termasuk ketika perubahan benar-benar digabungkan ke dalam arus utama.)

Perlihatkan pohon Git dengan dua komit ini (dan banyak riwayat kompleks Git dihapus):

git log --graph --oneline A B ^$(git merge-base A B) (A adalah komit pertama di atas, B adalah komit kedua di atas)

Tampilkan riwayat A dan riwayat B minus sejarah A dan B.

Versi alternatif (tampaknya menunjukkan jalur lebih linier daripada pohon riwayat Git biasa - namun saya lebih suka pohon riwayat git biasa):

git log --graph --oneline A...B

Tiga, bukan dua titik - tiga titik berarti "r1 r2 - tidak $ (git merge-base --all r1 r2). Ini adalah himpunan komit yang dapat dijangkau dari salah satu dari r1 (sisi kiri) atau r2 (kanan sisi), tetapi tidak dari keduanya. " - sumber: "man gitrevisions"

Curtis Yallop
sumber