Récupérer le journal de validation d'une ligne spécifique dans un fichier?

503

Existe-t-il un moyen d'obtenir que git vous donne un journal de validation pour les validations qui ont touché une ligne particulière dans un fichier?

Comme git blame, mais git blamevous montrera le DERNIER commit qui a touché une ligne particulière.

J'aimerais vraiment obtenir un journal similaire, pas la liste des validations n'importe où dans le fichier, mais uniquement les validations qui ont touché une ligne particulière.

jrochkind
la source
2
Voir aussi: Git blame - commits antérieurs
joeytwiddle

Réponses:

632

Voir aussi Git: découvrez quels commits ont touché une gamme de lignes .


Depuis Git 1.8.4 , git logil -Lfaut voir l'évolution d'une gamme de lignes.

Par exemple, supposons que vous regardiez git blamela sortie de. Ici -L 150,+11signifie "ne regardez que les lignes 150 à 150 + 11":

$ git blame -L 150,+11 -- git-web--browse.sh
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150)            die "The browser $browser is not
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151)    fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153) 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156)    # Check version because firefox < 2.0 do
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157)    vers=$(expr "$($browser_path -version)" 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158)    NEWTAB='-new-tab'
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159)    test "$vers" -lt 2 && NEWTAB=''
a0685a4f git-web--browse.sh (Dmitry Potapov   2008-02-09 23:22:22 -0800 160)    "$browser_path" $NEWTAB "$@" &

Et vous voulez connaître l'historique de ce qui est maintenant la ligne 155.

Ensuite, utilisez git log. Ici, -L 155,155:git-web--browse.shsignifie "retracer l'évolution des lignes 155 à 155 dans le fichier nommé git-web--browse.sh".

$ git log --pretty=short -u -L 155,155:git-web--browse.sh
commit 81f42f11496b9117273939c98d270af273c8a463
Author: Giuseppe Bilotta <[email protected]>

    web--browse: support opera, seamonkey and elinks

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -143,1 +143,1 @@
-firefox|iceweasel)
+firefox|iceweasel|seamonkey|iceape)

commit a180055a47c6793eaaba6289f623cff32644215b
Author: Giuseppe Bilotta <[email protected]>

    web--browse: coding style

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -142,1 +142,1 @@
-    firefox|iceweasel)
+firefox|iceweasel)

commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
Author: Christian Couder <[email protected]>

    Rename 'git-help--browse.sh' to 'git-web--browse.sh'.

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- /dev/null
+++ b/git-web--browse.sh
@@ -0,0 +127,1 @@
+    firefox|iceweasel)
Matt McClure
la source
2
'git log --topo-order --graph -u -L 155,155: git-web--browse.sh' - cela a donné une erreur fatale: 'invalide object name 155,155'. Version Git: 1.8.3.2. Aucune suggestion?
BairDev
12
Mettre à niveau vers Git 1.8.4 ou version ultérieure.
Matt McClure
4
que faire si je veux connaître "l'historique de la ligne 155 dans commitA" (au lieu de la ligne 155 dans HEAD). Puis-je simplement utiliser git log commitA-hash -L 155,155:file-name?
Ida
@Flimm, je n'ai pas de préférence marquée.
Matt McClure
cela fonctionne bien, sauf si le fichier a été déplacé / renommé ... il semble que --follow n'aime pas être combiné avec des arguments de plage de lignes.
Mike Ellery
67

Vous pouvez obtenir un ensemble de validations en utilisant pioche.

git log -S'the line from your file' -- path/to/your/file.txt

Cela vous donnera toutes les validations qui ont affecté ce texte dans ce fichier. Si le fichier a été renommé à un moment donné, vous pouvez ajouter --follow-parent.

Si vous souhaitez inspecter les validations à chacune de ces modifications, vous pouvez diriger ce résultat vers git show:

