94 votes

En utilisant git diff, comment puis-je obtenir les numéros des lignes ajoutées et modifiées ?

Supposons que j'ai un fichier texte

alex
bob
matrix
will be removed
git repo

et je l'ai mis à jour pour qu'il soit

alex
new line here
another new line
bob
matrix
git

Ici, j'ai ajouté les lignes numérotées (2,3) et mis à jour la ligne numérotée (6).

Comment puis-je obtenir ces informations sur les numéros de ligne en utilisant git diff ou toute autre commande git ?

100voto

Sedrik Points 659

git diff --stat vous montrera la sortie que vous obtenez lorsque vous commettez des choses, et c'est à cela que vous faites référence, je suppose.

git diff --stat

Pour montrer exactement les numéros de ligne qui ont été modifiés, vous pouvez utiliser

git blame -p <file> | grep "Not Committed Yet"

Et la ligne modifiée sera le dernier chiffre avant la parenthèse finale dans le résultat. Ce n'est pas une solution propre cependant :(

4 votes

Stat n'affiche que le nombre de lignes insérées/supprimées/mises à jour. Mais j'ai besoin de savoir quels numéros de lignes

0 votes

Cela semblait être un problème plus difficile qu'il ne devrait l'être, mais j'ai réussi à l'obtenir en utilisant git blame et grep. Voir ma réponse mise à jour

1 votes

Il faut généralement appeler 'git blame -p' si la sortie doit être traitée par d'autres programmes tels que 'awk' ou 'grep'.

33voto

John Points 2117

Voici une fonction bash pour calculer les numéros de ligne résultant d'un diff :

