Puis-je obtenir une sortie compatible avec les patchs de git-diff?

160

Je fais quelque chose de très simple mal. J'essaie de préparer un fichier de correctif ordinaire, afin de pouvoir réappliquer certaines modifications:

$ git diff > before
$ git diff something_here > save.patch
$ git checkout . 
$ patch < save.patch
$ git diff > after
$ diff before after
$

Avec something_here vide, cela fonctionne presque, mais les noms de fichiers ne sont pas corrects. Je pense qu'il me manque juste une option.

Dans la vraie vie, je vais faire une fusion après le paiement, donc le correctif peut échouer là-bas, mais vous voyez à quoi je veux en venir.

Modifier Ma faute ici pour avoir posé la mauvaise question. La vraie question est la suivante: je veux enregistrer mes modifications, faire une fusion, puis réappliquer les modifications, si possible? Je l'ai mal posé car je suis habitué à utiliser patch pour résoudre ce genre de problèmes et il git diffsemblait que c'était ce qu'il voulait que je fasse.

Le commentaire de Charles Bailey avait la bonne réponse. Pour moi, git-apply est la bonne chose à faire (git-stash semble plus lourd que ce dont j'ai besoin et le rebasage et les bundles dépassent définitivement mon niveau de compétence actuel.) Je vais accepter la réponse que Charles a donnée (parce que vous ne peut accepter un commentaire). Merci pour toutes les suggestions.

Edit, 6 ans plus tard Comme tous ceux qui connaissent le sujet le savent, j'ai surestimé la difficulté de git stash. Presque tous les jours environ, j'utiliserai la séquence suivante:

$ git stash
$ git merge
$ git stash pop
Malvolio
la source
8
Y a-t-il une raison pour laquelle vous souhaitez spécifiquement utiliser patchplutôt que git apply?
CB Bailey
3
Et même dans ce cas, avez-vous vraiment besoin de correctifs plutôt que de quelque chose comme git stashou d'autres outils git?
CB Bailey
3
Après l'édition, je pense que git stashc'est la solution la plus simple pour ce que vous essayez de faire, mais il existe de nombreuses approches qui fonctionnent.
CB Bailey
1
@Malvolio: En effet, vous n'avez même pas besoin de penser à un nom de fichier temporaire pour stocker votre patch.
CB Bailey
4
@Charlse, vous devez parfois envoyer un patch à quelqu'un sans le référentiel git complet. Par exemple si vous utilisez git-svn.
Elazar Leibovich

Réponses:

139

Si vous souhaitez utiliser patch, vous devez supprimer les a/ b/préfixes que git utilise par défaut. Vous pouvez le faire avec l' --no-prefixoption (vous pouvez également le faire avec l' -poption patch ):

git diff --no-prefix [<other git-diff arguments>]

Cependant, il est généralement plus facile d'utiliser directement git diff, puis d'utiliser la sortie pour alimenter git apply.

La plupart du temps, j'essaie d'éviter d'utiliser des patchs textuels. Habituellement, un ou plusieurs commits temporaires combinés à un rebase, git stashet les bundles sont plus faciles à gérer.

Pour votre cas d'utilisation, je pense que stashc'est le plus approprié.

# save uncommitted changes
git stash

# do a merge or some other operation
git merge some-branch

# re-apply changes, removing stash if successful
# (you may be asked to resolve conflicts).
git stash pop
CB Bailey
la source
7
git diff --no-prefix master > diff.patchet puisgit checkout master patch -p0 < diff.patch
Natim
1
@Natim Pour une sécurité ultime, je recommanderais d'utiliser patch --dry-run < diff.patchavant d'émettre la dernière commande.
ᴠɪɴᴄᴇɴᴛ
1
@ ᴠɪɴᴄᴇɴᴛ quel serait l'avantage de faire cela? Puisque nous utilisons git, il est peu probable que nous perdions quoi que ce soit, n'est-ce pas?
Natim
1
@Natim Comme je l'ai dit, juste pour une sécurité ultime, pas besoin de défaire quoi que ce soit en cas d'erreur. Je pensais aussi aux personnes qui lisent ceci et qui veulent utiliser en patchdehors de git (peut-être en utilisant un fichier de correctif généré par diff) dans un cas d'utilisation plus général.
ᴠɪɴᴄᴇɴᴛ
Afin d'inclure de nouveaux fichiers dans votre patch, vous devez également inclure "git diff --no-prefix --cached" dans le patch. Peut-être qu'il y a une meilleure façon?
jamshid
219

Il suffit d'utiliser -p1: vous devrez de toute façon utiliser -p0dans le --no-prefixcas, vous pouvez donc simplement omettre --no-prefixet utiliser -p1:

$ git diff > save.patch
$ patch -p1 < save.patch

$ git diff --no-prefix > save.patch
$ patch -p0 < save.patch
ndim
la source
1
Si vous vous demandez pourquoi, l'homme résume bien la situation - source .
tutuDajuju
3
Cela ne fonctionnera pas avec les renommés; git diffrenvoie une ligne qui patchignore. git applyest la voie à suivre.
hraban
17

Les diffs git ont un segment de chemin supplémentaire ajouté aux chemins de fichier. Vous pouvez supprimer l'entrée this dans le chemin en spécifiant -p1 avec patch, comme ceci:

patch -p1 < save.patch
Henrik Gustafsson
la source
10
  1. J'enregistre le diff du répertoire courant (y compris les fichiers non validés) par rapport au HEAD actuel.
  2. Ensuite, vous pouvez transporter le save.patchfichier n'importe où (y compris les fichiers binaires).
  3. Sur votre machine cible, appliquez le correctif en utilisant git apply <file>

Remarque: il diffère également des fichiers actuellement en attente.

$ git diff --binary --staged HEAD > save.patch
$ git reset --hard
$ <transport it>
$ git apply save.patch
Matej
la source
Hahaha. Ca c'est drôle. J'ai posé cette question il y a près de quatre ans et la façon dont je l'ai fait a évolué, mais si vous m'aviez demandé hier comment le faire, j'aurais donné votre réponse et dit que je l'avais obtenue à partir des réponses à cette question. (En fait, j'utiliserais probablement un simple git diff > save.patchet git checkout .au lieu d'une réinitialisation, mais oui ...
Malvolio
Oh n'a pas remarqué ses 4 ans: P. Btw, la réinitialisation est juste pour démontrer que cela fonctionne. Je ne vois également personne utiliser git applyou rendre le diff pertinent à votre état et le pointeur vers le dernier commit disponible. Faire git diffn'a tout simplement rien fait du tout
Matej
Ouais, maintenant je me demande comment j'ai découvert git apply. Le problème git diffest (je pense) de l'utilisation git reset- les relations entre le repo, l'index et la zone de travail sont le problème.
Malvolio
8

Une astuce utile pour éviter de créer des fichiers de correctifs temporaires:

git diff | patch -p1 -d [dst-dir]
démarrage lent
la source
Exactement ce que je voulais. Fonctionne également parfaitement avec les caches! git stash show -p stash@{3} | patch -p1 -d [dst-dir]
dtmland