Bagaimana menemukan komit Git yang memperkenalkan string di cabang mana saja?

396

Saya ingin dapat menemukan string tertentu yang diperkenalkan di komit apa pun di cabang mana pun, bagaimana saya bisa melakukannya? Saya menemukan sesuatu (yang saya modifikasi untuk Win32), tetapi git whatchangedtampaknya tidak melihat ke cabang yang berbeda (abaikan potongan py3k, itu hanya perbaikan feed baris msys / win)

git whatchanged -- <file> | \
grep "^commit " | \
python -c "exec(\"import sys,msvcrt,os\nmsvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)\nfor l in sys.stdin: print(l.split()[1])\")" | \
xargs -i% git show origin % -- <file>

Tidak masalah jika solusi Anda lambat.

Jonas Byström
sumber

Jawaban:

685

Anda dapat melakukan:

git log -S <whatever> --source --all

Untuk menemukan semua komit yang menambahkan atau menghapus string tetap whatever . The --allberarti parameter untuk memulai dari setiap cabang dan --sourcesarana untuk menunjukkan mana yang cabang menyebabkan temuan bahwa komit. Sering berguna untuk menambahkan -puntuk menunjukkan patch yang masing-masing berkomitmen akan memperkenalkan juga.

Versi git sejak 1.7.4 juga memiliki -Gopsi serupa , yang mengambil ekspresi reguler . Ini sebenarnya memiliki semantik yang berbeda (dan lebih jelas), dijelaskan dalam posting blog ini dari Junio ​​Hamano .

Seperti yang ditunjukkan thameera dalam komentar, Anda perlu memberi tanda kutip di sekitar istilah pencarian jika mengandung spasi atau karakter khusus lainnya, misalnya:

git log -S 'hello world' --source --all
git log -S "dude, where's my car?" --source --all

Berikut ini contoh yang digunakan -Guntuk menemukan kejadian function foo() {:

git log -G "^(\s)*function foo[(][)](\s)*{$" --source --all
Mark Longair
sumber
19
+1 untuk keunggulan. Menunjuk pada -S adalah satu hal, menjelaskan sesuatu, lebih baik. Juga, saya suka menggunakan --decorate untuk melihat dari mana cabang itu berasal
sehe
7
@ Sehe: Terima kasih atas komentar Anda yang bagus. Saya kira perlu dicatat bahwa --decoratehanya menambahkan nama cabang ke komit di ujung setiap cabang. Dalam praktiknya saya tidak benar-benar menggunakan --sourceatau --decorate, dan alih-alih menggunakan git branch -a --contains <commit-hash>untuk menemukan cabang mana yang berisi komit yang saya minati.
Mark Longair
3
tambahkan -p untuk melihat diff sebaris, juga, FWIW
rogerdpack
1
@ MarkLongair itu tidak menunjukkan perubahan yang dibuat dalam gabungan. Adakah saran untuk menunjukkannya juga?
Pahlevi Fikri Auliya
2
Bagi saya ini hanya berfungsi jika saya menghapus spasi antara -S dan istilah pencarian, yaitu git log -S"dude, where's my car?" --source --all,. @ribamar juga menulis itu dalam jawaban di bawah, tetapi mungkin dengan mudah diabaikan di samping jawaban teratas ini.
bug313
69

--reverse juga membantu karena Anda ingin komit pertama yang membuat perubahan:

git log --all -p --reverse --source -S 'needle'

Dengan cara ini, komitmen yang lebih lama akan muncul lebih dulu.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
20

Jawaban Mark Longair sangat bagus, tetapi saya telah menemukan versi yang lebih sederhana ini bekerja untuk saya.

git log -S whatever
Steven Penny
sumber
24
Hanya untuk memperjelas, itu berfungsi dengan baik jika komit yang Anda cari ada HEAD, tetapi pertanyaan khusus ini bertanya secara khusus tentang melihat semua cabang dalam repositori.
Mark Longair
18

Bercak dengan jawaban yang sama:

$ git config --global alias.find '!git log --color -p -S '
  • ! diperlukan karena dengan cara lain, git tidak meneruskan argumen dengan benar ke -S. Lihat respons ini
  • --color dan -p membantu menampilkan dengan tepat "whatchanged"

Sekarang kamu bisa melakukannya

$ git find <whatever>

atau

$ git find <whatever> --all
$ git find <whatever> master develop
Albfan
sumber
6
git log -S"string_to_search" # options like --source --reverse --all etc

Perhatikan untuk tidak menggunakan spasi antara S dan "string_to_search". Dalam beberapa pengaturan (git 1.7.1), Anda akan mendapatkan kesalahan seperti:

fatal: ambiguous argument 'string_to_search': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
ribamar
sumber
2

Meskipun ini tidak langsung menjawab pertanyaan Anda, saya pikir itu mungkin solusi yang baik untuk Anda di masa depan. Saya melihat bagian dari kode saya, yang buruk. Tidak tahu siapa yang menulisnya atau kapan. Saya dapat melihat semua perubahan dari file, tetapi jelas bahwa kode telah dipindahkan dari beberapa file lain ke yang ini. Saya ingin menemukan siapa yang sebenarnya menambahkannya di tempat pertama.

Untuk melakukan ini, saya menggunakan Git bisect , yang dengan cepat membiarkan saya menemukan orang berdosa.

Saya berlari git bisect startdan kemudian git bisect bad, karena revisi diperiksa memiliki masalah. Karena saya tidak tahu kapan masalah terjadi, saya menargetkan komit pertama untuk "baik" git bisect good <initial sha>,.

Kemudian saya terus mencari repo untuk kode yang buruk. Ketika saya menemukannya, aku berlari git bisect bad, dan ketika itu tidak ada: git bisect good.

Dalam ~ 11 langkah, saya telah membahas ~ 1000 komitmen dan menemukan komit yang tepat, di mana masalah tersebut diperkenalkan. Cukup bagus.

Eldamir
sumber
2

Tidak yakin mengapa jawaban yang diterima tidak bekerja di lingkungan saya, akhirnya saya menjalankan perintah di bawah ini untuk mendapatkan yang saya butuhkan

git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"
BMW
sumber