295 votes

Comment rechercher dans tous les commits Git et Mercurial du dépôt une certaine chaîne de caractères ?

J'ai un dépôt Git avec quelques branches et des commits pendants. Je voudrais rechercher tous ces commits dans le dépôt pour une chaîne spécifique.

Je sais comment obtenir un journal de tous les commits dans l'historique, mais ceux-ci n'incluent pas les branches ou les blobs pendants, juste l'historique de HEAD. Je veux les obtenir tous, pour trouver un commit spécifique qui a été mal placé.

J'aimerais également savoir comment faire cela dans Mercurial, car j'envisage de passer à cette technologie.

0 votes

337voto

richq Points 29694

Vous pouvez voir les commits en suspens avec git log -g .

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

Vous pouvez donc faire cela pour trouver une chaîne particulière dans un message de livraison qui est en suspens :

git log -g --grep=search_for_this

Alternativement, si vous voulez rechercher les modifications pour une chaîne de caractères particulière, vous pouvez utiliser l'option de recherche de la pioche, "-S" :

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

Git 1.7.4 sera ajouter l'option -G , vous permettant de passer -G<regexp> pour trouver quand une ligne contenant <regexp> a été déplacée, ce que -S ne peut pas faire. -S vous dira seulement quand le nombre total de lignes contenant la chaîne de caractères a changé (c'est-à-dire l'ajout/le retrait de la chaîne de caractères).

Enfin, vous pouvez utiliser gitk pour visualiser les commits en suspens :

gitk --all $(git log -g --pretty=format:%h)

Puis, utilisez ses fonctions de recherche pour retrouver le fichier égaré. Tout cela fonctionne en supposant que le commit manquant n'a pas "expiré" et n'a pas été collecté, ce qui peut arriver s'il traîne pendant 30 jours et que vous expirez les reflogs ou exécutez une commande qui les expire.

4 votes

Peut-être qu'au lieu de lancer "git grep" sur un (probablement grand) nombre de commits, ce qui trouverait tous les commits qui ont 'search_for_this' quelque part dans un projet, utilisez la recherche dite "pickaxe", c'est-à-dire l'option '-S' de git log, qui trouve les commits qui ont introduit ou supprimé une chaîne donnée, ou pour être plus exact où le nombre d'occurrences d'une chaîne donnée a changé.

5 votes

Vous pouvez spécifier plusieurs branches, ou utiliser l'option '--all', par exemple 'git log --grep="string in a commit message" --all'.

0 votes

Cela m'a juste permis de retrouver un commit perdu pour 2 jours de travail. J'ai totalement sauvé mon cul, merci !

56voto

Martin Geisler Points 44779

Dans Mercurial, vous utilisez hg log --keyword pour rechercher des mots-clés dans les messages de validation et hg log --user pour rechercher un utilisateur particulier. Voir hg help log pour d'autres moyens de limiter le journal.

36 votes

Josip a écrit qu'il envisage de passer à Mercurial et qu'il aimerait aussi savoir comment cela se passe là-bas.

1 votes

hg log -k recherche le nom de l'utilisateur et les noms de fichiers dans les changesets (je vois cela dans commands.py:log), ce qui est l'une des rares choses que je ne comprends pas dans hg. Il devrait y avoir des options séparées pour rechercher dans les messages de commit et les noms de fichiers. On dirait que hg log --template '{desc}\n'|grep est le moyen le plus sûr.

0 votes

@GeoffreyZheng : il y a des moyens de le faire. Voir "hg help revsets", notamment les fonctions desc(), user(), et file(). Il existe également des commutateurs hg log pour la plupart de ces comportements. D'après mon expérience, cependant, -k/keyword() est généralement le moyen le plus utile pour rechercher des choses.

24voto

Jakub Narębski Points 87537

En plus de réponse de Richq de l'utilisation git log -g --grep=<regexp> o git grep -e <regexp> $(git log -g --pretty=format:%h) : jetez un coup d'œil aux articles de blog suivants, rédigés par Junio C Hamano, mainteneur actuel de git


Résumé

Les deux sites git grep y git log --grep sont orienté vers la ligne en ce sens qu'ils recherchent les lignes qui correspondent à un modèle spécifié.

Vous pouvez utiliser git log --grep=<foo> --grep=<bar> (ou git log --author=<foo> --grep=<bar> qui se traduit en interne par deux --grep ) pour trouver les commits qui correspondent à o bien de motifs (implicites OU sémantique).

Parce qu'il est orienté vers les lignes, l'utile Y sémantique est d'utiliser git log --all-match --grep=<foo> --grep=<bar> pour trouver commettre qui a les deux la correspondance des lignes en premier lieu et la correspondance des lignes en second lieu quelque part.

Avec git grep vous pouvez combiner plusieurs motifs (qui doivent tous utiliser l'attribut -e <regexp> ) avec --or (qui est la valeur par défaut), --and , --not , ( y ) . Pour grep --all-match signifie que fichier doit avoir des lignes qui correspondent à chacune des alternatives.

0 votes

Hey Jakub, ça te dérange d'intégrer des citations/résumés de ces articles de blog ici ? On dirait que c'est l'une des réponses vintage à base de liens pour le moment.

11voto

Sam H Points 83

En me basant sur la réponse de rq, j'ai trouvé cette ligne qui fait ce que je veux :

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

Ce qui rapportera l'ID du commit, le nom du fichier, et affichera la ligne correspondante, comme ceci :

91ba969:testFile:this is a test

... Quelqu'un pense-t-il que ce serait une bonne option à inclure dans la commande git grep standard ?

5voto

adl Points 7294

Toute commande qui prend des références comme arguments acceptera l'option --all documentée dans la page de manuel de git rev-list comme suit :

   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

Ainsi, par exemple git log -Sstring --all affichera tous les commits qui mentionnent string et qui sont accessibles à partir d'une branche ou d'un tag (je suppose que vos commits dangling sont au moins nommés avec un tag).

3 votes

Cela ne semble pas être le cas pour git grep--all semble être traduit en / utilisé comme --all-match . Cela ressemble à un bogue pour moi en utilisant Git 1.7.2.3 (en utilisant $(git rev-list --all) travaille).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X