Git stash: "Ne peut pas postuler à un arbre de travail sale, veuillez effectuer vos modifications"

133

J'essaie d'appliquer les modifications que j'ai cachées précédemment git stash popet de recevoir le message:

Cannot apply to a dirty working tree, please stage your changes

Une suggestion sur la façon de gérer cela?

avernet
la source

Réponses:

196

Lorsque je dois appliquer des modifications cachées à une copie de travail sale, par exemple faire sortir plus d'un changesets de la réserve, j'utilise ce qui suit:

$ git stash show -p | git apply -3 && git stash drop

Fondamentalement, il

  1. crée un patch
  2. conduit cela vers la commande Apply
  3. s'il y a des conflits, ils devront être résolus via une fusion à 3 voies
  4. si appliquer (ou fusionner) a réussi, il supprime l'élément de cache qui vient d'être appliqué ...

Je me demande pourquoi il n'y a pas d' -foption (force) pour git stash poplaquelle devrait se comporter exactement comme le one-liner ci-dessus.

En attendant, vous voudrez peut-être ajouter ce one-liner en tant qu'alias git:

$ git config --global --replace-all alias.unstash \
   '!git stash show -p | git apply -3 && git stash drop'
$ git unstash

Merci à @SamHasler pour avoir signalé le -3paramètre qui permet de résoudre les conflits directement via la fusion à 3 voies.

muhqu
la source
Est-ce git stash show -p | git applydifférent de git stash apply?
Factor Mystic
1
Jo Factor git stash applyn'appliquera pas les modifications cachées si vous avez une copie de travail sale. Vous pouvez donc voir git stash show -p | git applyqu'une sorte de réserve forcée s'applique.
muhqu
1
n'aide pas Mais aide: git réinitialise HEAD et décolle les modifications après cela.
Roger Alien
4
J'obtiens "erreur: échec du correctif ... le correctif ne s'applique pas" pour l'un des fichiers. Je souhaite que cela donne un conflit de fusion.
Aleksandr Dubinsky le
1
Cette solution n'a pas fonctionné pour moi, elle a échoué error: <file> does not match indexpour chaque fichier modifié. Cependant, une autre solution a fonctionné.
silvenon
57

Je le fais de cette manière:

git add -A
git stash apply

puis (facultatif):

git reset
Sergii Mostovyi
la source
2
+1! C'est plus simple que les autres solutions qui impliquent de générer des correctifs ou de modifier des commits, et cela maintient vos modifications locales en toute sécurité isolées des modifications de cache appliquées jusqu'à ce que vous soyez sûr que les modifications ont été fusionnées correctement.
peterflynn
J'obtiens l'erreur "... existe déjà, pas de retrait ... Impossible de restaurer les fichiers non suivis de la cachette"
Aleksandr Dubinsky
2
J'ai utilisé git add -u, ce qui est comme -Asauf qu'il n'ajoute pas de fichiers non suivis.
Brad Cupit
9

Vous pouvez le faire sans avoir à cacher vos modifications actuelles en exportant la réserve que vous souhaitez sous forme de fichier de correctif et en l'appliquant manuellement.

Par exemple, supposons que vous souhaitiez appliquer stash @ {0} à un arbre sale:

  1. Exportez le stash @ {0} en tant que correctif:

    git stash show -p stash @ {0}> Stash0.patch

  2. Appliquez manuellement les modifications:

    git apply Stash0.patch

Si la deuxième étape échoue, vous devrez éditer le fichier Stash0.patch pour corriger les erreurs, puis réessayer git apply.

Ishan
la source
C'est pratique et réalisable pour le cas où j'ai fait une refactorisation sur un répertoire (je l'ai supprimé et j'ai créé un lien symbolique avec son nom). Git ne pouvait pas dire quels étaient mes changements de copie de travail.
yclian
1
Cela a très bien fonctionné. Je n'ai pas pu appliquer une réserve même si je suis presque sûr que mon arbre de travail est propre.
Shiki
Oui, j'ai dû supprimer des lignes sur un fichier binaire.
Dorian
8

Nettoyez votre répertoire de travail avec git reset, validez les modifications ou, si vous voulez cacher les modifications actuelles, essayez:

$ git stash save "description des changements actuels"
$ git stash pop stash @ {1}

Cela cachera les modifications actuelles, puis sortira la deuxième réserve de la pile de réserves.

William Pursell
la source
5
Mais ce gars veut que les deux cachettes soient appliquées!
Elazar Leibovich le
@Elazar Vous lisez la question. L'OP veut simplement appliquer une réserve précédente. Si vous avez raison de conserver les modifications actuelles, la solution peut être répétée: pop, commit, repeat.
William Pursell le
Je pense qu'il les veut tous les deux sans engagement. Mais là encore, il peut les commettre deux fois et les écraser en un seul commit.
Elazar Leibovich
J'obtiens l'erreur "... existe déjà, pas de retrait ... Impossible de restaurer les fichiers non suivis de la cachette"
Aleksandr Dubinsky
6

