L'utilisation de Git Stash comme workflow est-elle un contre-modèle?

25

J'ai récemment étudié comment moi et mon équipe utilisons Git et comment nos workflows fonctionnent. Nous utilisons actuellement un workflow de branche de fonctionnalité qui semble bien fonctionner.

J'ai également vu certaines personnes de notre équipe utiliser un flux de travail basé sur git stash . Le flux de travail ressemble à ceci:

  • Travailler sur une branche principale (comme master)
  • Faites des commits au fur et à mesure
  • Si vous devez obtenir des modifications ou changer de branche, placez vos modifications non validées dans la mémoire
  • Une fois votre mise à jour terminée, sortez les modifications de la cachette.

Je dois mentionner que ce flux de travail est utilisé à la place d' un flux de travail de branche de fonctionnalité. Au lieu de prendre une branche et de travailler dessus, les développeurs ne travaillent ici que sur une seule branche et poussent / sautent la pile comme bon leur semble.

En fait, je ne pense pas que ce soit un excellent flux de travail, et le branchement serait plus approprié que d'utiliser git stash de cette manière. Je peux voir la valeur de git stash comme une opération d'urgence, mais pas pour l'utiliser dans un flux de travail quotidien et régulier.

L'utilisation de git stash régulièrement serait-elle considérée comme un anti-modèle? Si oui, quels sont les problèmes spécifiques qui pourraient survenir? Sinon, quels sont les avantages?

joshin4colours
la source
2
Vous pouvez essayer de demander à vos collègues s'ils ont eu des problèmes avec le flux de travail. S'ils ne l'ont pas fait, je ne le considérerais pas comme nocif.
AlexFoxGill
@AlexG C'est un point valable. Je pose la question ici pour voir s'il y a des "pièges" que les gens ont trouvés.
joshin4colours
3
Si je comprends bien ... If you need to get changes or switch branches, push your uncommitted changes onto the stash- c'est exactement à quoi sert la cachette.
3
@MichaelT Ma succursale locale permet tout. Inconditionnellement.
maaartinus
2
Mon modèle est: -> ne pas utiliser git stash -> utiliser les branches de fonctionnalités -> enregistrer le travail en cours avec un message de validation de «wip». -> rebase interactif sur la branche pour écraser les wip en un seul commit significatif mais uniquement pour vos modifications locales non poussées . -> push to remote -> fusionner dans master (et push) selon votre flux de travail git.
Michael Durrant

Réponses:

31

Extrait du livre Git SCM :

Souvent, lorsque vous travaillez sur une partie de votre projet, les choses sont dans un état désordonné et vous voulez changer de branche pour travailler un peu sur autre chose. Le problème est que vous ne voulez pas faire un commit de travail à moitié fait juste pour pouvoir revenir à ce point plus tard. La réponse à ce problème est la commande git stash.

Le stashing prend l'état sale de votre répertoire de travail - c'est-à-dire vos fichiers suivis modifiés et les changements intermédiaires - et l'enregistre sur une pile de changements inachevés que vous pouvez réappliquer à tout moment.

Compte tenu de cette description, je dirais qu'il s'agit d'un Anti Pattern. Une explication trop simplifiée de Git Stash serait qu'il s'agit du "couper-coller" du contrôle de code source. Vous prenez un tas de fichiers modifiés, les «planquez» dans un stylo en dehors du flux de travail de branchement normal de Git, puis réappliquez ces modifications à une autre branche à une date ultérieure.

Pour revenir un peu plus loin, s'engager à maîtriser est ici le modèle anti . Utilisez des branches. C'est pour cela qu'ils ont été conçus.

Cela se résume vraiment à ceci:

Vous pouvez enfoncer une vis dans le mur et elle tiendra une photo, mais vous devez utiliser un tournevis. N'utilisez pas de marteau lorsque le tournevis est assis juste à côté de vous.

A propos de la validation du code "cassé"

Bien que ce qui suit soit une opinion, je suis arrivé à cette opinion par expérience.

