Ist es möglich, in allen Zweigen eines Git-Projekts eine 'grep-Suche' durchzuführen?

Antworten:

188

Die Frage " Wie kann man festgeschriebenen Code in der Git-Historie durchsuchen? " Empfiehlt:

 git grep <regexp> $(git rev-list --all)

Das durchsucht alle Commits, die alle Zweige enthalten sollten.

Eine andere Form wäre:

git rev-list --all | (
    while read revision; do
        git grep -F 'yourWord' $revision
    done
)

Weitere Beispiele finden Sie in diesem Artikel :

Ich habe das oben genannte bei einem Projekt ausprobiert, das groß genug ist, dass sich git über die Argumentgröße beschwert. Wenn Sie also auf dieses Problem stoßen, gehen Sie wie folgt vor:

git rev-list --all | (while read rev; do git grep -e <regexp> $rev; done)

(Siehe eine Alternative im letzten Abschnitt dieser Antwort unten)

Vergessen Sie diese Einstellungen nicht, wenn Sie sie möchten:

# Allow Extended Regular Expressions
git config --global grep.extendRegexp true
# Always Include Line Numbers
git config --global grep.lineNumber true

Dieser Alias ​​kann auch helfen:

git config --global alias.g "grep --break --heading --line-number"

Hinweis: Chernjie schlug vor, dass dies git rev-list --allein Overkill ist.

Ein verfeinerter Befehl kann sein:

git branch -a | tr -d \* | xargs git grep <regexp>

Damit können Sie nur Zweige durchsuchen (einschließlich entfernter Zweige).

Sie können sogar einen Bash / Zsh-Alias ​​dafür erstellen:

alias grep_all="git branch -a | tr -d \* | xargs git grep"
grep_all <regexp>

Update August 2016: RM empfiehlt in den Kommentaren

Ich habe ein " fatal: bad flag '->' used after filename" bekommen, als ich die git branchVersion ausprobiert habe . Der Fehler war mit einer HEADAliasing-Notation verbunden.

Ich habe es gelöst, indem ich ein sed '/->/d'in die Pipe zwischen dem trund dem xargsBefehl eingefügt habe.

 git branch -a | tr -d \* | sed '/->/d' | xargs git grep <regexp>

Das ist:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>
VonC
quelle
Es ist keine gute Idee, die Ausgabe von git branchin tr oder sed zu leiten. git branchist ein Porzellankommando für den menschlichen Verzehr. Bevorzugte Alternativen finden Sie unter stackoverflow.com/a/3847586/2562319 .
Jbyler
@ jbyler Guter Punkt. Ironischerweise habe ich die Antwort lange vor dieser Antwort auf Porzellan gepostet: stackoverflow.com/a/6978402/6309 . Und ich benutze es zum Beispiel in stackoverflow.com/a/19206916/6309 .
VonC
Ja, schön. Wenn ich mir die anderen Antworten ansehe, denke ich, dass die Antwort von @errordeveloper die sauberste ist: stackoverflow.com/a/21284342/2562319 : "git grep <regexp> $ (git für-jeden-ref --format = '% (refname) 'refs /) "
jbyler
1
Gibt es eine Möglichkeit, den Namen des Zweigs anzuzeigen, der der Suche entspricht?
Franksands
63

git log Dies kann eine effektivere Methode sein, um in allen Zweigen nach Text zu suchen, insbesondere wenn es viele Übereinstimmungen gibt und Sie zuerst neuere (relevante) Änderungen sehen möchten.

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

Diese Protokollbefehle listen Commits auf, mit denen die angegebene Suchzeichenfolge / Regex (im Allgemeinen) zuerst hinzugefügt oder entfernt wird. Die -pOption bewirkt, dass das relevante Diff dort angezeigt wird, wo das Muster hinzugefügt oder entfernt wurde, sodass Sie es im Kontext sehen können.

Nachdem Sie ein relevantes Commit gefunden haben, das den gesuchten Text hinzufügt (z. B. 8beeff00d), suchen Sie die Zweige, die das Commit enthalten:

git branch -a --contains 8beeff00d
Edward Anderson
quelle
22

Ich fand das am nützlichsten:

git grep -i foo `git for-each-ref --format='%(refname)' refs/`

Sie müssen die letzten Argumente anpassen, je nachdem, ob Sie nur entfernte oder lokale Zweige betrachten möchten, dh:

  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/remotes)
  • git grep -i foo $(git for-each-ref --format='%(refname)' refs/heads)

