Ne stocker que les modifications non échelonnées dans Git


230

J'aimerais effectuer le flux de travail suivant:

  1. Ajoutez des modifications à la scène.
  2. Stockez toutes les autres modifications qui n'ont pas été mises en scène.
  3. Faites des choses avec les choses à l'étape (par exemple, construire, exécuter des tests, etc.)
  4. Appliquez la cachette.

Existe-t-il un moyen de faire l'étape 2?

Exemple

 echo "123" > foo
 git add foo # Assumes this is a git directory
 echo "456" >> foo
 git stash
 cat foo # Should yield 123

Pourquoi ne pas valider vos modifications après les avoir mises en scène?
Shizzmo

3
IIRC --keepindex fait exactement cela
sehe

4
Parce que si, disons, la construction échoue, je ne veux pas que cela soit validé. Je sais que je peux supprimer le commit mais j'aimerais le faire sans commit si possible.
Unapiedra

Voyons, merci. Je peux confirmer que cela fonctionne. Gee, j'ai regardé le manuel sur linux.die.net/man/1/git-stash qui est obsolète. man git stashc'est beaucoup mieux.
Unapiedra

c'est --keep-index, fwiw.
jaf0

Réponses:


289

git stash savea une option --keep-indexqui fait exactement ce dont vous avez besoin.

Alors, cours git stash save --keep-index.


9
Vrai. Je continue à utiliser saveavec git stash. C'est peut-être le programmeur en moi qui insiste pour respecter la symétrie avec apply / pop. :)
vhallac

105
Remarque: cela cache toujours toutes vos modifications; la seule différence par rapport à regular git stash saveest qu'il laisse également les modifications déjà mises en scène dans votre copie de travail. Dans le flux de travail ci-dessus, cela fonctionnerait bien car vous appliquez simplement la cachette au-dessus d'une copie locale qui a déjà la moitié des modifications de la cachette (ce que git est assez intelligent pour ignorer). Mais si vous modifiez le code avant de réappliquer le stash, vous pouvez potentiellement voir des conflits de fusion lorsque vous allez appliquer. Fyi.
peterflynn

2
@ytpete Cela m'a mordu tant de fois. Je souhaite vraiment qu'il y ait un moyen pour git de ne cacher que les choses que vous ne gardez pas ... Je commets souvent des trucs, puis je fais un git stash complet, sachant que je peux git commit --ammends'il y a des problèmes dans ce que j'ai commis.
rjmunro

1
--amend(plutôt que --ammend)
Rhubbarb

19
Cette solution ne fonctionne pas pour moi en raison des problèmes décrits par peterflynn. Ce n'est pas une bonne réponse à la question car elle cache toujours les changements par étapes. Quelqu'un a une meilleure solution?
user643011

43

Cela peut se faire en 3 étapes: enregistrer les modifications par étapes, cacher tout le reste, restaurer l'index avec les modifications par étapes. Ce qui est essentiellement:

git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^

Cela fera exactement ce que vous voulez.


3
Remarque: -ustocke également les fichiers non suivis.
ma11hew28

Cette approche reproduit essentiellement ce qui git stash save --keep-indexfait avec beaucoup plus de travail. Je ne vois aucun avantage.
Inigo

1
@vas Non, l'approche ne fait pas double emploi avec cela. Voir le commentaire de peterflynn sur la réponse acceptée.
Alexander Klauer

28
git stash save --keep-index

Aussi, Re:

Pourquoi ne pas valider vos modifications après les avoir mises en scène? - Shin

R: Parce que vous devez toujours archiver le code testé :) Cela signifie que vous devez exécuter les tests avec uniquement les modifications que vous êtes sur le point de valider

Tout cela mis à part le fait que, bien sûr, en tant que programmeur expérimenté, vous avez l'envie innée de tester et de réviser uniquement ces changements - ne plaisantant qu'en partie


14

Avec git version 2.7.4vous pouvez faire:

git stash save --patch

Le gitvous demandera d'ajouter ou non vos modifications dans la cachette.
Et vous répondez alors simplement youn

Vous pouvez restaurer le répertoire de travail comme vous le faites toujours:

git stash pop

ou, si vous souhaitez conserver les modifications enregistrées dans la réserve:

git stash apply

C'est génial. C'est un peu laborieux, mais au moins vous pouvez ignorer et ajouter des fichiers entiers.
Dustin Oprea

5

En étendant les réponses précédentes, j'ai parfois un ensemble complexe de changements mis en scène, mais je souhaite d'abord valider un changement distinct. Par exemple, j'ai peut-être repéré un bogue ou un autre code incorrect que j'aimerais corriger avant mes modifications par étapes. Une voie possible à suivre est la suivante:

cache d'abord tout, mais laisse les changements par étapes intacts

$ git stash save --keep-index [--include-untracked]

maintenant également les modifications mises en scène séparément

$ git stash save

apporter des modifications pour corriger; et test; les engager:

$ git add [--interactive] [--patch]

$ git commit -m "fix ..."

maintenant restaurez les modifications précédemment mises en scène:

$ git stash pop

résoudre tout conflit, et notez que s'il y avait des conflits, git aura appliqué mais pas supprimé cette entrée de la première réserve.

(... Ensuite, validez les modifications par étapes, restaurez la cachette de toutes les autres modifications et continuez ...)


4