diff-lines() {
    local path=
    local line=
    while read; do
        esc=$'\033'
        if [[ $REPLY =~ ---\ (a/)?.* ]]; then
            continue
        elif [[ $REPLY =~ \+\+\+\ (b/)?([^[:blank:]$esc]+).* ]]; then
            path=${BASH_REMATCH[2]}
        elif [[ $REPLY =~ @@\ -[0-9]+(,[0-9]+)?\ \+([0-9]+)(,[0-9]+)?\ @@.* ]]; then
            line=${BASH_REMATCH[2]}
        elif [[ $REPLY =~ ^($esc\[[0-9;]+m)*([\ +-]) ]]; then
            echo "$path:$line:$REPLY"
            if [[ ${BASH_REMATCH[2]} != - ]]; then
                ((line++))
            fi
        fi
    done
}

Il peut produire des résultats tels que :

$ git diff | diff-lines
http-fetch.c:1: #include "cache.h"
http-fetch.c:2: #include "walker.h"
http-fetch.c:3: 
http-fetch.c:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
http-fetch.c:4:+int main(int argc, const char **argv)
http-fetch.c:5: {
http-fetch.c:6:+       const char *prefix;
http-fetch.c:7:        struct walker *walker;
http-fetch.c:8:        int commits_on_stdin = 0;
http-fetch.c:9:        int commits;
http-fetch.c:19:        int get_verbosely = 0;
http-fetch.c:20:        int get_recover = 0;
http-fetch.c:21: 
http-fetch.c:22:+       prefix = setup_git_directory();
http-fetch.c:23:+
http-fetch.c:24:        git_config(git_default_config, NULL);
http-fetch.c:25: 
http-fetch.c:26:        while (arg < argc && argv[arg][0] == '-') {
fetch.h:1: #include "config.h"
fetch.h:2: #include "http.h"
fetch.h:3: 
fetch.h:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix);
fetch.h:4:+int main(int argc, const char **argv);
fetch.h:5: 
fetch.h:6: void start_fetch(const char* uri);
fetch.h:7: bool fetch_succeeded(int status_code);

d'une différence comme celle-ci :

$ git diff
diff --git a/builtin-http-fetch.c b/http-fetch.c
similarity index 95%
rename from builtin-http-fetch.c
rename to http-fetch.c
index f3e63d7..e8f44ba 100644
--- a/builtin-http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,9 @@
 #include "cache.h"
 #include "walker.h"

-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
 {
+       const char *prefix;
        struct walker *walker;
        int commits_on_stdin = 0;
        int commits;
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
        int get_verbosely = 0;
        int get_recover = 0;

+       prefix = setup_git_directory();
+
        git_config(git_default_config, NULL);

        while (arg < argc && argv[arg][0] == '-') {
diff --git a/fetch.h b/fetch.h
index 5fd3e65..d43e0ca 100644
--- a/fetch.h
+++ b/fetch.h
@@ -1,7 +1,7 @@
 #include "config.h"
 #include "http.h"

-int cmd_http_fetch(int argc, const char **argv, const char *prefix);
+int main(int argc, const char **argv);

 void start_fetch(const char* uri);
 bool fetch_succeeded(int status_code);

Si vous souhaitez uniquement afficher les lignes ajoutées/supprimées/modifiées, et non le contexte environnant, vous pouvez passer le code suivant -U0 à git diff :

$ git diff -U0 | diff-lines
http-fetch.c:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
http-fetch.c:4:+int main(int argc, const char **argv)
http-fetch.c:6:+       const char *prefix;
http-fetch.c:22:+       prefix = setup_git_directory();
http-fetch.c:23:+
fetch.h:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix);
fetch.h:4:+int main(int argc, const char **argv);

Il est robuste par rapport aux codes de couleur ANSI, donc vous pouvez passer --color=always à git diff pour obtenir le code couleur habituel pour les lignes ajoutées/supprimées.

Le résultat peut être facilement récupéré :

$ git diff -U0 | diff-lines | grep 'main'
http-fetch.c:4:+int main(int argc, const char **argv)
fetch.h:4:+int main(int argc, const char **argv);

Dans votre cas git diff -U0 donnerait :

$ git diff -U0 | diff-lines
test.txt:2:+new line here
test.txt:3:+another new line
test.txt:6:-will be removed
test.txt:6:-git repo
test.txt:6:+git

Si vous ne voulez que les numéros de ligne, modifiez le paramètre echo "$path:$line:$REPLY" à juste echo "$line" et faire passer la sortie par uniq .

0 votes

Comment pourrais-je faire passer les codes d'échappement des couleurs de bash ? C'est génial, mais les codes de couleur provenant de git diff --color ne passent pas. Ou pensez-vous qu'il serait préférable d'ajouter les échappatoires de couleur dans le retour de cette fonction ?

2 votes

J'ai mis à jour la fonction pour que les différentes regex soient robustes aux codes couleurs ANSI. git diff --color | diff-lines fonctionne maintenant comme prévu :)

2 votes

Cette solution fonctionne à merveille ! Elle devrait être marquée comme la réponse car elle fait vraiment ce que le PO a demandé. Si cela a fonctionné pour vous, veuillez voter pour qu'elle devienne la réponse populaire :)

23voto

Ida Points 214

J'utilise le --unified=0 option de git diff .

Par exemple, git diff --unified=0 commit1 commit2 produit la différence :

*enter image description here*

En raison de la --unified=0 la sortie de diff montre 0 ligne de contexte ; en d'autres termes, elle montre exactement les lignes modifiées .

Maintenant, vous pouvez identifier les lignes qui commencent par '@@', et les analyser en fonction du modèle :

@@ -startline1,count1 +startline2,count2 @@

Reprenons l'exemple ci-dessus, pour le fichier WildcardBinding.java, à partir de la ligne 910, 0 ligne est supprimée. A partir de la ligne 911, 4 lignes sont ajoutées.

1 votes

Et si @@ -910,10,+911,15@@ ou autre, alors comment dire exactement combien de lignes ont été ajoutées, supprimées ou modifiées ?

1 votes

Avez-vous un bon moyen d'afficher les numéros de ligne dans une liste comme le demande OP ?

7voto

Jay Points 11

J'ai eu ce même problème et j'ai donc écrit un gawk script qui modifie la sortie de git diff pour faire précéder le numéro de ligne pour chaque ligne. Je le trouve utile parfois quand j'ai besoin de diff tree de travail, bien que ce ne soit pas limité à cela. Peut-être que cela peut être utile à quelqu'un ici ?

$ git diff HEAD~1 |showlinenum.awk
diff --git a/doc.txt b/doc.txt
index fae6176..6ca8c26 100644
--- a/doc.txt
+++ b/doc.txt
@@ -1,3 +1,3 @@
1: red
2: blue
 :-green
3:+yellow

Vous pouvez le télécharger ici :
https://github.com/jay/showlinenum

0 votes

Cela semble très pratique. Gardez à l'esprit que ce code a l'avantage (ou le désavantage) d'être sous licence GPL.

0 votes

J'ai écrit git diffn pour faire cela aussi, et il conserve entièrement les couleurs du terminal et affiche les numéros de ligne de l'ancien fichier à gauche et du nouveau fichier à droite.

2voto

manojlds Points 96599

Configurez un outil de comparaison externe qui vous montrera les numéros de ligne. Par exemple, voici ce que j'ai dans ma configuration globale de git :

diff.guitool=kdiff3
difftool.kdiff3.path=c:/Program Files (x86)/KDiff3/kdiff3.exe
difftool.kdiff3.cmd="c:/Program Files (x86)/KDiff3/kdiff3.exe" "$LOCAL" "$REMOTE"

Voir cette réponse pour plus de détails : https://stackoverflow.com/q/949242/526535

0 votes

N'y a-t-il pas un autre moyen d'obtenir ces informations sans utiliser l'outil diff. En utilisant uniquement les commandes git ?

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