Pertanyaan Bagaimana cara grep (pencarian) kode berkomitmen dalam sejarah git?


Saya telah menghapus file atau beberapa kode dalam file di masa lalu. Dapatkah saya meng-grep konten (bukan dalam pesan commit)?

Solusi yang sangat buruk adalah meng-grep log:

git log -p | grep <pattern>

Namun ini tidak mengembalikan hash komit langsung. Saya bermain-main dengan git grep tidak berhasil.


1112
2018-05-28 11:36


asal


Jawaban:


Untuk mencari commit konten (yaitu, baris sumber yang sebenarnya, sebagai lawan dari mengkomit pesan dan sejenisnya), yang perlu Anda lakukan adalah:

git grep <regexp> $(git rev-list --all)

Pembaruan: git rev-list --all | xargs git grep expression akan berfungsi jika Anda mengalami kesalahan "Argument list too long"

Jika Anda ingin membatasi pencarian ke beberapa subtree (misalnya "lib / util"), Anda harus meneruskannya ke rev-list sub perintah dan grep demikian juga:

git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util

Ini akan menyapa semua teks commit Anda untuk regexp.

Alasan untuk melewati jalan di kedua perintah adalah karena rev-list akan mengembalikan daftar revisi tempat semua perubahan lib/util terjadi, tetapi juga Anda harus lolos grep sehingga hanya akan mencari lib/util.

Bayangkan saja skenario berikut: grep mungkin menemukan hal yang sama <regexp> pada file lain yang terkandung dalam revisi yang sama dikembalikan oleh rev-list (bahkan jika tidak ada perubahan ke file itu pada revisi itu).

Berikut beberapa cara berguna lainnya dalam mencari sumber Anda:

Cari pohon kerja untuk teks yang cocok dengan ekspresi reguler regexp:

git grep <regexp>

Cari pohon kerja untuk baris teks yang cocok dengan ekspresi reguler regexp1 atau regexp2:

git grep -e <regexp1> [--or] -e <regexp2>

Cari pohon kerja untuk baris teks yang cocok dengan ekspresi reguler regexp1 dan regexp2, hanya melaporkan jalur file:

git grep -e <regexp1> --and -e <regexp2>

Telusuri pohon kerja untuk file yang memiliki baris teks yang cocok dengan ekspresi reguler regexp1 dan baris teks yang cocok dengan ekspresi reguler regexp2:

git grep -l --all-match -e <regexp1> -e <regexp2>

Cari pohon kerja untuk mengubah garis pola pencocokan teks:

git diff --unified=0 | grep <pattern>

Cari semua revisi untuk teks yang cocok dengan ekspresi reguler regexp:

git grep <regexp> $(git rev-list --all)

Cari semua revisi antara rev1 dan rev2 untuk regex reguler ekspresi reguler pencocokan teks:

git grep <regexp> $(git rev-list <rev1>..<rev2>)

1483
2018-05-28 13:47



Anda harus menggunakan beliung (-S) opsi dari git log

Untuk mencari Foo:

git log -SFoo -- path_containing_change 
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change

Lihat Riwayat Git - temukan garis hilang berdasarkan kata kunci untuk lebih.


Sebagai Jakub Narębski berkomentar:

  • ini mencari perbedaan yang memperkenalkan atau menghapus turunan dari <string>.
    Biasanya ini berarti "revisi di mana Anda menambahkan atau menghapus garis dengan 'Foo'".

  • itu --pickaxe-regex pilihan memungkinkan Anda untuk menggunakan regex POSIX diperpanjang alih-alih mencari string.


Sebagai rampok berkomentar, pencarian ini peka huruf besar kecil - ia membuka a Pertanyaan lanjutan tentang cara mencari case-insensitive.


439
2018-05-28 11:57



Cara favorit saya untuk melakukannya adalah dengan git log's -G opsi (ditambahkan dalam versi 1.7.4).

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

Ada perbedaan halus antara cara itu -G dan -S Pilihan menentukan apakah komit cocok:

  • Itu -S pilihan pada dasarnya menghitung berapa kali pencarian Anda cocok dalam file sebelum dan sesudah komit. Komit ditampilkan dalam log jika hitungan sebelum dan sesudah berbeda. Ini tidak akan, misalnya, menunjukkan komit di mana garis yang sesuai dengan pencarian Anda dipindahkan.
  • Dengan -G pilihan, komit ditampilkan di log jika pencarian Anda cocok dengan setiap baris yang ditambahkan, dihapus, atau diubah.

Ambil komit ini sebagai contoh:

diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello

Karena beberapa kali "hello" muncul di file adalah sama sebelum dan sesudah commit ini, itu tidak akan cocok menggunakan -Shello. Namun, karena ada perubahan pada pencocokan garis hello, komit akan ditampilkan menggunakan -Ghello.