Pour ajouter les fichiers non marqués (non ajoutés à la validation) à la stash, exécutez la commande suivante:

git stash -k

Ensuite, vous pouvez valider les fichiers intermédiaires. Après cela, vous pouvez récupérer les derniers fichiers cachés en utilisant la commande:

git stash pop

4

Cacher uniquement l'arbre de travail (modifications non mises en scène) dans Git est plus difficile qu'il ne devrait l'être. La réponse acceptée cache les modifications non mises en scène , mais aussi les modifications mises en scène (et les laisse également mises en scène), ce qui est rarement ce que vous voulez.

Cet alias fonctionne bien:

stash-working = "!f() { \
  git commit --quiet -m \"temp for stash-working\" && \
  git stash push \"$@\" && \
  git reset --quiet --soft HEAD~1; }; f"

Il valide temporairement les modifications par étapes, crée une cachette à partir des modifications restantes (et permet à des arguments supplémentaires tels que --include-untrackedet --messaged'être passés comme arguments d'alias), puis réinitialise la validation temporaire pour récupérer les modifications par étapes.

Il est similaire à la réponse de @Simon Knapp , mais avec quelques différences mineures - il utilise --quietles actions temporaires prises, et il accepte n'importe quel nombre de paramètres pour le stash push, plutôt que de coder en dur le -m, et il ajoute --softà la finale réinitialiser de sorte que l'index reste tel qu'il a commencé.

Pour le problème opposé de ne cacher que les modifications échelonnées (alias stash-index), consultez cette réponse .


2

Un autre conseil, lié à la question:

Lorsque vous stockez efficacement vos modifications non mises en scène à l'aide de

$ git stash save --keep-index

vous souhaiterez peut-être donner un message à la cachette, de sorte que lorsque vous ferez, git stash listil sera plus évident de savoir ce que vous avez caché auparavant, surtout si vous suivez cette opération de cachette par d'autres sauvegardes. Par exemple

$ git stash save --keep-index "changements pas encore mis en scène"

(bien qu'en réalité il contienne tous les changements comme indiqué dans les autres réponses).

Par exemple, ce qui précède peut être immédiatement suivi par:

$ git stash save "modifications par étapes pour la fonctionnalité X"

Attention, cependant, vous ne pouvez pas utiliser

$ git stash appliquer "stash @ {1}" ### ✘ ne fait pas tout à fait ce que vous pourriez souhaiter

pour restaurer uniquement les modifications non mises en scène.


2

Git n'a pas de commande qui ne cache que vos modifications non mises en scène.

Git vous permet cependant de spécifier les fichiers que vous souhaitez cacher.

git stash push --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

Si vous souhaitez uniquement cacher des modifications spécifiques dans ces fichiers, ajoutez l' --patchoption.

git stash push --patch --message 'Unstaged changes' -- app/controllers/products_controller.rb test/controllers/products_controller_test.rb

L' --include-untrackedoption vous permet de cacher des fichiers non suivis.

git stash push --include-untracked --message 'Untracked files' -- app/controllers/widgets_controller.rb test/controllers/widgets_controller_test.rb

Exécutez git help stash(ou man git-stash) pour plus d'informations.

Remarque: Si vos modifications non mises en scène sont plutôt désorganisées, la réponse de @ alesguzik est probablement plus facile.


0

La forme moderne de cette commande est git stash push [--] [<pathspec>...], puisque Git 2.16+ ( git stash saveest déconseillé )

Vous pouvez combiner cela avec un formulaire générique, par exemple:

git stash push --all --keep-index ':(glob)**/*.testextension' 

Mais cela ne fonctionne pas bien avec Git pour Windows, jusqu'à Git 2.22 (Q2 2019), voir le problème 2037 , considérant qu'il git stasha été réimplémenté en C (au lieu d'un script shell)

Voir commit 7db9302 (11 mars 2019) par Thomas Gummerer (tgummerer ) .
Voir commit 1366c78 , commit 7b556aa (07 mars 2019) par Johannes Schindelin ( dscho) .
(Fusionné par Junio ​​C Hamano - gitster- en commit 0ba1ba4 , 22 avril 2019)

intégré stash: gérer à :(glob)nouveau les spécifications de chemin

Lors de la transmission d'une liste de pathspec à, disons, git addnous devons faire attention à utiliser le formulaire d'origine, pas la forme analysée des pathspec.

Cela fait une différence, par exemple lors de l'appel

git stash -- ':(glob)**/*.txt'

où le formulaire d'origine inclut le :(glob)préfixe tandis que le formulaire analysé ne le fait pas.

Cependant, dans la version intégrée git stash, nous avons passé le formulaire analysé (c'est-à-dire incorrect) et git addéchouerions avec le message d'erreur:

fatal: pathspec '**/*.txt' did not match any files

à l'étape où git stashsupprime les modifications de l'arbre de travail, même si elle refs/stasha été effectivement mise à jour avec succès.


0

J'utilise un alias, qui accepte une chaîne à utiliser comme message pour l'entrée cachée.

mystash = "!f() { git commit -m hold && git stash push -m \"$1\" && git reset HEAD^; }; f"

Lequel:

  • valide tout dans l'index,
  • cache ce qui est changé dans l'arbre de travail (pourrait bien sûr ajouter -uou-a ),
  • réinitialise le dernier commit à l'essai de travail (peut vouloir utiliser --softpour le garder dans l'index).
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.