web-dev-qa-db-fra.com

Comment grep (recherche) le code engagé dans l'historique Git?

J'ai supprimé un fichier ou un code dans un fichier par le passé. Puis-je grep dans le contenu (pas dans les messages de validation)?

Une très mauvaise solution consiste à graper le journal:

git log -p | grep <pattern>

Cependant, cela ne retourne pas le hachage de commit immédiatement. J'ai joué avec git grep en vain.

1302
Ortwin Gentz

Pour rechercher commit content (c'est-à-dire les lignes de source réelles, par opposition aux messages de commit, etc.), vous devez procéder comme suit:

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

git rev-list --all | xargs git grep <expression> fonctionnera si vous rencontrez une erreur "Liste d'arguments trop longue".

Si vous souhaitez limiter la recherche à un sous-arbre (par exemple, "lib/util"), vous devrez le transmettre à la sous-commande rev-list et à la variable grep:

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

Ceci couvrira tout votre texte de validation pour regexp.

La raison de passer le chemin dans les deux commandes est parce que rev-list renverra la liste des révisions contenant tous les changements apportés à lib/util, mais vous devez également passer à grep pour qu'il ne contienne que recherche dans lib/util.

Imaginez simplement le scénario suivant: grep pourrait trouver le même <regexp> sur d'autres fichiers contenus dans la même révision renvoyée par rev-list (même si aucun changement n'a été apporté à ce fichier lors de cette révision. ).

Voici d'autres moyens utiles de rechercher votre source:

Recherche dans l'arborescence de travail pour la correspondance du texte dans l'expression régulière regexp:

git grep <regexp>

Rechercher dans l'arborescence de travail des lignes de texte correspondant à l'expression régulière regexp1 ou regexp2:

git grep -e <regexp1> [--or] -e <regexp2>

Recherchez dans l’arbre de travail les lignes de texte correspondant à l’expression régulière regexp1 et regexp2, indiquant les chemins de fichier uniquement:

git grep -e <regexp1> --and -e <regexp2>

Rechercher dans l'arborescence de travail les fichiers dont les lignes de texte correspondent à l'expression régulière regexp1 et celles correspondant à l'expression régulière regexp2:

git grep -l --all-match -e <regexp1> -e <regexp2>

Rechercher dans l'arborescence de travail les lignes modifiées du modèle de correspondance de texte:

git diff --unified=0 | grep <pattern>

Recherchez dans toutes les révisions les expressions correspondantes correspondant à l'expression régulière regexp:

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

Rechercher dans toutes les révisions entre rev1 et rev2 le texte correspondant à l'expression régulière regexp:

git grep <regexp> $(git rev-list <rev1>..<rev2>)
1722
Jeet

Vous devez utiliser l'option pioche (_-S_) de git log

Pour rechercher Foo:

_git log -SFoo -- path_containing_change 
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change
_

Voir Historique Git - Trouver la ligne perdue par mot-clé pour plus d'informations.


Comme Jakub Narębski a commenté:

  • this recherche les différences qui introduisent ou suppriment une instance de _<string>_ .
    Cela signifie généralement "révisions pour lesquelles vous avez ajouté ou supprimé une ligne avec 'Foo'".

  • l'option _--pickaxe-regex_ vous permet d'utiliser une expression rationnelle POSIX étendue au lieu de rechercher une chaîne.


Comme Rob a commenté, cette recherche est sensible à la casse - il a ouvert une question suivante sur la recherche de la casse.

496
VonC

Ma façon préférée de le faire est d'utiliser l'option git log de -G (ajoutée à la version 1.7.4).

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

Il existe une différence subtile entre la manière dont les options -G et -S déterminent si un commit correspond:

  • L'option -S compte essentiellement le nombre de correspondances de votre recherche dans un fichier avant et après une validation. La validation est indiquée dans le journal si les nombres avant et après sont différents. Cela ne montrera pas, par exemple, les commits où une ligne correspondant à votre recherche a été déplacée.
  • Avec l'option -G, la validation est affichée dans le journal si votre recherche correspond à une ligne ajoutée, supprimée ou modifiée.

Prenons ce commit comme exemple:

diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello

Etant donné que le nombre de fois que "hello" apparaît dans le fichier est identique avant et après cette validation, il ne correspondra pas avec -Shello. Cependant, comme il y a eu un changement dans une ligne correspondant à hello, la validation sera affichée à l'aide de -Ghello.

228
Tyler Holien

Si vous voulez parcourir les modifications de code (voyez ce qui a réellement été changé avec le mot donné dans toute l'historique), choisissez le mode patch - j'ai trouvé une combinaison très utile de ce qui suit:

git log -p
# hit '/' for search mode
# type in the Word you are searching
# if the first search is not relevant hit 'n' for next (like in vim ;) )
46
Bartek Skwira

Je pris réponse de @ Jeet et l'adpated à Windows (grâce à cette réponse ):

FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt

Notez que pour moi, pour une raison quelconque, la validation qui a supprimé cette expression rationnelle n'apparaissait pas dans le résultat de la commande, mais plutôt une validation antérieure.

24
ripper234

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

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) la plus récente en premier. L'option -p permet d'afficher le diff pertinent là où le motif a été ajouté ou supprimé, afin que vous puissiez le voir en contexte.

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