Engagez-vous tôt et engagez-vous souvent. Validez autant de code cassé que vous le souhaitez. Affichez votre historique de validation local en tant que «points de sauvegarde» pendant que vous piratez quelque chose. Une fois que vous avez fait un travail logique, faites un commit. Bien sûr, cela pourrait tout casser, mais cela n'a pas d'importance tant que vous ne poussez pas ces commits. Avant de pousser, rebaser et écraser vos commits.

  1. Créer une nouvelle branche
  2. Hack hack hack
  3. Valider le code cassé
  4. Polir le code et le faire fonctionner
  5. Valider le code de travail
  6. Rebase et Squash
  7. Tester
  8. Poussez lorsque les tests réussissent

Pour l'OP, ce fil de message kernel Linux pourrait être intéressant, car il semble que certains membres de l'équipe de l'OP utilisent Git de manière similaire.

@RibaldEddie a déclaré dans un commentaire ci-dessous:

Tout d'abord, une cachette n'est pas en dehors d'un "workflow de branchement" car sous la hotte, une cachette n'est qu'une autre branche.

(au risque de provoquer la colère de nombreuses personnes)

Linus a déclaré:

Avec "git stash", vous pouvez aussi avoir plusieurs choses cachées différentes, mais elles ne font pas la queue les unes sur les autres - ce sont juste des correctifs indépendants aléatoires que vous avez cachés parce qu'ils étaient gênants à un moment donné.

Ce que je pense que @RibaldEddie essaie de dire, c'est que vous pouvez l'utiliser git stashdans un flux de travail de branche de fonctionnalité - et c'est vrai. Ce n'est pas l'utilisation de git stashqui est le problème. C'est la combinaison de l'engagement à maîtriser et à utiliser git stash. Ceci est un anti motif.

Clarifier git rebase

Du commentaire de @ RibaldEddie:

Le rebasage ressemble beaucoup plus au copier-coller et, pire encore, modifie l'historique engagé.

(Souligner le mien)

La modification de l'historique des validations n'est pas une mauvaise chose, tant qu'il s'agit de l'historique des validations locales . Si vous rebasiez les commits que vous avez déjà poussés, vous serez essentiellement orphelin pour toute autre personne utilisant votre branche. C'est mauvais.

Supposons maintenant que vous ayez effectué plusieurs validations au cours d'une journée. Certains commits étaient bons. Certains ... pas si bons. La git rebasecommande associée à l'écrasement de vos validations est un bon moyen de nettoyer votre historique de validations local. Il est agréable de fusionner en un seul commit avec les branches publiques, car il garde propre l'historique des commit des branches partagées de votre équipe. Après le rebasage, vous voudrez tester à nouveau, mais si les tests réussissent, vous pouvez pousser un commit propre au lieu de plusieurs sales.

Il existe un autre fil intéressant du noyau Linux sur l'historique des validations propres .

Encore une fois, de Linus:

Je veux une histoire propre, mais cela signifie vraiment (a) une histoire propre et (b).

Les gens peuvent (et devraient probablement) rebaser leurs arbres privés (leur propre travail). C'est un nettoyage . Mais jamais les autres peuples ne codent. C'est une "histoire de détruire"

La partie historique est donc assez facile. Il n'y a qu'une seule règle majeure et une précision mineure:

  • Vous ne devez JAMAIS détruire l'histoire des autres peuples. Vous ne devez pas rebaser les engagements d'autres personnes. Fondamentalement, s'il n'a pas votre approbation, il est interdit: vous ne pouvez pas le rebaser, car ce n'est pas le vôtre.

    Notez que cela concerne vraiment l' histoire des autres peuples , pas le code des autres peuples . S'ils vous ont envoyé des trucs sous forme de patch envoyé par e-mail et que vous les avez appliqués avec "git am -s", alors c'est leur code, mais c'est votre historique.

    Ainsi, vous pouvez vous déchaîner sur la chose "git rebase", même si vous n'avez pas écrit le code, tant que la validation elle-même est privée.

  • Clarification mineure de la règle: une fois que vous avez publié votre historique sur un site public, d'autres personnes peuvent l'utiliser, et maintenant ce n'est clairement plus votre historique privé .

    Donc, la clarification mineure est vraiment qu'il ne s'agit pas seulement de "votre commit", mais aussi qu'il est privé de votre arbre, et que vous ne l'avez pas encore poussé et annoncé.

...