La solution de Mathias est certainement la plus proche d'un git stash pop --force (et vraiment, allez les développeurs Git, obtenons déjà cette option!)

Cependant, si vous souhaitez faire la même chose en utilisant uniquement des commandes git, vous pouvez:

  1. git commit -a -m "Fixme"
  2. git stash pop
  3. git commit -a --amend
  4. git reset HEAD ~

En d'autres termes, faites un commit (que nous ne pousserons jamais) de vos changements actuels. Maintenant que votre espace de travail est propre, ouvrez votre réserve. Maintenant, validez les changements de stash comme un amendement à votre commit précédent. Cela fait, vous avez maintenant les deux ensembles de changements combinés en un seul commit ("Fixme"); il suffit de réinitialiser (--soft PAS --hard donc rien n'est réellement perdu) votre checkout à "un avant cette validation", et maintenant vous avez les deux ensembles de changements, complètement non validés.

** MODIFIER * *

Je viens de réaliser que c'est encore plus facile; vous pouvez ignorer complètement l'étape 3, donc ...

  1. git commit -a -m "Fixme"
  2. git stash pop
  3. git reset HEAD ~

(Validez les modifications actuelles, supprimez les modifications cachées, réinitialisez cette première validation pour obtenir les deux ensembles de modifications combinés dans un état non validé.)

machineghost
la source
4

Aucune de ces réponses ne fonctionne réellement si vous vous trouvez dans cette situation comme je l'ai fait aujourd'hui. Peu importe combien git reset --hardj'ai fait, cela ne m'a mené nulle part. Ma réponse (pas officielle du tout était):

  1. Déterminez l'utilisation du hachage de la réserve git reflog --all
  2. Fusionnez ce hachage avec la branche qui vous intéresse
Dan Rosenstark
la source
1
Merci beaucoup Yar. J'étais frustré par la façon dont Git se comportait étrangement sur mon dépôt local tout à l'heure, le même problème que vous avez décrit.
yclian le
4

J'ai également trouvé que la solution de Mathias Leppich fonctionnait très bien, j'ai donc ajouté un alias pour cela à mon .gitconfig global

[alias]
        apply-stash-to-dirty-working-tree = !git stash show -p | git apply && git stash drop

Maintenant je peux juste taper

git apply-stash-to-dirty-working-tree

ce qui fonctionne très bien pour moi.

(Votre kilométrage peut varier sur ce long nom d'alias. Mais j'aime une dose de verbosité quand il s'agit de terminer bash.)

tapis
la source
3

Vous pouvez appliquer une réserve à un arbre "sale" en effectuant un git addpour mettre en scène toutes les modifications que vous avez apportées, nettoyant ainsi l'arbre. Ensuite, vous pouvez git stash popet appliquer les modifications cachées, pas de problème.

Chris Vandevelde
la source
2

Vous avez des fichiers qui ont été modifiés mais non validés. Soit:

git reset --hard HEAD (to bring everything back to HEAD)

ou, si vous souhaitez enregistrer vos modifications:

git checkout -b new_branch
git add ...
git commit
git checkout -b old_branch
git stash pop
brool
la source
1
@MikeCooper - Je pense qu'il voulait simplement dire ajouter ce que vous voulez ajouter avant de vous engager.
sscirrus
0

J'ai eu le même problème mais git n'avait aucun fichier modifié. Il s'avère que j'avais un fichier index.lock qui traînait. Le supprimer a résolu le problème.

en boîte
la source
0

J'ai été incapable de faire fonctionner la plupart de ces derniers; pour une raison quelconque, il pense toujours que j'ai des modifications locales dans un fichier. Je ne peux pas appliquer de réserve, les correctifs ne s'appliqueront pas checkoutet reset --hardéchoueront. Ce qui a finalement fonctionné a été de sauvegarder la réserve en tant que branche avec git stash branch tempbranchname, puis de faire une fusion de branche normale: git checkout masteret git merge tempbranchname. Depuis http://git-scm.com/book/en/Git-Tools-Stashing :

Si vous voulez un moyen plus simple de tester à nouveau les modifications cachées, vous pouvez exécuter git stash branch, qui crée une nouvelle branche pour vous, vérifie le commit sur lequel vous étiez lorsque vous avez caché votre travail, réapplique votre travail là-bas, puis supprime le cacher s'il s'applique avec succès

rwilson04
la source