Come escludere determinate directory / file dalla ricerca di git grep


144

C'è un modo per escludere determinati percorsi / directory / file durante la ricerca in un repository git usando git grep? Qualcosa di simile --excludeall'opzione nel grepcomando normale ?

Devo usare git grepperché usare grepdirettamente gira troppo lentamente su grandi repository git.



8
Questa funzione è stata aggiunta in 1.9.0 vedere la mia risposta di seguito
solo

Risposte:



206

In git 1.9.0 la "parola magica" è excludestata aggiunta a pathspecs. Quindi se vuoi cercare foobarin ogni file tranne quelli corrispondenti *.javapuoi fare:

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

O usando la !"forma abbreviata" per escludere:

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

Nota che nelle versioni git fino alla v2.12, quando usi un'esclusione pathspec, devi avere almeno un "inclusivo" pathspec. Negli esempi precedenti questo è il ./*(includi ricorsivamente tutto nella directory corrente). In git v2.13 questa limitazione è stata revocata e git grep foobar -- ':!*.java'funziona senza ./*.

È inoltre possibile utilizzare qualcosa di simile :(top)(forma abbreviata:) :/per includere tutto dalla parte superiore del repository. Ma probabilmente vorrai anche modificare la tua esclusione pathspecper iniziare anche dall'alto: :/!*.java(altrimenti escluderebbe solo i *.javafile dalla directory corrente).

C'è un buon riferimento per tutte le "parole magiche" consentite in a pathspecsu git-scm.com (o semplicemente git help glossary). Per qualche ragione, i documenti su kernel.org sono davvero obsoleti anche se spesso vengono prima nelle ricerche su Google.


4
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'per escludere più intere directory. Non penso che prevenga la ricorsione.
Ciro Santilli 23 冠状 病 六四 事件 法轮功

2
Per un uso frequente, è possibile effettuare un alias git con le esclusioni: git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'. Quindi solo git mygrep foobar. (Usando l'alias shell # trick e dir corrente )
medmunds

il problema che non posso risolvere con questa soluzione è che i percorsi segnalati dei file sono relativi alla radice WC. Quindi, se mi trovo in una sottodirectory del WC, non posso semplicemente usare il percorso dei file trovati così com'è (ad esempio per meno) ma devo congiungere percorsi comuni. C'è una soluzione a questo (senza dover sedurre me stesso)? [git bash su win7]
elonderin,

1
@elonderin questa soluzione non ha nulla a che fare con il modo in cui vengono riportati i file corrispondenti. Ma ho appena provato a git grepe git ls-filesdalle sottodirectory ed entrambi riportano i nomi dei file relativi alla directory corrente (anche quando si utilizza ':(top)'include pathspec). Entrambi i comandi hanno l' --full-nameopzione di riportare i nomi relativi alla radice, ma questo è disattivato per impostazione predefinita.
solo il

1
Non uso alias git quindi ho fatto una funzione bash, ma forse un alias git è meglio gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Colin D

62

Aggiornamento: per git> = 1.9 esiste un supporto nativo per i pattern di esclusione, vedi solo la risposta .

Questo può sembrare all'indietro, ma puoi passare un elenco di file che non corrispondono al tuo modello di esclusione in git grepquesto modo:

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

grep -vrestituisce ogni percorso non corrispondente <exclude-pattern>. Si noti che git ls-filesaccetta anche un --excludeparametro, ma che viene applicato solo ai file non tracciati .


Grazie per questo! Git grep è molto più veloce di ack & co, ma non poter escludere percorsi arbitrari è stato un po 'troppo scomodo per così dire :)
Tomasz Zieliński,

2
Purtroppo il mio repository ha molti file. Quando provo l'approccio di @ kynan ottengo: "-bash: / usr / bin / git: lista degli argomenti troppo lunga"
Benissimo,

2
Questo dovrebbe risolvere sia il problema "Elenco argomenti troppo lungo" di Benissimo sia il mio problema con i caratteri del nome file interpretati da bash (come []) o nomi di file contenenti spazi nel repository: git ls-files | grep -v <exclue-pattern> | xargs -d '\ n' git grep <pattern> -
Esploratore

2
Controlla solo la risposta di nessuno, probabilmente è possibile farlo completamente all'interno di (git versioni moderne di) git ora.
David,

Perché i downvotes? Questa risposta si applica ancora alle versioni git precedenti alla 1.9. Ho aggiunto una nota che fa riferimento alla sola risposta.
kynan il

5

È possibile contrassegnare file o directory come binari creando un file di attributi nel proprio repository, ad es

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

Le corrispondenze nei file binari sono elencate senza la riga inclusa, ad es

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

2

Con l'esempio di @kynan come base ho creato questo script e l'ho messo nel mio percorso ( ~/bin/) come gg. Lo usagit grep ma evita alcuni tipi di file specificati.

Nel nostro repository ci sono molte immagini, quindi ho escluso i file di immagine e questo riduce il tempo di serch a 1/3 se cerco l'intero repository. Ma lo script potrebbe essere facilmente modificato per escludere altri filestypes o geleralpatterns.

#!/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                                                                      

Nota 1

In base a ciò dovrebbe essere possibile nominare la cosa git-gged essere in grado di chiamarla come un normale comando git come:

$ git gg searchstring

Ma non riesco a farlo funzionare. Ho creato lo script nel mio ~/bin/e creato un git-ggcollegamento simbolico in /usr/lib/git-core/.

Nota 2

Il comando non può essere trasformato in un shgit-alias regolare poiché verrà quindi invocato alla radice del repository. E non è quello che voglio!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.