Come trovare il commit Git che ha introdotto una stringa in qualsiasi ramo?


396

Voglio essere in grado di trovare una determinata stringa che è stata introdotta in qualsiasi commit in qualsiasi ramo, come posso farlo? Ho trovato qualcosa (che ho modificato per Win32), ma git whatchangednon sembra guardare nei diversi rami (ignora il pezzo py3k, è solo una correzione del feed di linea 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>

Non importa se la tua soluzione è lenta.


Risposte:


685

Tu puoi fare:

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

Per trovare tutti i commit che hanno aggiunto o rimosso la stringa fissa whatever . Il --allparametro significa partire da ogni ramo e --sourceindicare quale di questi rami ha portato a trovare quel commit. È spesso utile aggiungere -pper mostrare anche le patch introdotte da ciascuna di queste commit.

Le versioni di git dalla 1.7.4 hanno anche -Gun'opzione simile , che assume un'espressione regolare . Questo in realtà ha una semantica diversa (e piuttosto più ovvia), spiegata in questo post sul blog di Junio ​​Hamano .

Come sottolinea Thameera nei commenti, è necessario inserire virgolette attorno al termine di ricerca se contiene spazi o altri caratteri speciali, ad esempio:

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

Ecco un esempio usando -Gper trovare occorrenze di function foo() {:

git log -G "^(\s)*function foo[(][)](\s)*{$" --source --all

19
+1 per eccellenza. Indicare -S è una cosa, spiegare le cose, meglio. Inoltre, mi piace usare - decorare per vedere da quali rami provengono le cose
sehe,

7
@sehe: grazie per il tuo bel commento. Immagino che valga la pena notare che --decorateaggiunge solo il nome del ramo al commit sulla punta di ogni ramo. In pratica non uso davvero --sourceo --decorate, e invece uso git branch -a --contains <commit-hash>per trovare quali rami contengono il commit che mi interessa.
Mark Longair,

3
aggiungi -p per vedere anche il diff inline, FWIW
rogerdpack

1
@MarkLongair non mostra le modifiche apportate in unione. Qualche suggerimento per mostrare anche quelli?
Pahlevi Fikri Auliya

2
Per me questo funziona solo se rimuovo lo spazio tra -S e il termine di ricerca, cioè git log -S"dude, where's my car?" --source --all. @ribamar lo ha anche scritto in una risposta di seguito, ma potrebbe facilmente essere trascurato accanto a questa risposta.
bug313,


20

La risposta di Mark Longair è eccellente, ma ho trovato questa versione più semplice che funziona per me.

git log -S whatever

24
Giusto per chiarire, funziona bene se il commit che stai cercando è presente HEAD, ma questa particolare domanda è stata posta in modo specifico su come guardare attraverso tutti i rami in un repository.
Mark Longair,

18

In giro con le stesse risposte:

$ git config --global alias.find '!git log --color -p -S '
  • ! è necessario perché altrimenti, git non passa l'argomento correttamente a -S. Vedi questa risposta
  • --color e -p aiutano a mostrare esattamente "ciò che è cambiato"

Adesso puoi farlo

$ git find <whatever>

o

$ git find <whatever> --all
$ git find <whatever> master develop

6
git log -S"string_to_search" # options like --source --reverse --all etc

Prestare attenzione a non utilizzare spazi tra S e "string_to_search". In alcune configurazioni (git 1.7.1), otterrai un errore come:

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

2

Anche se questo non risponde direttamente alla tua domanda, penso che potrebbe essere una buona soluzione per te in futuro. Ho visto una parte del mio codice, che era male. Non sapevo chi lo ha scritto o quando. Ho potuto vedere tutte le modifiche dal file, ma era chiaro che il codice era stato spostato da qualche altro file a questo. Volevo trovare chi lo ha effettivamente aggiunto in primo luogo.

Per fare questo, ho usato Git bisect , che mi ha fatto rapidamente trovare il peccatore.

Ho corso git bisect starte poi git bisect bad, perché la revisione verificata aveva il problema. Dal momento che non sapere quando il problema si è verificato, ho mirato il primo commit per il "bene", git bisect good <initial sha>.

Quindi ho continuato a cercare nel repository il codice errato. Quando l'ho trovato, mi sono imbattuto git bisect bad, e quando non era lì: git bisect good.

In ~ 11 passaggi, avevo coperto ~ 1000 commit e ho trovato il commit esatto, in cui è stato introdotto il problema. Abbastanza grande


2

Non sono sicuro del motivo per cui la risposta accettata non funziona nel mio ambiente, infine corro sotto il comando per ottenere ciò di cui ho bisogno

git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.