git log ... | xargs -n 1 git show
Adam Dymitruk
la source
5
Je ne suis pas sûr de voir comment cela aide. Si le texte a été affecté, alors la ligne n'est plus la même, donc pioche ne vous montrera que le changement le plus récent. Vous auriez alors à faire git log -S'the previous version of the line'et ainsi de suite, exactement comme vous finiriez par le faire avec git blame -L. Et ce sera beaucoup plus lent que cela git blame, car il doit chercher le texte partout, pas seulement à l'endroit donné.
Cascabel
Vous pouvez utiliser un regex là-dedans pour le rendre plus acceptant. Actuellement, il n'y a aucun moyen de «parcourir les correctifs» dans le temps sans un script élaboré. J'espère que gitk obtiendra cette fonctionnalité dans sa vue patch à l'avenir.
Adam Dymitruk
3
pourquoi cela s'appelle pioche ? :)
Ciprian Tomoiagă
43

Essayez d'utiliser la commande ci-dessous implémentée dans Git 1.8.4.

git log -u -L <upperLimit>,<lowerLimit>:<path_to_filename>

Donc, dans votre cas upperLimitet lowerLimitest touchéline_number

Plus d'informations - https://www.techpurohit.com/list-some-useful-git-commands

jitendrapurohit
la source
2
Je pense qu'il --pretty=shortest ignoré lors de l'utilisation -L. Veuillez corriger
Vic Seedoubleyew
14

Un moyen extrêmement simple de le faire est d'utiliser vim-fugitive . Ouvrez simplement le fichier dans vim, sélectionnez la ou les lignes que vous souhaitez utiliser V, puis entrez

:Glog

Vous pouvez maintenant utiliser :cnextet :cprevpour voir toutes les révisions du fichier où cette ligne est modifiée. À tout moment, entrez :Gblamepour voir les informations sur le sha, l'auteur et la date.

Cory Klein
la source
13

Simplifier la réponse de @ matt -

git blame -L14,15 -- <file_path>

Ici, vous obtiendrez un blâme pour une ligne 14 to 15.

