Wie durchsuche ich alle Git- und Mercurial-Commits im Repository nach einer bestimmten Zeichenfolge?

287

Ich habe ein Git-Repository mit wenigen Zweigen und baumelnden Commits. Ich möchte alle diese Commits im Repository nach einer bestimmten Zeichenfolge durchsuchen.

Ich weiß, wie man ein Protokoll aller Commits in der Geschichte erstellt, aber diese enthalten keine Zweige oder baumelnden Blobs, sondern nur die Geschichte von HEAD. Ich möchte sie alle bekommen, um ein bestimmtes Commit zu finden, das verlegt wurde.

Ich würde auch gerne wissen, wie das in Mercurial geht, da ich über den Wechsel nachdenke.

Josip
quelle

Antworten:

331

Sie können baumelnde Commits mit sehen git log -g.

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

Sie können dies also tun, um eine bestimmte Zeichenfolge in einer baumelnden Festschreibungsnachricht zu finden:

git log -g --grep=search_for_this

Wenn Sie alternativ die Änderungen nach einer bestimmten Zeichenfolge durchsuchen möchten, können Sie auch die Suchoption für Spitzhacken "-S" verwenden:

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 fügt die Option -G hinzu , mit der Sie -G <regexp> übergeben können, um festzustellen, wann eine Zeile mit <regexp> verschoben wurde, was -S nicht kann. -S zeigt Ihnen nur an, wann sich die Gesamtzahl der Zeilen mit der Zeichenfolge geändert hat (dh Hinzufügen / Entfernen der Zeichenfolge).

Schließlich können Sie gitk verwenden, um die baumelnden Commits zu visualisieren mit:

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

Verwenden Sie dann die Suchfunktionen, um nach der falsch platzierten Datei zu suchen. All diese Arbeiten setzen voraus, dass das fehlende Commit nicht "abgelaufen" ist und Müll gesammelt wurde. Dies kann passieren, wenn es 30 Tage lang baumelt und Sie Reflogs ablaufen lassen oder einen Befehl ausführen, der sie abläuft.

richq
quelle
4
Anstatt "git grep" für eine (möglicherweise große) Anzahl von Commits auszuführen, die alle Commits finden würden, die irgendwo in einem Projekt "search_for_this" haben, verwenden Sie möglicherweise die sogenannte "pickaxe" -Suche, dh die Option "-S", um das Protokoll zu erstellen Hiermit werden Commits gefunden, die eine bestimmte Zeichenfolge eingeführt oder entfernt haben, oder genauer gesagt, wenn sich die Anzahl der Vorkommen einer bestimmten Zeichenfolge geändert hat.
Jakub Narębski
5
Sie können mehrere Zweige angeben oder die Option '--all' verwenden, z. B. 'git log --grep = "Zeichenfolge in einer Festschreibungsnachricht" --all'
Jakub Narębski
Dies erlaubte mir nur, ein verlorenes Commit für 2 Tage Arbeit zu finden. Total meinen Arsch gerettet, danke!
Mike Chamberlain
2
Ich bin auf einige Situationen gestoßen, in denen ich Commits in meiner Datenbank hatte, aber nicht in meinem Reflog. Ich weiß nicht, wie häufig das ist. Ich habe verschiedene HG / Git-Brücken ausprobiert. Ich denke, es kann auch bei heruntergefallenen Verstecken auftreten. In jedem Fall funktioniert dieser Alias ​​gut, um diese Fälle zu !git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk
erfassen
Beachten Sie, dass das Durchsuchen von Notizobjekten nicht enthalten ist. Das wurde noch nicht implementiert: git.661346.n2.nabble.com/…
Antony Stubbs
54

In Mercurial verwenden Sie, um hg log --keywordin den Festschreibungsnachrichten nach Schlüsselwörtern hg log --userzu suchen und nach einem bestimmten Benutzer zu suchen. Siehe hg help logfür andere Möglichkeiten , um das Protokoll zu begrenzen.

Martin Geisler
quelle
36
Josip schrieb, dass er erwägt, zu Mercurial zu wechseln, und dass er auch gerne hören würde, wie es dort gemacht wird.
Martin Geisler
1
hg log -kSuchvorgänge schreiben Benutzernamen und Dateinamen auch in Änderungssätzen fest (ich sehe das in command.py:log), was eines der wenigen Dinge ist, die ich in hg nicht verstehe. Es sollte separate Optionen zum Suchen in Festschreibungsnachrichten und Dateinamen geben. Scheint hg log --template '{desc}\n'|grepder sichere Weg zu sein.
Geoffrey Zheng
@GeoffreyZheng: Es gibt Möglichkeiten, das zu tun. Siehe "hg help revsets", insbesondere die Funktionen desc (), user () und file (). Für die meisten dieser Verhaltensweisen gibt es auch hg-Protokollschalter. Nach meiner Erfahrung ist -k / keyword () normalerweise die hilfreichste Methode, um nach Dingen zu suchen.
Kevin Horn
Wie durchsucht man den tatsächlich festgeschriebenen Dateiinhalt ... die Unterschiede? Ich weiß, dass es eine langsame Suche wäre, aber ich möchte eine gründliche Suche nach einem fehlenden Funktionsnamen durchführen.
Jonathan
Oh hier ist es:hg grep --all <term>
Jonathan
24

