Wie finde ich das Git-Commit, das einen String in einem Zweig eingeführt hat?


396

Ich möchte in der Lage sein, eine bestimmte Zeichenfolge zu finden, die in einem Commit in einem Zweig eingeführt wurde. Wie kann ich das tun? Ich habe etwas gefunden (das ich für Win32 geändert habe), aber es git whatchangedscheint nicht in die verschiedenen Zweige zu schauen (ignoriere den py3k-Block, es ist nur ein msys / win-Zeilenvorschub-Fix)

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>

Es spielt keine Rolle, ob Ihre Lösung langsam ist.


Antworten:


685

Du kannst tun:

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

So finden Sie alle Commits, die die feste Zeichenfolge hinzugefügt oder entfernt haben whatever. Der --allParameter bedeutet, von jedem Zweig zu beginnen und --sourcezu zeigen, welcher dieser Zweige zum Auffinden dieses Commits geführt hat. Es ist oft nützlich, diese hinzuzufügen -p, um die Patches anzuzeigen, die bei jedem dieser Commits ebenfalls eingeführt werden.

Git-Versionen seit 1.7.4 haben auch eine ähnliche -GOption, die einen regulären Ausdruck verwendet . Dies hat tatsächlich eine andere (und offensichtlichere) Semantik, die in diesem Blog-Beitrag von Junio ​​Hamano erklärt wird .

Wie Thameera in den Kommentaren hervorhebt , müssen Sie den Suchbegriff in Anführungszeichen setzen, wenn er Leerzeichen oder andere Sonderzeichen enthält, zum Beispiel:

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

Hier ist ein Beispiel -Gzum Auffinden von Vorkommen von function foo() {:

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

19
+1 für hervorragende Leistungen. Auf -S zu zeigen ist eine Sache, Dinge zu erklären, besser. Außerdem verwende ich gerne --decorate, um zu sehen, aus welchen Zweigen die Dinge kommen
sehe am

7
@sehe: Danke für deinen netten Kommentar. Ich denke, es ist erwähnenswert, dass --decoratenur der Filialname zum Commit an der Spitze jeder Filiale hinzugefügt wird. In der Praxis verwende ich nicht wirklich --sourceoder --decorate, und verwenden Sie stattdessen git branch -a --contains <commit-hash>zu finden , die Verzweigungen enthalten die commit interessiert mich.
Mark Longair

3
füge -p hinzu, um auch den Inline-Diff zu sehen, FWIW
rogerdpack

1
@ MarkLongair zeigt die beim Zusammenführen vorgenommenen Änderungen nicht an. Irgendwelche Vorschläge, um diese auch zu zeigen?
Pahlevi Fikri Auliya

2
Bei mir funktioniert das nur, wenn ich den Abstand zwischen dem -S und dem Suchbegriff entferne , dh , git log -S"dude, where's my car?" --source --all. @ribamar hat das auch in einer Antwort unten geschrieben, aber es könnte leicht neben dieser Top-Antwort übersehen werden.
Bug313


20

Mark Longairs Antwort ist ausgezeichnet, aber ich habe festgestellt, dass diese einfachere Version für mich funktioniert.

git log -S whatever

24
Nur um zu verdeutlichen, dass dies gut funktioniert, wenn sich das gesuchte Commit befindet HEAD, aber diese spezielle Frage wurde speziell zum Durchsuchen aller Zweige in einem Repository gestellt.
Mark Longair

18

Mit den gleichen Antworten herumspielen:

$ git config --global alias.find '!git log --color -p -S '
  • ! wird benötigt, weil git auf andere Weise das Argument nicht korrekt an -S übergibt. Siehe diese Antwort
  • --color und -p helfen dabei, genau "whatchanged" anzuzeigen

Jetzt können Sie tun

$ git find <whatever>

oder

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

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

Achten Sie darauf, keine Leerzeichen zwischen S und "string_to_search" zu verwenden. In einigen Setups (Git 1.7.1) wird folgende Fehlermeldung angezeigt:

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

2

Dies beantwortet Ihre Frage zwar nicht direkt, aber ich denke, es könnte in Zukunft eine gute Lösung für Sie sein. Ich habe einen Teil meines Codes gesehen, der schlecht war. Ich wusste nicht, wer es wann geschrieben hat. Ich konnte alle Änderungen in der Datei sehen, aber es war klar, dass der Code von einer anderen Datei in diese verschoben wurde. Ich wollte herausfinden, wer es überhaupt hinzugefügt hat.

Dazu habe ich Git bisect verwendet , wodurch ich schnell den Sünder finden konnte.

Ich lief git bisect startund dann git bisect bad, weil die ausgecheckte Revision das Problem hatte. Da ich nicht wusste, wann das Problem auftrat, zielte ich auf das erste Commit für das "Gute" ab git bisect good <initial sha>.

Dann suchte ich einfach im Repo nach dem schlechten Code. Als ich es fand, rannte ich git bisect badund als es nicht da war : git bisect good.

In ~ 11 Schritten hatte ich ~ 1000 Commits abgedeckt und das genaue Commit gefunden, bei dem das Problem eingeführt wurde. Ziemlich toll.


2

Ich bin mir nicht sicher, warum die akzeptierte Antwort in meiner Umgebung nicht funktioniert. Schließlich führe ich den folgenden Befehl aus, um das zu erhalten, was ich brauche

git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.