Puisque l' -Loption attend en Rangetant que paramètre, nous ne pouvons pas obtenir un Blamepour une seule ligne en utilisant l' -Loption` .

Référence

Échanges
la source
10

Je ne crois pas qu'il y ait quelque chose de intégré à cela. Cela est rendu difficile par le fait qu'il est rare qu'une seule ligne change plusieurs fois sans que le reste du fichier ne change considérablement aussi, vous aurez donc tendance à finir avec des numéros de ligne changeant beaucoup.

Si vous avez la chance que la ligne ait toujours une caractéristique d'identification, par exemple une affectation à une variable dont le nom n'a jamais changé, vous pouvez utiliser le choix d'expression régulière pour git blame -L. Par exemple:

git blame -L '/variable_name *= */',+1

Mais cela ne trouve que la première correspondance pour cette expression régulière, donc si vous n'avez pas un bon moyen de faire correspondre la ligne, ce n'est pas trop utile.

Vous pourriez pirater quelque chose, je suppose. Je n'ai pas le temps d'écrire du code pour l'instant, mais ... quelque chose dans ce sens. Courez git blame -n -L $n,$n $file. Le premier champ est le commit précédent touché, et le deuxième champ est le numéro de ligne dans ce commit, car il aurait pu changer. Saisissez-les et exécutez git blame -n $n,$n $commit^ $file, c'est-à-dire la même chose à partir de la validation avant la dernière modification du fichier.

(Notez que cela vous échouera si le dernier commit qui a changé la ligne était un commit de fusion. La principale façon que cela pourrait se produire si la ligne était modifiée dans le cadre d'une résolution de conflit de fusion.)

Edit: je suis tombé sur ce message de la liste de diffusion de mars 2011 aujourd'hui, qui le mentionne tiget git guipossède une fonctionnalité qui vous aidera à le faire. Il semble que la fonctionnalité ait été envisagée, mais pas terminée, pour git lui-même.

Cascabel
la source
6

Cela nécessitera git blameque chaque révision significative montre la ligne $LINEde fichier $FILE:

git log --format=format:%H $FILE | xargs -L 1 git blame $FILE -L $LINE,$LINE

Comme d'habitude, le blâme indique le numéro de révision au début de chaque ligne. Vous pouvez ajouter

| sort | uniq -c

pour obtenir des résultats agrégés, quelque chose comme une liste de commits qui ont changé cette ligne. (Pas tout à fait, si le code uniquement a été déplacé, cela peut afficher le même ID de validation deux fois pour différents contenus de la ligne. Pour une analyse plus détaillée, vous devez effectuer une comparaison retardée des git blamerésultats pour les validations adjacentes. )

krlmlr
la source
Encore une fois, je pense que cela ne fonctionne pas, car il ne suit pas l'emplacement précédent de cette ligne. Donc, si une ligne a été ajoutée il y a 2 commits, vous regarderez une autre ligne
Vic Seedoubleyew
6

Voici une solution qui définit un alias git, vous pourrez donc l'utiliser comme ça:

git rblame -M -n -L '/REGEX/,+1' FILE

Exemple de sortie:

00000000 18 (Not Committed Yet 2013-08-19 13:04:52 +0000 728) fooREGEXbar
15227b97 18 (User1 2013-07-11 18:51:26 +0000 728) fooREGEX
1748695d 23 (User2 2013-03-19 21:09:09 +0000 741) REGEXbar

Vous pouvez définir l'alias dans votre .gitconfig ou simplement exécuter la commande suivante

git config alias.rblame !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); echo $line; done' dumb_param

Il s'agit d'un laid à une ligne, voici donc une fonction bash équivalente désobscurcie:

git-rblame () {
    local commit line
    while line=$(git blame "$@" $commit 2>/dev/null); do
        commit="${line:0:8}^"
        if [ "00000000^" == "$commit" ]; then
            commit=$(git rev-parse HEAD)
        fi
        echo $line
    done
}

La solution de pioche ( git log --pickaxe-regex -S'REGEX ' ) ne vous donnera que des ajouts / suppressions de lignes, pas les autres altérations de la ligne contenant l'expression régulière.

Une limitation de cette solution est que git blame ne renvoie que la 1ère correspondance REGEX, donc si plusieurs correspondances existent, la récursivité peut "sauter" pour suivre une autre ligne. Assurez-vous de vérifier la sortie de l'historique complet pour repérer ces «sauts», puis réparez votre REGEX pour ignorer les lignes parasites.

Enfin, voici une version alternative qui exécute git show sur chaque commit pour obtenir la diff complète:

git config alias.rblameshow !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); git show $commit; done' dumb_param
Lucas Cimon
la source
2

Vous pouvez mélanger git blameet git logcommander pour récupérer le résumé de chaque commit dans la commande git blame et les ajouter. Quelque chose comme le script bash + awk suivant. Il ajoute le résumé de la validation sous forme de commentaire de code en ligne.

git blame FILE_NAME | awk -F" " \
'{
   commit = substr($0, 0, 8);
   if (!a[commit]) {
     query = "git log --oneline -n 1 " commit " --";
     (query | getline a[commit]);
   }
   print $0 "  // " substr(a[commit], 9);
 }'

En une seule ligne:

git blame FILE_NAME | awk -F" " '{ commit = substr($0, 0, 8); if (!a[commit]) { query = "git log --oneline -n 1 " commit " --"; (query | getline a[commit]); } print $0 "  // " substr(a[commit], 9); }'
cserpell
la source
2

Dans mon cas, le numéro de ligne a beaucoup changé au fil du temps. J'étais également sur git 1.8.3 qui ne supporte pas l'expression régulière dans "git blame -L". (RHEL7 a toujours 1.8.3)

myfile=haproxy.cfg
git rev-list HEAD -- $myfile | while read i
do
    git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"
done | grep "<sometext>"

Bon mot:

myfile=<myfile> ; git rev-list HEAD -- $myfile | while read i; do     git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"; done | grep "<sometext>"

Cela peut bien sûr être transformé en script ou en fonction.

sastorsl
la source