Comment résoudre le conflit de git stash sans commit?

495

Comme demandé dans cette question , je veux également savoir comment résoudre un conflit git stash popsans ajouter toutes les modifications à un commit (tout comme "git stash pop" sans conflit).

Mon approche actuelle est très peu cool car je le fais de cette façon:

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[Mise à jour] Une façon de le reproduire:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

2016-06-27: Ajout d'un nouveau fichier appelé «troisième» à l'exemple pour montrer que des solutions de contournement comme la solution de scy ne fonctionnent que pour les HEAD vides mais ne résolvent pas le problème initial que la HEAD n'a pas le même contenu comme pour un git stash popsans conflit.

Sven
la source
Vous git addavez donc résolu vos fichiers de conflit, les mettre en scène efficacement dans l'index, et vous ne souhaitez pas les avoir dans notre index?
Romain
Oui c'est vrai. Je veux juste le comportement qui git stash popse produit quand aucun conflit ne se produit (mais avec notification des fichiers à fusionner).
Sven
2
On dirait que la réponse est ici: stackoverflow.com/questions/3945826/git-stash-questions . Dans la réponse choisie, sur le 4ème commentaire, Adam explique pourquoi git fait cela.
Patrick
@Patrick Merci pour cette information - il semble donc qu'il n'y aura pas de solution disponible car son "par conception"
Sven

Réponses:

510

Ne suivez pas les autres réponses

Eh bien, vous pouvez les suivre :). Mais je ne pense pas que faire un commit puis réinitialiser la branche pour supprimer ce commit et les solutions de contournement similaires suggérées dans d'autres réponses soient la bonne façon de résoudre ce problème.

Solution propre

La solution suivante semble être beaucoup plus propre pour moi et elle est également suggérée par le Git lui - même - essayez de l'exécuter git statusdans le référentiel avec un conflit:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

Faisons donc ce que Git suggère (sans faire de commits inutiles):

  1. Résolvez manuellement le conflit (ou en utilisant un outil de fusion , voir ci-dessous).
  2. Permet git resetde marquer les conflits comme résolus et de supprimer les modifications. Vous pouvez l'exécuter sans aucun paramètre et Git supprimera tout de l'index. Vous n'avez pas à exécuter git addavant.
  3. Enfin, supprimez la cachette avec git stash drop, car Git ne le fait pas en cas de conflit.

Traduit en ligne de commande:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Explication du comportement par défaut

Il existe deux façons de marquer les conflits comme résolus: git addet git reset. Bien que git resetmarque les conflits comme résolus et supprime les fichiers de l'index, git addmarque également les conflits comme résolus, mais conserve les fichiers dans l'index.

L'ajout de fichiers à l'index après la résolution d'un conflit est délibéré. De cette façon, vous pouvez différencier les modifications de la sauvegarde précédente et les modifications apportées après la résolution du conflit. Si vous ne l'aimez pas, vous pouvez toujours utiliser git resetpour tout supprimer de l'index.

Outils de fusion

Je recommande fortement d'utiliser l'un des outils de fusion à 3 voies pour résoudre les conflits, par exemple KDiff3 , Meld , etc., au lieu de le faire manuellement. Il résout généralement automatiquement la totalité ou la majorité des conflits. C'est un énorme gain de temps!

David Ferenczy Rogožan
la source
32
@kamalpal, il semble nécessaire en cas d' git stash popéchec des conflits.
Emile Bergeron
21
@kamalpal oui, Git vous informe même que la cachette n'a pas été lâchée en cas de conflit. Et la question portait sur un tel cas, donc vous devez vraiment l'exécuter àgit stash drop moins que vous ne vouliez garder cette cachette.
David Ferenczy Rogožan
@ DavidFerenczyRogožan Git ne m'a pas du tout informé qu'il n'avait pas supprimé l'entrée de la cachette. Version 2.17.1 ici.
Robert Siemer
298

Supposons que vous ayez ce scénario dans lequel vous planifiez vos modifications afin de tirer de l'origine. Peut-être parce que vos modifications locales ne se trouvent que debug: truedans certains fichiers de paramètres. Maintenant, vous tirez et quelqu'un y a introduit un nouveau paramètre, créant un conflit.

git status dit:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

D'accord. J'ai décidé de suivre ce que Git a suggéré: j'ai résolu le conflit et commis:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

Maintenant, ma copie de travail est dans l'état que je veux, mais j'ai créé un commit que je ne veux pas avoir. Comment puis-je me débarrasser de ce commit sans modifier ma copie de travail? Attendez, il y a une commande populaire pour ça!

git reset HEAD^

Ma copie de travail n'a pas été modifiée, mais la validation WIP a disparu. C'est exactement ce que je voulais! (Notez que je n'utilise pas --softici, car s'il y a des fichiers fusionnés automatiquement dans votre stash, ils sont automatiquement mis en scène et vous vous retrouveriez donc avec ces fichiers en cours de mise en scène après reset.)

Mais il reste une chose: la page de manuel pour git stash popnous rappelle que "L'application de l'état peut échouer avec des conflits; dans ce cas, il n'est pas supprimé de la liste de dissimulation. Vous devez résoudre les conflits à la main et appeler git stash dropmanuellement par la suite." C'est exactement ce que nous faisons maintenant:

git stash drop

Et.. Voila.

