Est-il possible d'effectuer une 'recherche grep' dans toutes les branches d'un projet Git?

138

Est-il possible de s'exécuter git grepdans toutes les branches d'un projet provenant d'un contrôle Git? Ou y a-t-il une autre commande à exécuter?

epsilones
la source
4
duplication possible de Utilisation de git, comment pourrais-je rechercher une chaîne dans toutes les branches?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

189

La question " Comment grep (rechercher) du code commis dans l'historique git? " Recommande:

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

Cela parcourt tous les commits, qui devraient inclure toutes les branches.

Une autre forme serait:

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

Vous pouvez trouver encore plus d'exemples dans cet article :

J'ai essayé ce qui précède sur un projet suffisamment grand pour que git se soit plaint de la taille de l'argument, donc si vous rencontrez ce problème, faites quelque chose comme:

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

(voir une alternative dans la dernière section de cette réponse, ci-dessous)

N'oubliez pas ces paramètres, si vous les voulez:

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

Cet alias peut également aider:

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

Remarque: chernjie a suggéré que git rev-list --allc'est une exagération.

Une commande plus raffinée peut être:

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

Ce qui vous permettra de rechercher uniquement les branches (y compris les branches distantes)

Vous pouvez même créer un alias bash / zsh pour cela:

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

Mise à jour août 2016: RM recommande dans les commentaires

J'ai eu un " fatal: bad flag '->' used after filename" en essayant la git branchversion. L'erreur était associée à une HEADnotation d'alias.

Je l'ai résolu en ajoutant un sed '/->/d'dans le tuyau, entre les tret les xargscommandes.

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

C'est:

alias grep_all="git branch -a | tr -d \* | sed '/->/d' | xargs git grep"
grep_all <regexp>
VonC
la source
Ce n'est pas une bonne idée de diriger la sortie de git branchdans tr ou sed; git branchest une commande en porcelaine destinée à la consommation humaine. Voir stackoverflow.com/a/3847586/2562319 pour les alternatives préférées.
jbyler
@jbyler Bon point. Ironiquement, j'ai posté la réponse sur la porcelaine bien avant cette réponse: stackoverflow.com/a/6978402/6309 . Et je l'utilise par exemple dans stackoverflow.com/a/19206916/6309 .
VonC
Ouais, bien. En regardant à travers les autres réponses, je pense que la réponse de @errordeveloper est la plus propre: stackoverflow.com/a/21284342/2562319 : "git grep <regexp> $ (git for-each-ref --format = '% (refname) 'refs /) "
jbyler
1
Existe-t-il un moyen d'afficher le nom de la branche qui correspond à la recherche?
franksands
63

git log peut être un moyen plus efficace de rechercher du texte dans toutes les branches, surtout s'il y a beaucoup de correspondances, et que vous voulez d'abord voir les modifications les plus récentes (pertinentes).

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

Ces commandes de journal répertorient les commits qui ajoutent ou suppriment la chaîne de recherche / expression régulière donnée, (généralement) plus récente en premier. L' -poption permet d'afficher le diff pertinent à l'endroit où le modèle a été ajouté ou supprimé, afin que vous puissiez le voir dans son contexte.

Après avoir trouvé un commit pertinent qui ajoute le texte que vous recherchiez (par exemple 8beeff00d), trouvez les branches qui contiennent le commit:

git branch -a --contains 8beeff00d
Edward Anderson
la source
22

J'ai trouvé cela très utile:

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

Vous auriez besoin d'ajuster les derniers arguments selon que vous ne voulez regarder que les branches distantes ou locales, c'est-à-dire:

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

L'alias que j'ai créé ressemble à ceci:

