So schließen Sie bestimmte Verzeichnisse / Dateien von der Git Grep-Suche aus

144

Gibt es eine Möglichkeit, bestimmte Pfade / Verzeichnisse / Dateien beim Durchsuchen eines Git-Repositorys mit auszuschließen git grep? Etwas ähnliches wie die --excludeOption im normalen grepBefehl?

Ich muss verwenden, git grepda die grepdirekte Verwendung in großen Git-Repositories zu langsam läuft.

Yogeshwer Sharma
quelle
Dies auf Bash zu tun, wäre eine mögliche Problemumgehung
Ciro Santilli 19 冠状 病 六四 事件 法轮功
8
Diese Funktion wurde in 1.9.0 hinzugefügt, siehe meine Antwort unten
nur

Antworten:

204

In Git 1.9.0 wurde das "Zauberwort" excludezu pathspecs hinzugefügt . Wenn Sie also foobarin jeder Datei suchen möchten, mit Ausnahme derjenigen, die übereinstimmen *.java, können Sie Folgendes tun:

git grep foobar -- './*' ':(exclude)*.java'

Oder verwenden Sie die !"Kurzform" zum Ausschließen:

git grep foobar -- './*' ':!*.java'

Beachten Sie, dass in Git-Versionen bis Version 2.12 bei Verwendung eines Ausschlusses pathspecmindestens ein "Inklusiv" vorhanden sein muss pathspec. In den obigen Beispielen ist dies das ./*(rekursiv alles unter dem aktuellen Verzeichnis einschließen). In git v2.13 wurde diese Einschränkung aufgehoben und git grep foobar -- ':!*.java'funktioniert ohne die ./*.

Sie können auch etwas wie :(top)(Kurzform :) verwenden :/, um alles von oben in das Repo aufzunehmen. Aber dann möchten Sie wahrscheinlich auch Ihren Ausschluss so anpassen, dass pathspecer auch von oben beginnt: :/!*.java(Andernfalls werden nur *.javaDateien aus Ihrem aktuellen Verzeichnis ausgeschlossen).

Es gibt eine gute Referenz für alle "magischen Wörter", die in a pathspecbei git-scm.com (oder nur git help glossary) erlaubt sind . Aus irgendeinem Grund sind die Dokumente auf kernel.org wirklich veraltet, obwohl sie bei Google-Suchanfragen häufig an erster Stelle stehen.

nur keiner
quelle
4
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'um mehrere ganze Verzeichnisse auszuschließen. Ich denke nicht, dass es eine Rekursion verhindert.
Ciro Santilli 法轮功 冠状 病. 事件 法轮功
2
Für den häufigen Gebrauch können Sie einen Git-Alias ​​mit den folgenden Ausschlüssen erstellen : git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'. Dann einfach git mygrep foobar. (Mit Alias Shell # Trick und aktuellem
Verzeichnis
Das Problem, das ich mit dieser Lösung nicht lösen kann, ist, dass die gemeldeten Pfade der Dateien relativ zum WC-Stamm sind. Wenn ich mich also in einem Unterverzeichnis des WC befinde, kann ich den Pfad der gefundenen Datei (en) nicht unverändert verwenden (z. B. für weniger), sondern muss gemeinsame Pfade verknüpfen. Gibt es eine Lösung dafür (ohne mich selbst beschäftigen zu müssen)? [Git Bash auf Win7]
Elonderin
1
@elonderin Diese Lösung hat nichts damit zu tun, wie die übereinstimmenden Dateien gemeldet werden. Aber ich habe gerade ein git grepund git ls-filesaus Unterverzeichnissen ausprobiert und beide melden Dateinamen relativ zum aktuellen Verzeichnis (selbst wenn Sie die ':(top)'Include-Pfadspezifikation verwenden). Beide Befehle haben die --full-nameOption, Namen relativ zum Stamm zu melden, dies ist jedoch standardmäßig deaktiviert.
Nur
1
Ich benutze keine git Aliase so dass ich ein Bash - Funktion gemacht, aber möglicherweise ein git alias ist besser gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Colin D
62

Update: Für git> = 1.9 gibt es native Unterstützung für Ausschlussmuster, siehe nur die Antwort von one .

Dies mag rückwärts erscheinen, aber Sie können eine Liste von Dateien übergeben, die nicht mit Ihrem Ausschlussmuster übereinstimmen, um Folgendes zu git grepmögen:

git grep <pattern> -- `git ls-files | grep -v <exclude-pattern>`

grep -vGibt jeden Pfad zurück, der nicht übereinstimmt <exclude-pattern>. Beachten Sie, dass dies git ls-filesauch einen --excludeParameter erfordert, der jedoch nur auf nicht verfolgte Dateien angewendet wird .

kynan
quelle
Danke dafür! Git grep ist so viel schneller als ack & co, aber beliebige Pfade nicht ausschließen zu können, war sozusagen etwas zu unpraktisch :)
Tomasz Zieliński
2
Leider hat mein Repo viele Dateien. Wenn ich @ kynans Ansatz versuche, erhalte ich: "-bash: / usr / bin / git: Argumentliste zu lang"
Benissimo
2
Dies sollte sowohl das Problem "Argumentliste zu lang" von Benissimo als auch mein Problem mit Dateinamenzeichen lösen, die von bash (wie []) interpretiert werden, oder Dateinamen, die Leerzeichen im Repository enthalten: git ls-files | grep -v <Ausschlussmuster> | xargs -d '\ n' git grep <Muster> -
Scout
2
Überprüfen Sie nur die Antwort von niemandem, es ist möglicherweise möglich, dies jetzt vollständig innerhalb (moderner Versionen von) git zu tun.
David
Warum die Abstimmungen? Diese Antwort gilt weiterhin für Git-Versionen vor 1.9. Ich habe eine Notiz hinzugefügt, die sich nur auf die Antwort von jemandem bezieht.
Kynan
5

Sie können Dateien oder Verzeichnisse als binär markieren, indem Sie eine Attributdatei in Ihrem Repository erstellen, z

$ cat .git/info/attributes 
directory/to/ignore/*.* binary
directory/to/ignore/*/*.* binary
another_directory/to/also/ignore/*.* binary

Übereinstimmungen in Binärdateien werden ohne die Einschlusszeile aufgelistet, z

$ git grep "bar"
Binary file directory/to/ignore/filename matches
other_directory/other_filename:      foo << bar - bazz[:whatnot]
coberlin
quelle
2

Mit dem Beispiel von @kynan als Basis habe ich dieses Skript erstellt und es in meinen Pfad ( ~/bin/) als eingefügt gg. Es werden git grepeinige angegebene Dateitypen verwendet, aber vermieden.

In unserem Repo gibt es viele Bilder, daher habe ich die Bilddateien ausgeschlossen, und dies verkürzt die Serchtime auf 1/3, wenn ich das gesamte Repo durchsuche. Das Skript kann jedoch leicht geändert werden, um andere Dateitypen oder Geleralmuster auszuschließen.

#!/bin/bash                                                                    
#                                                                              
# Wrapper of git-grep that excludes certain filetypes.                         
# NOTE: The filetypes to exclude is hardcoded for my specific needs.           
#                                                                              
# The basic setup of this script is from here:                                 
#   https://stackoverflow.com/a/14226610/42580                                  
# But there is issues with giving extra path information to the script         
# therefor I crafted the while-thing that moves path-parts to the other side   
# of the '--'.                                                                 

# Declare the filetypes to ignore here                                         
EXCLUDES="png xcf jpg jpeg pdf ps"                                             

# Rebuild the list of fileendings to a good regexp                             
EXCLUDES=`echo $EXCLUDES | sed -e 's/ /\\\|/g' -e 's/.*/\\\.\\\(\0\\\)/'`      