scy
la source
34
Il y a juste beaucoup de laideur héritée à devoir délibérément faire un reset HEAD ^ ... pour quelque chose qui ne devrait affecter que l'arbre de travail.
6
Pourquoi ne pas résoudre les conflits juste et git add <resolved conflict files>suivi git reset HEAD?
BoltzmannBrain
Merci pour la suggestion, mais cela ne résout pas le problème initial que ce n'est pas le même comportement que git stash popsans conflit. Ajoutez simplement un autre fichier à HEAD avant de faire le conflit git stash popet vous git commit -a -m WIPajouteriez également le nouveau fichier au commit. Mais sans conflit, seul le nouveau fichier resterait dans HEAD mais pas les git stash popfichiers.
Sven
7
Je ne pense pas qu'il soit nécessaire de valider d'abord puis d'annuler la validation. La simple réinitialisation de la réponse de Dawid Ferenczy fera de même
vladkras
3
Pour les utilisateurs de Windows, le ^est utilisé comme une continuation de ligne spéciale et vous laissera assis à un Plus? invite au lieu d'exécuter la commande. Au lieu d' utiliser: git reset --soft HEAD~1. Voir comment-je-supprimer-non-poussé-git-commits?
mrfelis
87

Au lieu d'ajouter les modifications que vous apportez pour résoudre le conflit, vous pouvez utiliser git reset HEAD filepour résoudre le conflit sans mettre en scène vos modifications.

Cependant, vous devrez peut-être exécuter cette commande deux fois. Une fois pour marquer le conflit comme résolu et une fois pour mettre en scène les changements qui ont été mis en place par la routine de résolution de conflit.

Il est possible qu'il y ait un mode de réinitialisation qui fasse ces deux choses simultanément, bien qu'il n'y en ait pas maintenant.

ComputerDruid
la source
2
Le mode de réinitialisation est celui que je recherche - d'autres solutions de contournement sont comme celle que j'ai décrite et ne sont pas pratiques pour plus de 5 fichiers.
Sven
25
Et utilisez ensuite "git stash drop" pour terminer la "git stash pop".
David Liu
2
Bien que la question ne le demande pas explicitement, il peut être utile de mettre à jour la réponse pour inclure "git stash drop" car la stash n'est pas supprimée automatiquement en cas de conflit.
Abhishek Pathak
29
git checkout stash -- .

travaillé pour moi.

Remarque : cela peut être dangereux car il n'essaie pas de fusionner les modifications de la cachette dans votre copie de travail, mais l' écrase à la place avec les fichiers cachés. Vous pouvez donc perdre vos modifications non validées.

stevenspiel
la source
Cela a aidé lorsque "git pull --autostash" introduit des validations de fusion indésirables et git checkout stash -. écrase inconditionnellement les conflits de la cachette
Alec Istomin
11
git add .
git reset

git add . mettra en scène TOUS les fichiers indiquant à git que vous avez résolu le conflit

git reset décompactera TOUS les fichiers intermédiaires sans créer de commit

Aaron Goldman
la source
Ceci est en fait pas une mauvaise réponse, il est à peu près comme git add -ualorsgit reset
ebob
4

Il semble que ce soit la réponse que vous cherchez, je n'ai pas encore essayé personnellement, mais il semble que cela puisse faire l'affaire. Avec cette commande, GIT essaiera d'appliquer les modifications telles qu'elles étaient auparavant, sans essayer de les ajouter toutes pour les valider.

git stash apply --index

voici l'explication complète:

http://git-scm.com/book/en/Git-Tools-Stashing

Marco Ponti
la source
Merci pour cette astuce, mais cela n'aidera pas quand je l'ai déjà fait git stash pop- ou y a-t-il un moyen de revenir sur cela et de le faire git stash apply --indexquand j'ai découvert que cela git stash popse heurtera à un conflit?
Sven
J'ai ajouté un exemple sur la façon de produire cela - imaginez que vous modifiez plus de 10 fichiers, de sorte que vous ne savez pas lequel d'entre eux vous avez modifié en dehors de la cachette.
Sven
3
Si vous regardez au bas de ce post ICI, il est dit que si vous exécutez git stash popet que cela se termine par des conflits, la cachette n'est pas supprimée ... vous pouvez donc exécuter git reset --hardpour annuler la pop et essayer la solution que j'ai suggérée.
Marco Ponti
Je viens de l'essayer et cela ne fonctionne pas après avoir un fichier en état de conflit. Même si vous résolvez le conflit manuellement.
Sam3k
2

git stash branchwill works, qui crée une nouvelle branche pour vous, vérifie le commit sur lequel vous étiez lorsque vous avez caché votre travail, y réapplique votre travail, puis supprime la cachette si elle s'applique correctement. vérifier ça

chérir
la source
2

Le moyen le plus rapide que j'ai trouvé est de résoudre le conflit, puis de le faire git add -u, puis de le faire git reset HEAD, cela n'implique même pas un commit.

Jammer
la source
1

Selon Git Stash , après avoir réglé le conflit, git add <file>c'est la bonne ligne de conduite.

C'est après avoir lu ce commentaire que j'ai compris que les modifications sont automatiquement ajoutées à l'index (par conception). C'est pourquoi git add <file>achève le processus de résolution des conflits.

samgrigg
la source
-1

Ce n'est pas la meilleure façon de le faire, mais cela fonctionne:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file
Bishwas Mishra
la source
cette réponse me semble tout à fait erronée, car elle annulerait toutes les modifications apportées file/path/to/your/file, ce qui n'est pas ce que le PO a demandé, AFAIU
oromoiluig