Jak znaleźć zatwierdzenie Git, które wprowadziło ciąg w dowolnej gałęzi?

396

Chcę być w stanie znaleźć określony ciąg, który został wprowadzony w dowolnym zatwierdzeniu w dowolnej gałęzi, jak mogę to zrobić? Znalazłem coś (co zmodyfikowałem dla Win32), ale git whatchangedwydaje się, że nie patrzy na różne gałęzie (zignoruj ​​fragment py3k, to tylko poprawka msys / win line feed)

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>

Tak naprawdę nie ma znaczenia, czy twoje rozwiązanie jest wolne.

Jonas Byström
źródło

Odpowiedzi:

685

Możesz to zrobić:

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

Aby znaleźć wszystkie zatwierdzenia, które dodały lub usunęły ustalony ciąg whatever . Ten --allparametr oznacza rozpoczęcie od każdej gałęzi i --sourceoznacza, która z tych gałęzi doprowadziła do znalezienia tego zatwierdzenia. Często przydatne jest dodanie, -paby pokazać łatki, które wprowadziłby każdy z tych zatwierdzeń.

Wersje git od wersji 1.7.4 również mają podobną -Gopcję, która przyjmuje wyrażenie regularne . To faktycznie ma inną (i raczej bardziej oczywistą) semantykę, wyjaśnioną w tym blogu od Junio ​​Hamano .

Jak wskazuje thameera w komentarzach, musisz wstawić cudzysłowy wokół wyszukiwanego terminu, jeśli zawiera spacje lub inne znaki specjalne, na przykład:

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

Oto przykład, za pomocą którego -Gmożna znaleźć wystąpienia function foo() {:

git log -G "^(\s)*function foo[(][)](\s)*{$" --source --all
Mark Longair
źródło
19
+1 za doskonałość. Wskazywanie na -S jest jedną rzeczą, wyjaśnianie rzeczy, lepiej. Lubię też - dekorować, aby zobaczyć, z jakich gałęzi pochodzą
dniu
7
@sehe: Dzięki za miły komentarz. Myślę, że warto zauważyć, że --decoratedodaje tylko nazwę gałęzi do zatwierdzenia na końcu każdej gałęzi. W praktyce tak naprawdę nie używam --sourceani --decorate, a zamiast tego używam git branch -a --contains <commit-hash>do znalezienia, które gałęzie zawierają zatwierdzenie, które mnie interesuje.
Mark Longair
3
dodaj -p, aby zobaczyć różnicę wbudowaną, FWIW
rogerdpack
1
@ MarkLongair nie pokazuje zmian dokonanych podczas scalania. Wszelkie sugestie, aby je również pokazać?
Pahlevi Fikri Auliya
2
Dla mnie działa to tylko wtedy, gdy usunę spację między -S a wyszukiwanym terminem, tj git log -S"dude, where's my car?" --source --all. @ribamar również napisał to w odpowiedzi poniżej, ale można łatwo przeoczyć tę odpowiedź.
bug313
69

--reverse jest również pomocne, ponieważ chcesz pierwszego zatwierdzenia, które dokonało zmiany:

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

W ten sposób najpierw pojawią się starsze zatwierdzenia.

Ciro Santilli
źródło
20

Odpowiedź Marka Longaira jest doskonała, ale uważam, że ta prostsza wersja działa dla mnie.

git log -S whatever
Steven Penny
źródło
24
Żeby wyjaśnić, działa to dobrze, jeśli szuka się zatwierdzenia HEAD, ale w tym konkretnym pytaniu zadano konkretnie o przejrzeniu wszystkich gałęzi w repozytorium.
Mark Longair
18

Bałagan z tymi samymi odpowiedziami:

$ git config --global alias.find '!git log --color -p -S '
  • ! jest potrzebne, ponieważ w inny sposób git nie przekazuje poprawnie argumentu do -S. Zobacz tę odpowiedź
  • --color i -p pomaga pokazać dokładnie „whatchanged”

Teraz możesz zrobić

$ git find <whatever>

lub

$ git find <whatever> --all
$ git find <whatever> master develop
albfan
źródło
6
git log -S"string_to_search" # options like --source --reverse --all etc

Uważaj, aby nie używać spacji między S a „string_to_search”. W niektórych konfiguracjach (git 1.7.1) pojawia się błąd:

fatal: ambiguous argument 'string_to_search': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
ribamar
źródło
2

Chociaż nie odpowiada to bezpośrednio na pytanie, myślę, że może to być dobre rozwiązanie dla ciebie w przyszłości. Widziałem część mojego kodu, co było złe. Nie wiedziałam, kto to napisał i kiedy. Widziałem wszystkie zmiany z pliku, ale było jasne, że kod został przeniesiony z innego pliku do tego. Chciałem przede wszystkim dowiedzieć się, kto go dodał.

Aby to zrobić, użyłem Git Bisect , co szybko pozwoliło mi znaleźć grzesznika.

Pobiegłem, git bisect starta potem git bisect bad, ponieważ sprawdzona wersja miała problem. Ponieważ nie wiadomo, kiedy problem wystąpił, ja kierowane pierwszy popełnić za „dobre”, git bisect good <initial sha>.

Potem po prostu szukałem w repozytorium złego kodu. Kiedy okazało się, że wpadłem git bisect bad, a gdy nie było tam: git bisect good.

W ~ 11 krokach omówiłem ~ 1000 zatwierdzeń i znalazłem dokładne zatwierdzenie, w którym problem został wprowadzony. Całkiem dobrze.

Eldamir
źródło
2

Nie jestem pewien, dlaczego zaakceptowana odpowiedź nie działa w moim środowisku, w końcu uruchamiam poniżej polecenia, aby uzyskać to, czego potrzebuję

git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"
BMW
źródło