Comment exclure certains répertoires / fichiers de la recherche git grep

144

Existe-t-il un moyen d'exclure certains chemins / répertoires / fichiers lors de la recherche d'un référentiel git à l'aide de git grep? Quelque chose de similaire à l' --excludeoption de la grepcommande normale ?

J'ai besoin d'utiliser git grepparce que l'utilisation grepdirecte s'exécute trop lentement sur les grands dépôts git.

Yogeshwer Sharma
la source
Le faire sur bash serait une solution de contournement possible: stackoverflow.com/questions/216995/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
8
Cette fonctionnalité a été ajoutée dans la version 1.9.0 voir ma réponse ci
seulement

Réponses:

17

Ce n'est pas possible, mais cela a été discuté récemment . Solution de contournement proposée dans le lien:

Vous pouvez alors mettre *.dlldans un fichier .gitignore git grep --exclude-standard.

EDIT ne voyez que la réponse , puisque git 1.9.0 c'est possible.

CharlesB
la source
2
C'était vrai mais plus maintenant, c'est maintenant possible dans git. Voyez ce que devrait être la vraie réponse ci-dessous: stackoverflow.com/a/30084612/1391445
user1391445
206

Dans git 1.9.0, le "mot magique" a excludeété ajouté à pathspecs. Donc, si vous voulez rechercher foobardans tous les fichiers à l'exception de ceux qui correspondent, *.javavous pouvez faire:

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

Ou en utilisant la !"forme courte" pour exclure:

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

Notez que dans les versions git jusqu'à la v2.12, lorsque vous utilisez une exclusion pathspec, vous devez avoir au moins un "inclusif" pathspec. Dans les exemples ci-dessus, il s'agit du ./*(inclure récursivement tout sous le répertoire courant). Dans git v2.13, cette restriction a été levée et git grep foobar -- ':!*.java'fonctionne sans l' extension ./*.

Vous pouvez également utiliser quelque chose comme :(top)(forme courte:) :/pour tout inclure depuis le haut du dépôt. Mais alors vous voudrez probablement également ajuster votre exclusion pathspecpour qu'elle commence également par le haut: :/!*.java(sinon, cela n'exclurait que les *.javafichiers de votre répertoire actuel).

Il existe une bonne référence pour tous les «mots magiques» autorisés dans un pathspecat git-scm.com (ou juste git help glossary). Pour une raison quelconque, les documents sur kernel.org sont vraiment obsolètes même s'ils apparaissent souvent en premier dans les recherches Google.

seul
la source
4
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'pour exclure plusieurs répertoires entiers. Je ne pense pas que cela empêche la récursivité.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
Pour une utilisation fréquente, vous pouvez faire un alias git avec les exclusions: git config alias.mygrep '!git grep "$@" -- "${GIT_PREFIX}/*" ":!*.java*" #'. Alors juste git mygrep foobar. (Utilisation de l'alias shell # trick et current dir .)
medmunds
le problème que je ne peux pas résoudre avec cette solution est que les chemins signalés des fichiers sont relatifs à la racine WC. Donc, si je suis dans un sous-répertoire du WC, je ne peux pas simplement utiliser le chemin du (des) fichier (s) trouvé (s) tel quel (par exemple pour moins) mais je dois junc chemins communs. Y a-t-il une solution à cela (sans devoir m'employer)? [git bash sur win7]
elonderin le
1
@elonderin cette solution n'a rien à voir avec la façon dont les fichiers correspondants sont signalés. Mais je viens d'essayer un git grepet git ls-filesdes sous-répertoires et les deux rapportent les noms de fichiers par rapport au répertoire actuel (même lorsque vous utilisez le ':(top)'chemin include). Les deux commandes ont la --full-namepossibilité de rapporter les noms relatifs à la racine, mais c'est désactivé par défaut.
seulement le
1
Je n'utilise pas d'alias git, j'ai donc créé une fonction bash, mais peut-être qu'un alias git est préférable gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
Colin D
62

Mise à jour: pour git> = 1.9, il existe un support natif pour les modèles d'exclusion, voir la réponse d'une seule .

Cela peut sembler à l'envers, mais vous pouvez passer une liste de fichiers ne correspondant pas à votre modèle d'exclusion pour git grepaimer ceci:

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

grep -vrenvoie tous les chemins qui ne correspondent pas<exclude-pattern> . Notez que git ls-filesprend également un --excludeparamètre, mais qui n'est appliqué qu'aux fichiers non suivis .

kynan
la source
Merci pour cela! Git grep est tellement plus rapide que ack & co mais ne pas pouvoir exclure des chemins arbitraires était un peu trop gênant pour ainsi dire :)
Tomasz Zieliński
2
Malheureusement, mon dépôt contient beaucoup de fichiers. Quand j'essaye l'approche de @ kynan, j'obtiens: "-bash: / usr / bin / git: Liste d'arguments trop longue"
Benissimo
2
Cela devrait résoudre à la fois le problème "Liste d'arguments trop longue" de Benissimo et mon problème avec les caractères de nom de fichier interprétés par bash (comme []) ou les noms de fichiers contenant des espaces dans le référentiel: git ls-files | grep -v <exclue-pattern> | xargs -d '\ n' git grep <modèle> -
Scout
2
Ne vérifiez que la réponse de personne, il est peut-être possible de le faire entièrement dans (les versions modernes de) git maintenant.
David
Pourquoi les votes négatifs? Cette réponse s'applique toujours aux versions de git antérieures à 1.9. J'ai ajouté une note faisant référence à la réponse d'une seule personne.
kynan
5

Vous pouvez marquer des fichiers ou des répertoires comme binaires en créant un fichier d'attributs dans votre référentiel, par exemple

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

Les correspondances dans les fichiers binaires sont listées sans la ligne d'inclusion, par exemple

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

Avec l'exemple de @kynan comme base, j'ai créé ce script et l'ai mis dans mon chemin ( ~/bin/) sous la forme gg. Il utilise git grepmais évite certains types de fichiers spécifiés.

Dans notre repo, il y a beaucoup d'images, j'ai donc exclu les fichiers image, ce qui réduit le temps de recherche à 1/3 si je recherche tout le repo. Mais le script pourrait facilement être modifié pour exclure d'autres types de fichiers ou modèles de gel.

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

Note 1

Selon cela, il devrait être possible de nommer l'objet git-gget de pouvoir l'appeler comme une commande git régulière comme:

$ git gg searchstring

Mais je ne peux pas faire fonctionner cela. J'ai créé le script dans my ~/bin/et créé le git-gglien symbolique dans /usr/lib/git-core/.

Note 2

La commande ne peut pas être transformée en un shgit-alias normal car elle sera alors appelée à la racine du dépôt. Et ce n'est pas ce que je veux!

UlfR
la source