Git diff --name-only et copiez cette liste

151

Je veux juste obtenir une liste des fichiers modifiés entre deux révisions, ce qui est simple:

git diff -–name-only commit1 commit2 > /path/to/my/file

Mais, que dois-je écrire, si je veux copier tous les fichiers répertoriés dans un autre endroit? Et j'ai besoin d'une structure de répertoire complètement identique pour les fichiers copiés.

Par exemple, j'ai modifié et ajouté des fichiers:

/protected/texts/file1.txt
/protected/scripts/index.php
/public/pics/pic1.png

Je veux avoir dans /home/changes/tous ces fichiers modifiés et ajoutés:

/home/changes/protected/texts/file1.txt
/home/changes/protected/scripts/index.php
/home/changes/public/pics/pic1.png
BazZy
la source
1
Je ne comprends pas très bien ce que vous essayez de réaliser… propager des changements à différents clones? créer des correctifs? patcher des fichiers en dehors d'un référentiel git?
knittl
Pas de correctif, mais une copie exacte de la structure des fichiers modifiés. Comme le patch, mais avec des fichiers solides
BazZy
Et oui, patcher des fichiers en dehors du référentiel git - la cible la plus proche pour moi :)
BazZy
3
Désolé. QUOI? vous souhaitez capturer et rejouer les modifications apportées aux fichiers et les modifications apportées aux arborescences? c'est un patch. git format-patchpeut faire cela pour les plages de validation.
knittl
1
git diff commit1 commit2 > my.patchet puis cd other/path; patch -p1 < my.patch. Pourquoi faut-il le faire avec des copies complètes des fichiers? Si c'est parce que vous pensez que le correctif pourrait ne pas s'appliquer, et que par conséquent l'autre répertoire n'est pas vraiment dans l' commit1état, vous devriez vraiment tout copier de l' commit2état ...
Cascabel

Réponses:

118

Essayez la commande suivante, que j'ai testée:

$ cp -pv --parents $(git diff --name-only) DESTINATION-DIRECTORY
York
la source
2
Merci pour l' cp --parentsindice, je voulais cette option depuis des années et je n'ai jamais su qu'elle existait! .. évidemment je n'ai jamais pris la peine de le chercher non plus = \
Stephan Henningsen
2
Notez que cela ne fonctionne pas sur Mac, car l' --parentsoption de cpn'est pas disponible.
M. Justin
Des conseils pour l'utiliser si les fichiers ont des caractères inhabituels? Espaces blancs, personnages nordiques.
Halvor Holsten Strand
@HalvorStrand, je ne l'ai pas testé, mais le réglage en IFS=$'\n'premier peut le faire. (De préférence dans un sous-shell pour ne pas gâcher votre valeur IFS d'origine.)
Wildcard
J'obtiens une erreur cp: cannot stat 'git diff --name-only': No such file or directorysur git bash sous Windows. Qu'est-ce que je fais mal? Le répertoire de destination existe
Shiva
14

Les éléments suivants devraient fonctionner correctement:

git diff -z --name-only commit1 commit2 | xargs -0 -IREPLACE rsync -aR REPLACE /home/changes/protected/

Pour expliquer davantage:

  • Le -zà avec git diff --name-onlysignifie pour afficher la liste des fichiers séparés par des octets NUL au lieu de nouvelles lignes, juste au cas où vos noms de fichiers contiennent des caractères inhabituels.

  • Le -0to xargsdit d'interpréter l'entrée standard comme une liste de paramètres séparés par NUL.

  • Le -IREPLACEest nécessaire car par défaut xargsajouterait les paramètres à la fin de la rsynccommande. Au lieu de cela, cela dit de les mettre là où se trouve le dernier REPLACE. (C'est un bon conseil de cette réponse Server Fault .)

  • Le -aparamètre rsyncsignifie pour préserver les autorisations, la propriété, etc. si possible. Le -Rmoyen d'utiliser le chemin d'accès relatif complet lors de la création des fichiers dans la destination.

Mise à jour: si vous avez une ancienne version de xargs, vous devrez utiliser l' -ioption à la place de -I. (Le premier est obsolète dans les versions ultérieures de findutils.)

Mark Longair
la source
C'est étrange - quel système d'exploitation utilisez-vous? S'il s'agit d'une distribution Linux, laquelle et que xargs --versiondit-elle?
Mark Longair
1
Ah, dans cette version de xargs, vous devez utiliser à la -iplace, ce qui est obsolète dans les versions ultérieures - la 4.1 est maintenant assez ancienne. Je mettrai à jour ma réponse.
Mark Longair
@Mark: Je me souviens avoir lu quelque part que vous avez besoin d'un espace après -Idans certaines versions, alors essayez peut-être à la -I REPLACEplace.
Mikel
Ça ne fait rien. Cela ne fonctionne pas non plus. -In'est pris en charge que depuis la version findutils4.2.10, sortie en décembre 2004.
Mikel
Vous devez ajouter --diff-filter=dpour exclure les fichiers supprimés de la liste. Sinon, vous finirez par avoir des erreurs en essayant de les copier dans le dossier des modifications. Sinon, bonne réponse. Merci!
taymless
11

Voici un one-liner:

Répertoriez les fichiers modifiés et compressez-les au format * .zip:

git diff --name-only | zip patched.zip -@

Répertoriez les derniers fichiers modifiés validés et compressez-les au format * .zip:

git diff --name-only HEAD~ HEAD | zip patched.zip -@
kolypto
la source
Si vous utilisez Windows, vous pouvez télécharger le zip en ligne de commande depuis sourceforge.net/projects/gnuwin32/files/zip
Radon8472
@ Radon8472 Qui installe sed.exe? Je ne suis toujours zippas trouvé sur Windows.
Shiva
non, le lien pointe vers le téléchargement pour zip.exe et non pour sed. Si vous ne pouvez pas utiliser zip en ligne de commande, vous devez ajouter le dossier dans lequel le zip.exe est installé à votre PATHvariable env.
Radon8472
6
zip update.zip $(git diff --name-only commit commit)
marque
la source
2

Cela fonctionne parfaitement.

git diff 1526043 82a4f7d --name-only | xargs zip update.zip

git diff 1526043 82a4f7d --name-only |xargs -n 10 zip update.zip
chevalier2016
la source
1

Personne n'a mentionné cpioce qui est facile à taper, crée des liens physiques et gère les espaces dans les noms de fichiers:

git diff --name-only $from..$to  | cpio -pld outdir
hexten
la source