Puis-je utiliser git diff sur des fichiers non suivis?

270

Est-il possible de demander à git diff d'inclure des fichiers non suivis dans sa sortie diff? Ou est mon meilleur pari pour ajouter les nouveaux fichiers que j'ai créés et les fichiers existants que j'ai édités et utiliser

git diff --cached

?

Andrew Grimm
la source

Réponses:

267

Avec les versions récentes de git, vous pouvez git add -Nle fichier (ou --intent-to-add), qui ajoute un blob de longueur nulle à l'index à cet emplacement. Le résultat est que votre fichier "non suivi" devient maintenant une modification pour ajouter tout le contenu à ce fichier de longueur nulle, et cela apparaît dans la sortie "git diff".

git diff

echo "this is a new file" > new.txt
git diff

git add -N new.txt
git diff
diff --git a/new.txt b/new.txt
index e69de29..3b2aed8 100644
--- a/new.txt
+++ b/new.txt
@@ -0,0 +1 @@
+this is a new file

Malheureusement, comme indiqué, vous ne pouvez pas tant git stashque vous avez un --intent-to-addfichier en attente comme celui-ci. Bien que si vous devez ranger, il vous suffit d'ajouter les nouveaux fichiers, puis de les ranger. Ou vous pouvez utiliser la solution de contournement d'émulation:

git update-index --add --cacheinfo \
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt

(la création d'un alias est votre ami ici).

araqnid
la source
Il s'avère que ma copie de Git n'est pas assez récente pour avoir l'ajout de -N, mais cela répond à ma question.
Andrew Grimm
1
Vous pouvez émuler "git add -N new.txt" avec "git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt" (comment ai-je réussi à mettre cela sur la mauvaise réponse?)
araqnid
1
que se passe-t-il si vous avez beaucoup de nouveaux fichiers, existe-t-il un moyen facile de les ajouter tous puis de les différencier?
Vic
1
@Vicgit add -N .
Nathan
92

Je pense que vous pouvez comparer les fichiers de votre index et les fichiers non suivis en fournissant simplement le chemin d'accès aux deux fichiers.

git diff --no-index tracked_file untracked_file
Harold
la source
3
Est-ce que cela fonctionne si vous avez créé plusieurs fichiers non suivis depuis le dernier commit?
Andrew Grimm
12
Oui, réponse parfaite! Je peux ensuite utiliser git diff --no-index untracked_file_1 untracked_file_2pour obtenir la git diffcoloration syntaxique, etc. sur les diffs ... magnifique.
Colin D Bennett
40
Je ne comprends pas pourquoi vous comparez un fichier suivi avec un fichier non suivi non lié. Si vous voulez juste pour obtenir diff sortie pour le fichier untracked, vous pouvez simplement utiliser à la /dev/nullplace: git diff --no-index -- /dev/null <untracked_file>.
4
Ou tout simplement cat untracked_file_1, ou peut printf '\e[1;32m%s\e[0m\n' "$(cat untracked_file_1)"- être si vous avez vraiment besoin d'une sortie verte. :) (Bien que sur une note plus sérieuse, veuillez noter que la substitution de commandes supprimera les nouvelles lignes de fin de votre fichier.)
Wildcard
8
Cela devrait être la réponse acceptée - cela ne nécessite pas de changer l'index de git; qui, comme le dit l'auteur original, a ses inconvénients
DIMMSum
38

Pour mon gitting interactif au jour le jour (où je diffère l'arborescence de travail contre la tête tout le temps, et j'aimerais avoir des fichiers non suivis inclus dans le diff), add -N/--intent-to-addest inutilisable, car il se casse git stash .

Voici donc mon git diffremplaçant. Ce n'est pas une solution particulièrement propre, mais comme je ne l'utilise que de manière interactive, je vais bien avec un hack:

d() {
    if test "$#" = 0; then
        (
            git diff --color
            git ls-files --others --exclude-standard |
                while read -r i; do git diff --color -- /dev/null "$i"; done
        ) | `git config --get core.pager`
    else
        git diff "$@"
    fi
}

Taper juste dinclura les fichiers non suivis dans le diff (ce qui m'importe dans mon flux de travail), et d args...se comportera comme d'habitude git diff.

Remarques:

  • Nous utilisons ici le fait qu'il git diffs'agit uniquement de diffs individuels concaténés, il n'est donc pas possible de distinguer la dsortie d'un "vrai diff" - à l'exception du fait que tous les fichiers non suivis sont triés en dernier.
  • Le seul problème avec cette fonction est que la sortie est colorisée même lorsqu'elle est redirigée; mais je ne peux pas être dérangé d'ajouter de la logique pour cela.
  • Je n'ai trouvé aucun moyen d'obtenir des fichiers non suivis en assemblant simplement une liste d'arguments pour git diff. Si quelqu'un découvre comment faire cela, ou si une fonctionnalité est ajoutée gità un moment donné dans le futur, veuillez laisser une note ici!
Jo Liss
la source
4
Ironie du sort, ma git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txtsolution que je suggère pour Gits vieux - t travail avec git stash, en supposant que vous avez déjà dans votre e69de29bb db, par exemple en essayant d'utiliser add -Nprécédemment. Donc, apparemment, ce n'est pas exactement l'équivalent d'une git add -Ncertaine manière: tbh, je ne sais pas comment.
araqnid
2
Soit dit testen passant, vous effectuez une comparaison de chaînes plutôt qu'une vérification d'égalité numérique avec votre commande. Cela ne devrait rien affecter, mais test "$#" -eq 0c'est plus précisément ce qui est prévu.
Wildcard
1
Oui, il semble toujours que vous devez le faire par paire ... mais vous pouvez le simuler en un seul lesspour que vous n'ayez pas à appuyer qsur chaque fichier et que cela ressemble exactement git diff, en supprimant la pagination par fichier ( -P), en l'ajoutant par la suite ( | less), préservant la couleur ( --color=always) et l'interprétant comme couleur ( less -rou less -R). Donc tout à fait c'est:do git -P diff --color=always -- /dev/null "$i"; done | less -r
hyperpallium
Au cas où vous souhaiteriez être dérangé à l'avenir, test -t 1(par exemple, if [ -t 1 ]; then color_arg=--color; fiou quelque chose) est un moyen pour le shell de vérifier si sa sortie est un terminal, ce qui est un moyen utile de décider de la coloration. Et xargspourrait donner un moyen de se débarrasser de la boucle while. Vous aurez toujours besoin -n 1de cela, donc il lancera toujours git un tas de fois, et devra toujours être par paire de cette façon, mais ... il se débarrasse de whileet read, alors peut-être que c'est mieux?!? Je laisse cela au lecteur.
lindes
28

Pas à 100% au point, mais si pour une raison quelconque vous ne voulez pas ajouter vos fichiers à l'index comme suggéré par la réponse acceptée, voici une autre option:

Si les fichiers ne sont pas suivis, le diff est évidemment le fichier entier, vous pouvez donc simplement les visualiser avec moins:

less $(git ls-files --others --exclude-standard)

Naviguez entre eux avec :net :ppour le suivant et le précédent.

Mise à jour à partir des commentaires: Si vous avez besoin d'un format de patch, vous pouvez également le combiner avec git diff:

git ls-files --others --exclude-standard | xargs -n 1 git --no-pager diff /dev/null | less

Vous pouvez également rediriger la sortie vers un fichier ou utiliser une autre commande diff dans ce cas.

user1587520
la source
6
vous pouvez également exécuter git diff /dev/null <untracked_tile>et obtenir le correctif au format correctif plutôt que «juste» un fichier
SimSimY
2
cette réponse combinée avec git diff est une solution parfaite.
iwind
22
git add -A
git diff HEAD

Générez le correctif si nécessaire, puis:

git reset HEAD
Amol Pujari
la source
Cela a le potentiel de perdre le (pré-) travail précédent, en ajoutant tout. Surtout le cas si on s'en sert git add -ptrès souvent (ce que je recommande généralement d'ailleurs) ... Cela donne une façon de faire le truc de base, il faut juste ... qu'il faut noter qu'il a le potentiel de côté indésirable effets.
lindes
13

cela fonctionne pour moi:

git add my_file.txt
git diff --cached my_file.txt
git reset my_file.txt

La dernière étape est facultative, elle laissera le fichier dans l'état précédent (non suivi)

utile si vous créez également un patch:

  git diff --cached my_file.txt > my_file-patch.patch
Alejandro Moreno
la source
La spécificité de cette paire d'ajout / réinitialisation est un joli contraste avec l'approche du fusil de chasse de stackoverflow.com/a/50486906/313756 ... merci pour cela.
lindes
9

Les changements fonctionnent lorsqu'ils sont intermédiaires et non intermédiaires avec cette commande. Les nouveaux fichiers fonctionnent lorsqu'ils sont organisés:

$ git diff HEAD

S'ils ne sont pas organisés, vous ne verrez que les différences de fichiers.

alairock
la source
26
HEADest la valeur par défaut , c'est donc la même que celle git diffqui ne résout pas le problème.
Iulian Onofrei
4
Cela nécessite git addde chaque fichier non suivi
SilvioQ
Si vous modifiez cette réponse pour l'inclure, git addc'est la plus simple si votre cas d'utilisation est de vérifier ce que vous venez d'ajouter / voulez ajouter
KCD
8

Pour un fichier:

git diff --no-index /dev/null new_file

Pour tous les nouveaux fichiers:

for next in $( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null $next; done;

Comme alias:

alias gdnew="for next in \$( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null \$next; done;"

Pour tous les fichiers modifiés et nouveaux combinés en une seule commande:

{ git --no-pager diff; gdnew }
radzimir
la source
2

généralement lorsque je travaille avec des équipes de sites distants, il est important pour moi d'avoir une connaissance préalable des changements effectués par d'autres équipes dans le même fichier, avant de suivre les étapes de git untrack -> staged -> commit pour cela j'ai écrit un script bash qui aidez-moi à éviter les conflits de fusion de résolution inutiles avec l'équipe distante ou créez une nouvelle branche locale et comparez et fusionnez sur la branche principale

#set -x 
branchname=`git branch | grep -F '*' |  awk '{print $2}'`
echo $branchname
git fetch origin ${branchname}
for file in `git status | grep "modified" | awk "{print $2}" `
do
echo "PLEASE CHECK OUT GIT DIFF FOR "$file 
git difftool FETCH_HEAD $file ;
done

dans le script ci-dessus, je récupère la branche principale distante (pas nécessaire sa branche principale) pour les FETCH_HEAD faire une liste de mon fichier modifié uniquement et comparer les fichiers modifiés à git difftool

ici de nombreux outils difft supportés par git, je configure 'Meld Diff Viewer' pour une bonne comparaison GUI.

adg
la source
-9

En supposant que vous n'ayez pas de commits locaux,

git diff origin/master
Pradhan
la source
8
La question demande une git diffcommande qui inclut des fichiers non suivis. Cette commande ne les inclut pas. De plus, l'existence ou non de commits locaux n'a absolument rien à voir avec la question.
toon81
JFTR, moi git merge --squash mybranch, et git diff masterm'a montré les changements dans les fichiers non suivis.
muammar
2
C'est impossible. Vous semblez confus sur ce que signifie «non suivi». Non suivi ne signifie pas qu'un fichier est suivi dans une branche et pas dans une autre, cela signifie qu'il n'est "en Git" nulle part. Que vous vous écrasiez ou non, cela ne fait aucune différence. git diffn'affiche pas de différences dans les fichiers non suivis: parce qu'ils ne le sont pas, il n'y a jamais de différences à afficher, par définition. C'est juste la façon dont Git fonctionne. :)
toon81