grep-refs = !sh -c 'git grep "$0" "$@" "$(git for-each-ref --format=\"%(refname)\"" refs/)'
développeur d'erreurs
la source
1
Alias ​​intéressant. +1. Plus précis que dans ma réponse.
VonC le
Comment faire fonctionner votre alias pour la recherche de phrases? Quand je passe "foo bar" comme paramètre, j'obtiens: fatal: argument ambigu "bar": révision inconnue ou chemin non dans l'arbre de travail. Utilisez '-' pour séparer les chemins des révisions
jutky
Essayez d'échapper à l'espace: "foo \ bar"
Garry Gomez
Ce sera clairement la réponse acceptée;) Je l'ai développé pour rechercher uniquement dans les dernières branches de mon projet (Vous avez plus de 500, ne demandez pas, et chaque grep prend environ 4 secondes, donc je ne veux ni n'en ai besoin pour rechercher plus de, disons, 100 derniers d'entre eux). Pour cela, j'ai mis à jour le git for-each-refavec --sort=-committerdate --count=100! Merci pour l'idée originale!
Vser le
6

Il est possible de le faire de deux manières courantes: alias Bash ou Git

Voici trois commandes:

  1. git grep-branch - Recherche dans toutes les succursales locales et distantes
  2. git grep-branch-local - Recherche dans les succursales locales uniquement
  3. git grep-branch-remote - Succursales distantes uniquement

L'utilisation est la même que git grep

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

GREP utilisant: alias Git

Fichier ~ / .gitconfig

Les commandes doivent être ajoutées manuellement au ~/.gitconfigfichier, car git config --global aliasévaluer le code complexe que vous ajoutez et le gâcher.


[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 "

Remarque: lorsque vous ajoutez des alias et qu'ils ne s'exécutent pas - vérifiez les antislashs, \ils peuvent nécessiter un échappement supplémentaire \\par rapport aux commandes bash .

  • git branch -a - Afficher toutes les branches;
  • sed -e 's/[ \\*]*//'- Coupez les espaces (de branch -a) et * (le nom de la branche active l'a);
  • grep -v -e '\\->'- Ignorez les noms complexes comme remotes/origin/HEAD -> origin/master;
  • grep '^remotes' - Obtenez toutes les branches distantes;
  • grep -v -e '^remotes'- Obtenez des succursales sauf les succursales distantes;

Exemple git grep-branch-local -n getTastyCookies

-n Préfixez le numéro de ligne aux lignes correspondantes.

[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)

La structure actuelle est:

: - Séparateur

  1. Branche: dev
  2. Numéro de ligne: 53
  3. Chemin du fichier: modules/factory/getters.php
  4. Ligne assortie: function getTastyCookies($user)

GREP utilisant: BASH

Comme vous devez le savoir: les commandes Bash doivent être stockées dans des .shscripts ou exécutées dans un shell.

Succursales locales uniquement

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

Succursales distantes uniquement

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

Succursales locales et distantes

git branch -a | sed -e 's/[ \*]*//' | grep -v -e '\->' | xargs git grep "TEXT"
Devaldo
la source
Cela semble bien, mais j'ai eu cette erreur de git grep-branch "find my text":fatal: ambiguous argument 'client': both revision and filename
nealmcb
Pourquoi toujours utiliser -a, qui montre toutes les branches? Je suggérerais d'utiliser des options pour la git branchcommande pour séparer les braches. Quand on regarde les succursales locales, il n'y en a qu'une seule *, donc pas besoin d'y échapper pour sed. Donc: git branch | sed -e 's/*/ /' | xargs git grep "TEXT"pour les succursales locales seulement, git branch -r | grep -v -- "->" | xargs git grep "TEXT"pour les succursales éloignées seulement et git branch -a | grep -v -- "->" | xargs git grep "TEXT"pour toutes les succursales
jalanb
4

Voici comment je fais:

git for-each-ref --format='%(*refname)' | xargs git grep SEARCHTERM
William Entriken
la source
2
La seule solution qui a fonctionné pour moi sur Windows (dans Git bash)
Ivan
4

Si vous donnez à un commit une valeur de hachage SHA-1, git grepvous le faites chercher à l'intérieur, au lieu de la copie de travail.

Pour rechercher toutes les branches, vous pouvez obtenir tous les arbres avec git rev-list --all. Mettez tout cela avec

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

... et ayez de la patience

CharlesB
la source