Maintenant, la partie "propre" est un peu plus subtile, bien que les premières règles soient assez évidentes et faciles:

  • Gardez votre propre histoire lisible

    Certaines personnes le font simplement en réglant les choses en tête et en ne faisant pas d’erreurs. mais c'est très rare, et pour le reste d'entre nous, nous utilisons "git rebase" etc. pendant que nous travaillons sur nos problèmes.

    Donc, "git rebase" n'est pas faux. Mais ce n'est vrai que si c'est VOTRE TRÈS PROPRE arbre git PRIVÉ.

  • N'exposez pas vos conneries.

    Cela signifie: si vous êtes encore dans la phase "git rebase", vous ne le repoussez pas. S'il n'est pas prêt, vous envoyez des correctifs ou utilisez des arborescences git privées (tout comme un «remplacement de série de correctifs») dont vous ne parlez pas au grand public.

(c'est moi qui souligne)

Conclusion

En fin de compte, l'OP a quelques développeurs qui font ceci:

git checkout master
(edit files)
git commit -am "..."
(edit files)
git stash
git pull
git stash (pop|apply)

Ici, nous avons deux problèmes:

  1. Les développeurs s'engagent à maîtriser. Verrouillez-le immédiatement. C'est vraiment le plus gros problème.
  2. Les développeurs utilisent git stashet git pullmaîtrisent constamment quand ils devraient utiliser des branches de fonctionnalités.

Il n'y a rien de mal à utiliser git stash- en particulier avant un pull - mais utiliser git stashde cette manière est un anti-pattern quand il y a de meilleurs workflows dans Git.

Leur utilisation d' git stashun hareng rouge. Ce n'est pas le problème. S'engager à maîtriser est le problème.

Greg Burghardt
la source
4
Wow, ce n'est pas juste. Tout d'abord, une cachette n'est pas en dehors d'un "workflow de branchement" car sous la hotte, une cachette n'est qu'une autre branche. L'idée qu'il s'agit d'un workflow de copier-coller n'a aucun sens. Le rebasage ressemble beaucoup plus au copier-coller et, pire encore, modifie l'historique engagé. Enfin, votre flux de travail est complètement inutile dès que vous devez partager le travail en cours avec des collègues car il se désagrège dès que vous appuyez sur les modifications. Comment cela a six votes positifs est ahurissant.
RibaldEddie
8
@RibaldEddie: Il n'y a rien de mal à rebaser et à réécrire l'historique des validations tant qu'il s'agit de l'historique des validations locales. Une fois que vous avez poussé ces validations, votre commentaire serait correct, mais relisez ma réponse. Il dit: "Avant de pousser, rebaser et écraser vos commits." C'est l' historique des validations locales , qui est entièrement sous votre contrôle.
Greg Burghardt
1
@RibaldEddie: J'ai clarifié ma réponse. Il avait besoin d'un peu de nettoyage.
Greg Burghardt du
Je fournirai un peu plus de contexte dans une réponse à moi.
RibaldEddie
Voir ma réponse ci-dessous - tout en s'engageant à maîtriser est un anti-modèle, ce n'est pas le vrai problème.
RibaldEddie
7

Personnellement, je n'utilise que stashpour des interruptions courtes et inattendues, comme quelqu'un qui pose une question qui nécessite de changer de branche. Je fais cela parce que j'ai déjà oublié des cachettes, alors elles ne s'appliqueraient pas proprement. Les validations régulières sur les branches de fonctionnalités sont beaucoup plus difficiles à oublier et plus faciles à fusionner.J'ai donc tendance à faire une validation cassée, puis à effectuer une git reset HEAD~1ou une rebase si je ne veux pas la conserver plus tard.

Cependant, l'avantage du contrôle de version distribué est que les utilisateurs peuvent utiliser leur flux de travail préféré dans leurs propres référentiels, tant que les référentiels partagés répondent aux normes. Je m'assurerais que les gens n'utilisent pas seulement un stashflux de travail parce qu'ils n'ont pas suffisamment de formation ou de sensibilisation aux alternatives, mais s'ils choisissent toujours un flux de travail que vous trouvez sous-optimal, je le laisserais.

Karl Bielefeldt
la source
1

Je pense que la partie de votre question qui est un anti-modèle est l'utilisation d'une seule branche principale partagée . Cependant, si vous deviez inclure une branche de développement en plus de la branche principale, puis utiliser des stashes pour gérer vos propres changements de contexte dans la branche de développement, ce ne serait pas un anti-modèle, et cela reflète de très près une partie du flux de travail décrire par des organisations comme Etsy et Facebook.

Cela dit, la réponse de @Greg Burghardt ci-dessus est un peu trop favorable au flux de travail dit git-flow ou feature-branch. J'avais l'habitude de plaider pour une stratégie similaire, mais après avoir réalisé qu'elle ajoute une complexité inutile et crée un faux sentiment de sécurité, je ne le fais plus. C'est aussi un vestige de l'époque des systèmes de contrôle de version non décentralisés comme la subversion.

Tout d'abord, puisque Git est un système de contrôle de version décentralisé contrairement à la subversion, le référentiel local d'un développeur est essentiellement une branche géante du code en soi. Ce qu'un individu développe localement n'a pas et ne devrait pas avoir d'impact sur les autres membres de l'équipe à moins que du code cassé ou bogué ne soit poussé vers les branches partagées dans un référentiel partagé.

Cependant, la commande rebase peut endommager l'historique de la branche lorsqu'il y a un conflit de fusion dans l'un des commits rejoués. Depuis http://ryantablada.com/post/the-dangers-of-rebasing-a-branch

Le reste du rebase se déroule sans problème, les tests semblent tous réussir. Un PR est fait.

Et puis un peu plus de code est écrit qui s'appuie sur la propriété commentsForAllPosts et tout est cassé. Mais à qui allons-nous demander de l'aide? git blame montre que la ligne de code n'a été écrite que par l'ingénieur côté serveur et qu'il lève les mains.

Maintenant, votre ingénieur front-end est en vacances, en arrêt maladie ou qui sait. Personne ne peut comprendre à quoi devrait ressembler ce code!

Rebase a supprimé la capacité de l'équipe à consulter l'historique pour trouver ce qui n'allait pas, car tout conflit de fusion sur la branche enfant est tué et le code d'origine est perdu à jamais.

Si ce même conflit de fusion se produisait et que la fusion était utilisée, le blâme montrerait que cette ligne de code avait été touchée dans le processus de fusion, la validation sur la branche parent et la validation sur la branche enfant. Certains jouent avec les trois permutations et vous pouvez retrouver l'intention d'origine dans la base de code et travailler sans qu'une tonne de tête ne se gratte le doigt. Et tout ce que vous aviez vraiment était un autre commit

De plus, un modèle à plusieurs branches suppose qu'aucune branche ne puisse jamais contenir de modifications de code interdépendantes. Lorsque cela se produit inévitablement, le développeur doit maintenant jongler avec encore plus de branches pour fonctionner efficacement.

L'anti-pattern fondamental que je vois n'est pas lié aux branches vs aux stashes, mais plutôt au type de problèmes dont certaines personnes très intelligentes parlent depuis un certain temps maintenant: avez-vous confiance en votre code via l'utilisation de tests unitaires et une bonne architecture? Êtes-vous en mesure d'apporter des modifications incrémentielles à votre code de sorte que vos développeurs puissent facilement raisonner sur les modifications et comprendre ce que fera une modification? Vos développeurs parcourent-ils même le nouveau code une fois pour voir s'il fonctionne réellement? (Oui, je l'ai déjà vu).