204
2017-09-14 18:34



Jika Anda ingin menelusuri perubahan kode (lihat apa yang sebenarnya telah diubah dengan kata yang diberikan di seluruh sejarah), lakukan patch mode - Saya menemukan kombinasi yang sangat berguna dalam melakukan:

git log -p
# hit '/' for search mode
# type in the word you are searching
# if the first search is not relevant hit 'n' for next (like in vim ;) )

33
2018-04-17 08:17



Saya ambil Jawaban @ Jeet dan mengadaptasikannya ke Windows (terima kasih jawaban ini):

FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt

Perhatikan bahwa untuk saya, untuk beberapa alasan, komit yang sebenarnya yang menghapus regex ini tidak muncul dalam output dari perintah, melainkan satu komit sebelum itu.


22
2017-11-17 09:35



Mencari setiap revisi, file apa pun:

git rev-list --all | xargs git grep <regexp>

Cari hanya di beberapa file yang diberikan, misalnya file xml:

git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"

Garis hasil akan terlihat seperti ini: 6988bec26b1503d45eb0b2e8a4364afb87dde7af: bla.xml: teks dari garis yang ditemukan ...

Anda kemudian dapat memperoleh lebih banyak informasi seperti penulis, tanggal, diff menggunakan git show:

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

10
2018-04-02 15:03



git log dapat menjadi cara yang lebih efektif untuk mencari teks di semua cabang, terutama jika ada banyak kecocokan, dan Anda ingin melihat perubahan yang lebih baru (relevan) terlebih dahulu.

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

Daftar perintah log ini melakukan yang menambah atau menghapus string pencarian yang diberikan / regex, (umumnya) lebih baru pertama. Itu -p opsi menyebabkan diff yang relevan ditampilkan di mana pola ditambahkan atau dihapus, sehingga Anda dapat melihatnya dalam konteks.

Setelah menemukan komitmen yang relevan yang menambahkan teks yang Anda cari (mis. 8beeff00d), temukan cabang-cabang yang berisi commit:

git branch -a --contains 8beeff00d

8
2018-06-23 00:38



Untuk orang lain yang mencoba melakukan ini SumberTree, tidak ada perintah langsung di UI untuk itu (seperti versi 1.6.21.0). Namun Anda dapat menggunakan perintah yang ditentukan dalam jawaban yang diterima dengan membuka Terminal jendela (tombol yang tersedia di toolbar utama) dan salin / tempelkan di dalamnya.

Catatan: SourceTree's Pencarian view dapat melakukan pencarian teks sebagian untuk Anda. tekan Ctrl + 3 untuk masuk ke tampilan Pencarian (atau klik tab Cari tersedia di bagian bawah). Dari ujung kanan, atur jenis Pencarian ke Perubahan File lalu ketikkan string yang ingin Anda cari. Metode ini memiliki batasan berikut dibandingkan dengan perintah di atas:

  1. SourceTree hanya menunjukkan melakukan yang berisi kata pencarian di salah satu file yang diubah. Menemukan file yang tepat yang berisi teks pencarian lagi adalah tugas manual.
  2. RegEx tidak didukung.

5
2017-10-01 05:51



Jadi, apakah Anda mencoba untuk grep melalui versi kode yang lebih lama mencari untuk melihat di mana sesuatu yang terakhir ada?

Jika saya melakukan ini, saya mungkin akan menggunakannya git bisect. Dengan menggunakan membagi dua, Anda dapat menentukan versi yang dikenal baik, versi buruk yang diketahui, dan skrip sederhana yang memeriksa untuk melihat apakah versinya baik atau buruk (dalam kasus ini sebuah grep untuk melihat apakah kode yang Anda cari ada ). Menjalankan ini akan menemukan ketika kode telah dihapus.


2
2018-05-28 11:52



Jawaban @ Jeet bekerja di PowerShell.

git grep -n <regex> $(git rev-list --all)

Berikut ini menampilkan semua file, dalam komit apa pun, yang berisi a password.

# store intermediate result
$result = git grep -n "password" $(git rev-list --all)

# display unique file names
$result | select -unique { $_ -replace "(^.*?:)|(:.*)", "" }

2
2017-12-16 02:17



Untuk kesederhanaan, saya sarankan menggunakan GUI: gitk - Browser repositori Git, cukup fleksibel

  1. ke kode pencarian: enter image description here
  2. ke file pencarian: enter image description here
  3. penyebabnya juga mendukung regex: enter image description here

dan Anda dapat menavigasi hasil menggunakan panah atas / bawah


2
2018-02-07 07:35