Bagaimana cara mencari semua komit Git dan Mercurial di repositori untuk string tertentu?

287

Saya memiliki repositori Git dengan beberapa cabang dan komit menggantung. Saya ingin mencari semua commit di repositori untuk string tertentu.

Saya tahu cara mendapatkan log dari semua commit dalam sejarah, tetapi ini tidak termasuk cabang atau gumpalan yang menggantung, hanya sejarah HEAD. Saya ingin mendapatkan semuanya, untuk menemukan komit tertentu yang salah tempat.

Saya juga ingin tahu bagaimana melakukan ini di Mercurial, karena saya sedang mempertimbangkan saklar.

Josip
sumber

Jawaban:

331

Anda dapat melihat komit menggantung dengan git log -g.

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

Jadi Anda bisa melakukan ini untuk menemukan string tertentu dalam pesan komit yang menggantung:

git log -g --grep=search_for_this

Atau, jika Anda ingin mencari perubahan untuk string tertentu, Anda dapat menggunakan opsi pencarian beliung, "-S":

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

Git 1.7.4 akan menambahkan opsi -G , memungkinkan Anda untuk melewatkan -G <regexp> untuk menemukan ketika baris yang mengandung <regexp> dipindahkan, yang -S tidak bisa lakukan. -S hanya akan memberi tahu Anda ketika jumlah total baris yang berisi string berubah (yaitu menambah / menghapus string).

Akhirnya, Anda bisa menggunakan gitk untuk memvisualisasikan komit yang menggantung dengan:

gitk --all $(git log -g --pretty=format:%h)

Dan kemudian gunakan fitur pencariannya untuk mencari file yang salah tempat. Semua pekerjaan ini dengan asumsi komit yang hilang belum "kedaluwarsa" dan telah dikumpulkan, yang dapat terjadi jika menggantung selama 30 hari dan Anda kedaluwarsa reflog atau menjalankan perintah yang kedaluwarsa.

richq
sumber
4
Mungkin alih-alih menjalankan "git grep" pada sejumlah komit (yang mungkin besar), yang akan menemukan semua komit yang memiliki 'search_for_this' di suatu proyek, gunakan yang disebut pencarian "beliung", yaitu opsi '-S' untuk mendapatkan log , yang menemukan komit yang memperkenalkan atau menghapus string yang diberikan, atau lebih tepatnya di mana jumlah kemunculan string yang diberikan berubah.
Jakub Narębski
5
Anda dapat menentukan beberapa cabang, atau menggunakan opsi '--all', mis. 'Git log --grep = "string dalam pesan commit" --all'
Jakub Narębski
Ini hanya memungkinkan saya untuk menemukan komitmen yang hilang untuk pekerjaan 2 hari. Benar-benar menyelamatkan pantat saya, terima kasih!
Mike Chamberlain
2
Saya telah menemukan beberapa situasi di mana saya memiliki komit dalam database saya tetapi tidak dalam reflog saya. Saya tidak tahu seberapa umum ini. Saya mencoba berbagai jembatan hg / git. Saya pikir itu juga bisa timbul dengan simpanan jatuh. Bagaimanapun, alias ini berfungsi dengan baik untuk menangkap kasus-kasus tersebut:!git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk
dubiousjim
Catatan, itu tidak termasuk mencari objek catatan. Itu belum diimplementasikan: git.661346.n2.nabble.com/…
Antony Stubbs
54

Di Mercurial Anda gunakan hg log --keyworduntuk mencari kata kunci dalam pesan komit dan hg log --useruntuk mencari pengguna tertentu. Lihat hg help logcara lain untuk membatasi log.

Martin Geisler
sumber
36
Josip menulis bahwa dia mempertimbangkan untuk beralih ke Mercurial dan bahwa dia juga ingin mendengar bagaimana hal itu dilakukan di sana.
Martin Geisler
1
hg log -kpencarian komit nama pengguna dan nama file di changesets juga (saya melihat itu di commands.py:log), yang merupakan salah satu dari beberapa hal yang saya tidak mengerti di hg. Seharusnya ada opsi terpisah untuk mencari dalam pesan komit dan nama file. Sepertinya hg log --template '{desc}\n'|grepcara yang pasti.
Geoffrey Zheng
@ GeoffreyZheng: ada cara untuk melakukan itu. Lihat "hg help revsets", khususnya fungsi desc (), user (), dan file (). Ada juga sakelar hg log untuk sebagian besar perilaku ini. Dalam pengalaman saya, meskipun -k / kata kunci () biasanya merupakan cara yang paling membantu untuk mencari sesuatu.
Kevin Horn
Bagaimana seseorang mencari melalui konten file yang sebenarnya dilakukan ... diffs? Saya tahu ini akan menjadi pencarian yang lambat, tetapi saya ingin melakukan pencarian mendalam untuk nama fungsi yang hilang.
Jonathan
Oh ini dia:hg grep --all <term>
Jonathan
24