Neben der Richq-Antwort zur Verwendung von git log -g --grep=<regexp>oder git grep -e <regexp> $(git log -g --pretty=format:%h): Schauen Sie sich die folgenden Blog-Beiträge von Junio ​​C Hamano an, dem aktuellen Git-Betreuer


Zusammenfassung

Sowohl git grep als auch git log --grep sind zeilenorientiert , da sie nach Linien suchen, die dem angegebenen Muster entsprechen.

Sie können Commits verwenden git log --grep=<foo> --grep=<bar>(oder dies wird git log --author=<foo> --grep=<bar>intern in zwei übersetzt --grep), um Commits zu finden, die mit einem der Muster übereinstimmen (implizite ODER semantische).

Aufgrund der zeilenorientierten Ausrichtung besteht die nützliche UND- Semantik git log --all-match --grep=<foo> --grep=<bar>darin, ein Commit zu finden , bei dem sowohl die erste als auch die zweite Zeile irgendwo übereinstimmen.

Mit git grepIhnen mehrere Muster kombinieren können (alle , die das verwenden müssen , -e <regexp>Form) mit --or(was der Standard ist), --and, --not, (und ). Für grep --all-matchbedeutet, dass die Datei Zeilen haben muss, die mit jeder der Alternativen übereinstimmen.

Jakub Narębski
quelle
Hey Jakub, hast du etwas dagegen, Zitate / Zusammenfassungen aus diesen Blog-Posts hier zu integrieren? Sieht aus wie eine der Vintage-Nur-Link-Antworten im Moment.
Nathan Tuggy
11

Aufbauend auf der Antwort von rq fand ich, dass diese Zeile das tut, was ich will:

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

Hiermit werden die Festschreibungs-ID, der Dateiname und die übereinstimmende Zeile wie folgt angezeigt:

91ba969:testFile:this is a test

... Ist jemand damit einverstanden, dass dies eine gute Option wäre, um in den Standardbefehl git grep aufgenommen zu werden?

Sam Hiatt
quelle
5

Jeder Befehl, der Referenzen als Argumente verwendet, akzeptiert die --allin der Manpage dokumentierte Option git rev-listwie folgt:

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

So werden beispielsweise git log -Sstring --allalle Commits angezeigt, die erwähnt werden stringund auf die über einen Zweig oder ein Tag zugegriffen werden kann (ich gehe davon aus, dass Ihre baumelnden Commits mindestens mit einem Tag benannt sind).

adl
quelle
3
Dies scheint nicht der Fall zu sein git grep, wenn es so --allaussieht, als würde es übersetzt / verwendet als --all-match. Das sieht für mich nach einem Fehler aus. Mit Git 1.7.2.3 (mit $(git rev-list --all)Works).
Blueyed
5

Mit Mercurial machst du a

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

Es gibt andere Optionen, die den Bereich der gesuchten Revisionen einschränken.

Yawar
quelle
1
Ich mag auch die Flaggehg grep --all
Jonathan
2

Ich weiß nichts über Git, aber in Mercurial würde ich die Ausgabe von hg log einfach an ein sed / perl / any-Skript weiterleiten, um nach dem zu suchen, wonach Sie suchen. Sie können die Ausgabe des hg-Protokolls mithilfe einer Vorlage oder eines Stils anpassen, um die Suche zu vereinfachen, wenn Sie dies wünschen.

Dies schließt alle benannten Zweige im Repo ein. Mercurial hat nicht so etwas wie baumelnde Blobs afaik.

Kurt Schelfthout
quelle
1
Ich verstehe nicht, wie relevant diese Antwort für das angegebene Problem ist.
Jribeiro
3
Es ist eine Antwort auf die Frage an Mercurial, nach der die ursprüngliche Frage im letzten Absatz fragt.
Kurt Schelfthout
1

Um nur eine weitere Lösung hinzuzufügen, die noch nicht erwähnt wurde, musste ich sagen, dass die Verwendung des grafischen Suchfelds von gitg die einfachste Lösung für mich war. Es wird das erste Vorkommen ausgewählt und Sie können das nächste mit Strg-G finden.

icarito
quelle
1

Ein Befehl in Git, von dem ich denke, dass es viel einfacher ist, einen String zu finden:

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

funktioniert in Git 2.0.4

Adriano Rosa
quelle