# Store the stuff that is moved from the arguments.                            
moved=                                                                         

# If git-grep returns this "fatal..." then move the last element of the        
# arg-list to the list of files to search.                                     
err="fatal: bad flag '--' used after filename"                                 
while [ "$err" = "fatal: bad flag '--' used after filename" ]; do              
    {                                                                          
        err=$(git grep "$@" -- `git ls-files $moved | grep -iv "$EXCLUDES"` \  
            2>&1 1>&3-)                                                        
    } 3>&1                                                                     

    # The rest of the code in this loop is here to move the last argument in   
    # the arglist to a separate list $moved. I had issues with whitespace in   
    # the search-string, so this is loosely based on:                          
    #   http://www.linuxjournal.com/content/bash-preserving-whitespace-using-set-and-eval
    x=1                                                                        
    items=                                                                     
    for i in "$@"; do                                                          
        if [ $x -lt $# ]; then                                                 
            items="$items \"$i\""                                              
        else                                                                   
            moved="$i $moved"                                                  
        fi                                                                     
        x=$(($x+1))                                                            
    done                                                                       
    eval set -- $items                                                         
done                                                                           
# Show the error if there was any                                              
echo $err                                                                      

Anmerkung 1

Nach dieser soll es möglich sein , die Sache zu nennen git-ggund in der Lage es als regulärer git Befehl zu nennen wie:

$ git gg searchstring

Aber ich kann das nicht zum Laufen bringen. Ich habe das Skript in meinem erstellt ~/bin/und einen git-ggSymlink in erstellt /usr/lib/git-core/.

Anmerkung 2

Der Befehl kann nicht zu einem regulären shGit-Alias ​​gemacht werden, da er dann im Stammverzeichnis des Repos aufgerufen wird. Und das will ich nicht!

UlfR
quelle