Selain jawaban richq menggunakan git log -g --grep=<regexp>atau git grep -e <regexp> $(git log -g --pretty=format:%h): lihat posting blog berikut oleh Junio ​​C Hamano, pengelola git saat ini


Ringkasan

Kedua git grep dan git log --grep yang garis berorientasi , dalam bahwa mereka mencari jalur yang cocok dengan pola yang telah ditentukan.

Anda dapat menggunakan git log --grep=<foo> --grep=<bar>(atau git log --author=<foo> --grep=<bar>yang diterjemahkan secara internal menjadi dua --grep) untuk menemukan komit yang cocok dengan salah satu pola (implisit ATAU semantik).

Karena menjadi line-berorientasi, berguna dan semantik adalah dengan menggunakan git log --all-match --grep=<foo> --grep=<bar>untuk menemukan komit yang memiliki kedua pencocokan baris pertama dan baris yang cocok di suatu tempat kedua.

Dengan git grepAnda dapat menggabungkan beberapa pola (semua yang harus menggunakan -e <regexp>bentuk) dengan --or(yang merupakan default), --and, --not, (dan ). For grep --all-matchberarti file tersebut harus memiliki garis yang cocok dengan setiap alternatif.

Jakub Narębski
sumber
Hai Jakub, bisakah mengintegrasikan kutipan / ringkasan dari posting blog di sini? Sepertinya salah satu jawaban hanya tautan vintage saat ini.
Nathan Tuggy
11

Berdasarkan jawaban rq, saya menemukan baris ini melakukan apa yang saya inginkan:

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

Yang akan melaporkan ID komit, nama file, dan menampilkan garis yang cocok, seperti ini:

91ba969:testFile:this is a test

... Apakah ada yang setuju bahwa ini akan menjadi opsi yang bagus untuk dimasukkan dalam perintah standar git grep?

Sam Hiatt
sumber
5

Perintah apa pun yang menggunakan referensi sebagai argumen akan menerima --allopsi yang didokumentasikan dalam halaman manual git rev-listsebagai berikut:

   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

Jadi misalnya git log -Sstring --allakan menampilkan semua komit yang menyebutkan stringdan yang dapat diakses dari cabang atau dari tag (Saya mengasumsikan bahwa komit Anda menggantung setidaknya dinamai dengan tag).

adl
sumber
3
Ini tampaknya bukan kasus untuk git grep, di mana --alltampaknya diterjemahkan ke / digunakan sebagai --all-match. Ini terlihat seperti bug bagi saya .. menggunakan Git 1.7.2.3 (menggunakan $(git rev-list --all)karya).
blueyed
5

Dengan Mercurial Anda melakukan a

$ hg grep "search for this" [file...]

Ada opsi lain yang mempersempit rentang revisi yang dicari.

Yawar
sumber
1
Saya juga suka benderahg grep --all
Jonathan
2

Tidak tahu tentang git, tetapi di Mercurial saya hanya akan menyalurkan output dari hg log ke beberapa sed / perl / script apa pun untuk mencari apa pun yang Anda cari. Anda dapat menyesuaikan output log hg menggunakan templat atau gaya agar lebih mudah dicari, jika diinginkan.

Ini akan mencakup semua cabang bernama dalam repo. Mercurial tidak memiliki sesuatu seperti menggantung gumpalan afaik.

Kurt Schelfthout
sumber
1
Saya tidak mengerti bagaimana jawaban ini relevan dengan masalah yang ditentukan.
jribeiro
3
Ini adalah jawaban untuk pertanyaan untuk Mercurial, yang ditanyakan oleh pertanyaan asli pada paragraf terakhir.
Kurt Schelfthout
1

jika Anda adalah pengguna vim, Anda dapat menginstal tig (apt-get install tig), dan menggunakan /, perintah yang sama untuk mencari di vim

https://blogs.atlassian.com/2013/05/git-tig/

jacktrade
sumber
1

Untuk menambahkan satu lagi solusi yang belum disebutkan, saya harus mengatakan bahwa menggunakan kotak pencarian grafis gitg adalah solusi paling sederhana untuk saya. Ini akan memilih kejadian pertama dan Anda dapat menemukan yang berikutnya dengan Ctrl-G.

icarito
sumber
1

Satu perintah di git yang menurut saya lebih mudah untuk menemukan string:

git log --pretty=oneline --grep "string to search"

bekerja di Git 2.0.4

Adriano Rosa
sumber