Si la réponse à ces questions est non, alors peu importe le nombre de branches que vous avez - les développeurs diront que le code est prêt, fonctionne et adapté à la production alors qu'il ne l'est vraiment pas, et aucun nombre de branches ne le sera. vous aider quand ce code monte en production de toute façon.

RibaldEddie
la source
2
Votre commentaire sur le rebasage ayant des problèmes avec la résolution de fusion n'est pas vrai. Un rebase est le même type de fusion qu'une fusion réelle. Git fusionne juste des commits sous le capot. La redéfinition et la résolution d'un conflit de fusion n'endommagent pas l'historique de validation. Une nouvelle base et une résolution incorrecte d'un conflit de fusion endommagent les choses, ce qui est tout aussi probable avec une fusion normale. Je dois convenir que les branches de fonctionnalités ajoutent de la complexité, mais cela pourrait être une complexité nécessaire si les développeurs doivent jongler avec plusieurs changements non liés.
Greg Burghardt du
Vous dites donc que les fusions peuvent détruire l'histoire?! On dirait que c'est juste une justification supplémentaire pour éviter d'avoir trop de branches!
RibaldEddie
1
Les fusions ne peuvent pas détruire l'histoire. Je pense que vous vous méprenez peut-être sur le fonctionnement du rebasage et de la fusion. Lorsqu'un conflit de fusion est déclenché, c'est à l'humain de le résoudre. Si l'humain le résout incorrectement, vous ne pouvez pas blâmer Git (ou SVN, ou CVS, ou {insérer le contrôle de source ici}).
Greg Burghardt du
Maintenant, ce que vous dites est en conflit avec ce que vous avez dit auparavant. Avez-vous lu l'article que j'ai cité? Comprenez-vous le contexte dans lequel un rebase perdra l'historique?
RibaldEddie
1
J'ai lu l'article. "Chez Keen, nous essayons de pousser notre code après presque chaque commit." Cela me semble fou. Soit ils font des commits excessivement gros, soit ils poussent du code qui n'est pas encore prêt. Si vous rendez tous vos commits publics immédiatement, alors oui, le rebasage causera des problèmes. C'est le principe "Docteur, docteur, ça fait mal quand je fais ça".
Kyralessa
1