Der von mir erstellte Alias ​​sieht folgendermaßen aus:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'
Fehlerentwickler
quelle
1
Interessanter Alias. +1. Genauer als in meiner Antwort.
VonC
Wie kann Ihr Alias ​​für die Phrasensuche verwendet werden? Wenn ich "foo bar" als Parameter übergebe, erhalte ich: fatal: mehrdeutiges Argument 'bar': unbekannte Revision oder Pfad nicht im Arbeitsbaum. Verwenden Sie '-', um Pfade von Revisionen zu trennen
jutky
Versuchen Sie, dem Raum zu entkommen: "foo \ bar"
Garry Gomez
Dies soll eindeutig die akzeptierte Antwort sein;) Ich habe sie erweitert, um nur nach den neuesten Zweigen meines Projekts zu suchen (Ich habe mehr als 500, frage nicht, und jeder Grep dauert ungefähr 4 Sekunden, also möchte oder brauche ich nicht über mehr als die beispielsweise 100 neuesten von ihnen zu suchen). Dafür habe ich das git for-each-refmit aktualisiert --sort=-committerdate --count=100! Danke für die ursprüngliche Idee!
Vser
6

Es gibt zwei Möglichkeiten: Bash- oder Git-Aliase

Hier sind drei Befehle:

  1. git grep-branch - Suche in allen Filialen lokal & remote
  2. git grep-branch-local - Suche nur in lokalen Filialen
  3. git grep-branch-remote - Nur entfernte Zweige

Die Verwendung ist die gleiche wie git grep

git grep-branch "find my text"
git grep-branch --some-grep-options "find my text"

GREP mit: Git-Aliasen

Datei ~ / .gitconfig

Befehle sollten manuell zur ~/.gitconfigDatei hinzugefügt werden , da git config --global aliasSie den von Ihnen hinzugefügten komplexen Code auswerten und durcheinander bringen.


[alias]
    grep-branch        = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | xargs git grep $@; };f "
    grep-branch-remote = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' | grep '^remotes' | xargs git grep $@; };f"
    grep-branch-local  = "!f(){ git branch -a | sed -e 's/[ \\*]*//' | grep -v -e '\\->' -e '^remotes' | xargs git grep $@;  };f "

Hinweis: Wenn Sie Aliase hinzufügen und diese nicht ausgeführt werden können - überprüfen Sie die Backslashes \, für die \\im Vergleich zu Bash- Befehlen möglicherweise ein zusätzliches Escape erforderlich ist .

  • git branch -a - Alle Zweige anzeigen;
  • sed -e 's/[ \\*]*//'- Trim Leerzeichen (von branch -a) und * (Name des aktiven Zweigs haben es);
  • grep -v -e '\\->'- Ignorieren Sie komplexe Namen wie remotes/origin/HEAD -> origin/master;
  • grep '^remotes' - Holen Sie sich alle Remote-Filialen;
  • grep -v -e '^remotes'- Holen Sie sich Filialen außer Remote-Filialen;

Beispiel git grep-branch-local -n getTastyCookies

-n Stellen Sie die Zeilennummer den übereinstimmenden Zeilen voran.

[user@pc project]$ git grep-branch-local -n getTastyCookies

dev:53:modules/factory/getters.php:function getTastyCookies($user);
master:50:modules/factory/getters.php:function getTastyCookies($user)

Die aktuelle Struktur ist:

: - Trennzeichen

  1. Ast: dev
  2. Zeilennummer: 53
  3. Dateipfad: modules/factory/getters.php
  4. Übereinstimmende Linie: function getTastyCookies($user)

GREP mit: BASH

Wie Sie wissen sollten: Bash-Befehle sollten in .shSkripten gespeichert oder in einer Shell ausgeführt werden.

Nur lokale Niederlassungen

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' -e '^remotes' | xargs git grep "TEXT"

Nur entfernte Zweige

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | grep '^remotes' | xargs git grep "TEXT"

Lokale und entfernte Niederlassungen

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"
Devaldo
quelle
git grep-branch "find my text"fatal: ambiguous argument 'client': both revision and filename
Hört sich
Warum immer verwenden -a, die alle Zweige zeigt? Ich würde vorschlagen, Optionen für den git branchBefehl zu verwenden, um Klammern zu trennen. Wenn Sie sich lokale Niederlassungen ansehen, gibt es nur eine einzige *, sodass Sie nicht für sed entkommen müssen. Also: nur git branch | sed -e 's/*/ /' | xargs git grep "TEXT"für lokale Filialen, nur git branch -r | grep -v -- "->" | xargs git grep "TEXT"für entfernte Filialen und git branch -a | grep -v -- "->" | xargs git grep "TEXT"für alle Filialen
Jalanb
4

So mache ich das:

git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
William Entriken
quelle
2
Die einzige Lösung, die für mich unter Windows (in Git Bash) funktioniert hat
Ivan
4

Wenn Sie einem Commit einen SHA-1-Hashwert geben, git grepsuchen Sie ihn anstelle der Arbeitskopie.

Um alle Zweige zu durchsuchen, können Sie alle Bäume mit abrufen git rev-list --all. Setzen Sie alles mit

git grep "regexp" $(git rev-list --all)

... und Geduld haben

CharlesB
quelle