web-dev-qa-db-fra.com

Abandonner un pop caché dans Git

J'ai sauté une cachette et il y avait un conflit de fusion. Contrairement à la question qui est répertoriée en tant que duplicata, j'avais déjà quelques modifications non validées dans le répertoire que je voulais conserver. Je ne veux pas seulement faire disparaître le conflit de fusion, mais aussi remettre mon répertoire dans l'état où il se trouvait avant la sortie.

J'ai essayé git merge --abort, mais git a affirmé qu'aucune fusion n'était en cours. Existe-t-il un moyen simple d’abandonner un pop sans détruire les modifications que j’avais apportées au répertoire à l’origine?

220
Casebash

Ok, je pense avoir travaillé sur "Git Stash Unapply". C'est plus complexe que git apply --reverse car vous avez besoin d'une action de fusion inverse au cas où la fusion aurait été effectuée par git stash apply.

La fusion inverse nécessite que toutes les modifications actuelles soient insérées dans l'index:

  • git add -u

Puis inversez le merge-recursive qui a été effectué par git stash apply:

  • git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1

Maintenant, il ne vous restera plus que les changements non stash. Ils seront dans l'index. Vous pouvez utiliser git reset pour annuler vos modifications si vous le souhaitez.

Étant donné que votre git stash apply original a échoué, je suppose que l'inverse peut également échouer car certaines des choses qu'il souhaite annuler ne sont pas terminées.

Voici un exemple montrant comment la copie de travail (via git status) est nettoyée à nouveau:

 $ git status
# On branch trunk
nothing to commit (working directory clean)
 $ git stash apply
Auto-merging foo.c
# On branch trunk
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   foo.c
#
no changes added to commit (use "git add" and/or "git commit -a")
 $ git add -u
 $ git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
Auto-merging foo.c
 $ git status
# On branch trunk
nothing to commit (working directory clean)
45
Ben Jackson

Mon cas d'utilisation: j'ai juste essayé de sauter sur la mauvaise branche et j'ai eu des conflits. Tout ce dont j'ai besoin, c'est d'annuler l'opération, mais de la conserver dans la liste de sélection afin de pouvoir la placer dans la branche appropriée. J'ai fait ça:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Facile.

236
jmoz

Edit: À partir de la documentation git help stash dans la section pop:

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 manuellement et appeler ensuite git stash drop manuellement.

Si l'option --index est utilisée, tente de rétablir non seulement les modifications de l'arborescence de travail, mais également celles de l'index. Toutefois, cela peut échouer en cas de conflits (qui sont stockés dans l'index et où vous ne pouvez donc plus appliquer les modifications telles qu'elles étaient à l'origine).

Essayez de copier en dur tout votre rapport dans un nouveau répertoire (pour en avoir une copie) et exécutez:

git stash show et sauvegardez cette sortie quelque part si vous en tenez à vous.

then: git stash drop pour supprimer le cache en conflit, puis: git reset HEAD

Cela devrait laisser votre pension dans l'état où elle était avant (heureusement, je n'ai toujours pas été en mesure de vous reprocher votre problème)

===

J'essaie de reproduire votre problème, mais tout ce que je reçois quand on utilise git stash pop est:

error: Your local changes to the following files would be overwritten by merge:
...
Please, commit your changes or stash them before you can merge.
Aborting

Dans un répertoire propre:

git init
echo hello world > a
git add a & git commit -m "a"
echo hallo welt >> a
echo hello world > b
git add b & git commit -m "b"
echo hallo welt >> b
git stash
echo hola mundo >> a
git stash pop

Je ne vois pas git qui essaye de fusionner mes modifications, ça échoue. Avez-vous des étapes de reprographie que nous pouvons suivre pour vous aider?

43
DavidG

Si vous n'avez pas à vous soucier des autres modifications que vous avez apportées et que vous voulez simplement revenir au dernier commit, vous pouvez alors:

git reset .
git checkout .
git clean -f
6
hugo der hungrige

OK, je pense avoir réussi à trouver un flux de travail qui vous ramènera à l'endroit où vous devez être (comme si vous n'aviez pas fait la pop).

PRENEZ UNE SAUVEGARDE AVANT LA MAIN !! Je ne sais pas si cela fonctionnera pour vous, alors copiez l'intégralité de votre pension au cas où cela ne fonctionnerait pas.

1) Corrigez les problèmes de fusion et résolvez tous les conflits en sélectionnant tous les changements apportés par le correctif (dans tortoisemerge, cela apparaît sous la forme one.REMOETE (le leur)).

git mergetool

2) Validez ces modifications (elles seront déjà ajoutées via la commande mergetool). Donnez-lui un message de "fusion" ou quelque chose dont vous vous souvenez.

git commit -m "merge"