git stashest un outil. Ce n'est pas en soi un motif, ni un anti-motif. C'est un outil, un peu comme un marteau est un outil. L'utilisation d'un marteau pour enfoncer les clous est un modèle et l'utilisation d'un marteau pour enfoncer les vis est un anti-modèle. De même, il existe des workflows et des environnements où git stashest l'outil approprié à utiliser, et des workflows et des environnements où il est incorrect.

Le flux de travail «tout le monde s'engage et pousse vers la ligne principale» fonctionne de manière assez raisonnable en l'absence de changements à haut risque. Son souvent vu utilisé dans les environnements svn où il y a un serveur central faisant autorité qui a le code.

Git, cependant, doit se débarrasser du seul serveur central. Avoir tous les développeurs faisant commit, pull(ou rebasesi vous êtes en cela), pushtout le temps peut faire un grand désordre.

Les plus gros problèmes surviennent: vous avez quelque chose en cours qui est cassé et vous devez travailler sur un bug prioritaire. Cela signifie que vous devez mettre un peu de côté ce travail, récupérer le dernier, travailler dessus sans que le travail en cours ne cause des problèmes avec la construction que vous essayez de faire.

Pour cela, git stashserait l'outil approprié à utiliser.

Il existe cependant un problème plus important qui se cache au cœur de ce flux de travail. Est-ce que tous les rôles des branches de contrôle de version sont sur une seule branche. Mainline, développement, maintenance, accumulation et emballage sont tous sur Master. C'est un problème. (Voir Stratégies de branchement SCM avancées pour en savoir plus sur cette approche des succursales)

Et oui, vous avez dit que ce n'était pas un bon flux de travail et qu'il y avait des problèmes. Cependant, le problème n'est pas avec l'outil git stash. Le problème est le manque de branchements distincts pour les rôles ou pour les politiques incompatibles .

git stashcependant, c'est quelque chose que j'ai utilisé quand j'ai eu une situation où j'ai construit un peu, j'ai eu un état collant que je ne savais pas si c'était le bon ... alors j'ai caché mes changements puis a exploré une autre approche pour résoudre le problème. Si cela a fonctionné - super, jetez les trucs sur la cachette et continuez. Si l'autre exploration est devenue plus collante, réinitialisez la modification précédente et réappliquez la cachette pour y travailler. L'alternative serait de valider, de payer, de créer une branche puis de continuer sur cette nouvelle branche ou de revenir en arrière et de la réinitialiser. La question est-elle vraiment la peine de mettre cela dans l'histoire quand c'est juste quelque chose que je veux explorer un peu?

git stashn'est pas un motif anti. Utiliser git stashcomme alternative à la ramification pendant que tout le monde s'engage sur le Master est un anti-modèle - mais pas à cause de git stash.

Si vous ne l'avez pas encore atteint, attendez jusqu'à ce que vous rencontriez des problèmes avec les builds , lorsque quelqu'un doit apporter des modifications architecturales importantes à de nombreux fichiers (et les conflits de fusion) ou à un code de travail en cours non testé qui s'échappe en production pour cela. anti-motif pour vous rattraper.

Communauté
la source