git branch -a --contains 8beeff00d
20
Edward Anderson

Rechercher dans toute révision, tous les fichiers:

git rev-list --all | xargs git grep <regexp>

Rechercher uniquement dans certains fichiers, pour exemple fichiers XML:

git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"

Les lignes de résultat doivent ressembler à ceci: 6988bec26b1503d45eb0b2e8a4364afb87dde7af: bla.xml: texte de la ligne trouvée ...

Vous pouvez alors obtenir plus d’informations comme auteur, date, diff en utilisant git show:

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af
17

Pour tous ceux qui essaient de le faire dans Sourcetree, il n'y a pas de commande directe dans l'interface utilisateur pour cela (à partir de la version 1.6.21.0). Cependant, vous pouvez utiliser les commandes spécifiées dans la réponse acceptée en ouvrant la fenêtre Terminal (bouton disponible dans la barre d’outils principale) et en les copiant/collant dessus.

Remarque: La vue Search de Sourcetree peut partiellement rechercher du texte pour vous. presse Ctrl + 3 accéder à la vue Recherche (ou cliquez sur l’onglet Recherche disponible en bas). De l'extrême droite, définissez Type de recherche sur Fichier Modifications, puis tapez la chaîne que vous souhaitez rechercher. Cette méthode présente les limitations suivantes par rapport à la commande ci-dessus:

  1. Sourcetree affiche uniquement les commits qui contiennent le mot de recherche dans l'un des fichiers modifiés. La recherche du fichier contenant exactement le texte de recherche est à nouveau une tâche manuelle.
  2. RegEx n'est pas pris en charge.
6
dotNET

Pour plus de simplicité, je suggérerais d'utiliser une interface graphique: gitk - le navigateur de référentiel Git . C'est assez flexible

  1. Pour rechercher le code:

    Enter image description here
  2. Pour rechercher des fichiers:

    Enter image description here
  3. Bien sûr, il supporte également les expressions régulières:

    Enter image description here

Et vous pouvez naviguer dans les résultats en utilisant les flèches haut/bas.

4
watashiSHUN

La réponse de @ Jeet fonctionne dans PowerShell.

git grep -n <regex> $(git rev-list --all)

Ce qui suit affiche tous les fichiers, dans n’importe quelle livraison, contenant un password.

# store intermediate result
$result = git grep -n "password" $(git rev-list --all)

# display unique file names
$result | select -unique { $_ -replace "(^.*?:)|(:.*)", "" }
2
Shaun Luttin

Alors essayez-vous de passer par les anciennes versions du code en cherchant où quelque chose existe?

Si je le faisais, j'utiliserais probablement git bisect . En utilisant une bissecte, vous pouvez spécifier une bonne version connue, une mauvaise version connue et un script simple qui vérifie si la version est bonne ou incorrecte (dans ce cas, un grep pour voir si le code que vous recherchez est présent. ). En cours d’exécution, vous découvrirez quand le code a été supprimé.

1
Rob Di Marco
git rev-list --all | xargs -n 5 git grep EXPRESSION

est une solution de Tweak to @ Jeet, de sorte qu'elle affiche les résultats pendant la recherche et pas seulement à la fin (ce qui peut prendre beaucoup de temps dans un grand référentiel).

0
laktak

Dans mon cas, je devais rechercher un court engagement et les solutions listées ne fonctionnaient malheureusement pas.

J'ai réussi à le faire avec: (remplace le jeton REGEX)

for commit in $(git rev-list --all --abbrev-commit)
do
    if [[ $commit =~ __REGEX__ ]]; then 
        git --no-pager show -s --format='%h %an - %s' $commit
    fi
done
0
user1183098

Scénario: Vous avez fait un grand nettoyage de votre code en utilisant votre IDE. Problème: Le IDE a nettoyé plus qu'il ne devrait et maintenant votre code ne compile pas (ressources manquantes, etc.)

Solution:

git grep --cached "text_to_find"

Il trouvera le fichier où "text_to_find" a été changé.

Vous pouvez maintenant annuler cette modification et compiler votre code.

0
Garytech

Chaque fois que je me trouve chez vous. J'utilise la ligne de commande suivante:

git log -S "<words/phrases i am trying to find>" --all --oneline  --graph 

Explication:

  1. git log - J'ai besoin d'écrire plus ici, il montre les logs dans un ordre chronologique.
  2. -S "<words/phrases i am trying to find>" - Il montre tous les commits git où n'importe quel fichier (ajouté/modifié/supprimé) contient les mots/phrases que j'essaie de trouver sans les symboles '<>'.
  3. --all - Pour appliquer et rechercher dans toutes les branches.
  4. --oneline - Compresse le journal git en une ligne.
  5. --graph - Il crée le graphe des commits ordonnés dans l'ordre chronologique.
0
psyco