3) Maintenant, vous aurez toujours vos modifications locales non mises en scène que vous avez commencées à l’origine, avec un nouveau commit à partir du patch (nous pourrons nous en débarrasser plus tard). Maintenant, commettez vos modifications non mises en scène

git add .
git add -u .
git commit -m "local changes"

4) Inverser le patch. Cela peut être fait avec la commande suivante:

git stash show -p | git apply -R

5) Commettez ces changements:

git commit -a -m "reversed patch"

6) Se débarrasser des commits patch/unpatch

git rebase -i HEAD^^^

à partir de là, supprimez les deux lignes contenant "fusion" et "patch inversé".

7) Récupérez vos modifications non liées et annulez la validation des modifications locales

git reset HEAD^

Je l'ai parcouru avec un exemple simple et cela vous ramène à l'endroit où vous voulez être - juste avant que la réserve ne soit ouverte, avec vos modifications locales et la réserve restant disponible.

4
agentgonzo

J'ai résolu ceci d'une manière quelque peu différente. Voici ce qui s'est passé.

Tout d'abord, j'ai sauté sur la mauvaise branche et j'ai eu des conflits. La cachette est restée intacte mais l'index était en résolution de conflit, bloquant de nombreuses commandes.

Un simple git reset HEAD a annulé la résolution du conflit et laissé les modifications non validées (et NON DÉSIRÉES).

Plusieurs git co <filename> ont rétabli l'index à l'état initial. Finalement, j'ai changé de branche avec git co <branch-name> et ai lancé un nouveau git stash pop, qui a été résolu sans conflit.

3
pid

Quelques idées:

  • Utilisez git mergetool pour scinder les fichiers de fusion en pièces originales et nouvelles. Espérons que l’un de ceux-ci est le fichier avec vos modifications non stockées.

  • Appliquez le diff de la réserve à l'envers, pour annuler uniquement ces modifications. Vous devrez probablement séparer manuellement les fichiers avec les conflits de fusion (dans l’espoir que l’astuce ci-dessus fonctionnera).

Je n’ai testé ni l’un ni l’autre, donc je ne sais pas avec certitude qu’ils fonctionneront.

2
asmeurer

Je pourrais reproduire propre git stash pop sur un répertoire "sale", avec des modifications non validées, mais pas encore pop qui génère un conflit de fusion.

Si lors du conflit de fusion, le stash que vous avez essayé d'appliquer n'a pas disparu, vous pouvez essayer d'examiner git show stash@{0} (éventuellement avec --ours ou --theirs) et de le comparer à git statis et git diff HEAD. Vous devriez pouvoir voir quels changements ont été apportés par l’application d’une réserve.

1
Jakub Narębski

Si DavidG a raison de dire qu'il n'a pas été masqué à cause du conflit de fusion, vous devez simplement nettoyer votre répertoire de travail. Rapidement git commit tout ce qui compte pour vous. (Vous pouvez reset ou squash la validation plus tard si vous n’êtes pas encore terminé.) Puis, avec tout ce qui vous intéresse, git reset tout ce que git stash pop a déversé dans votre travail. annuaire.

1
robrich

Utilisez git reflog pour répertorier toutes les modifications apportées à votre historique git. Copiez un identifiant d'action et tapez git reset ACTION_ID

1
Fatih

S'il n'y a pas eu de changements programmés avant le git stash pop, comme dans la question, les deux commandes suivantes devraient alors fonctionner.

git diff --name-only --cached | xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only | xargs rm

La première inverse toute fusion de la réserve, réussie ou non. La seconde supprime tous les fichiers non suivis introduits par la cachette.

De man git stash: The working directory must match the index. que @DavidG souligne, le stash pop échouera en cas de conflit entre des fichiers modifiés actuellement non mis en scène. En tant que tel, nous ne devrions pas avoir à nous soucier de la résolution des conflits de fusion au-delà du retour à HEAD. Tous les fichiers modifiés restants sont alors sans lien avec la stash et ont été modifiés avant le stash pop

S'il y avait des changements mis en scène, je ne sais pas si nous pouvons utiliser les mêmes commandes et vous voudrez peut-être essayer la technique de @Ben Jackson. Suggestions appréciées ..

Voici une configuration de test pour tous les différents cas https://Gist.github.com/here/4f3af6dafdb4ca15e804

# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d

# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c
0
here

Je poste ici en espérant que les autres trouveront ma réponse utile. J'ai eu un problème similaire lorsque j'ai essayé de créer une pop cachée sur une branche différente de celle que j'avais cachée. Dans mon cas, aucun fichier non engagé ni dans l'index, mais toujours dans le cas des conflits de fusion (même cas que @pid). Comme d'autres l'ont fait remarquer précédemment, la copie masquée git ayant échoué a bien conservé ma copie, puis une réinitialisation rapide de la touche *HEAD ainsi que le retour à ma branche d'origine et le stockage à partir de là ont résolu mon problème.

0
Victor Camacho