Sta usando Git Stash come flusso di lavoro un antipattern?

24

Di recente ho osservato come io e il mio team utilizziamo Git e come funzionano i nostri flussi di lavoro. Al momento utilizziamo un flusso di lavoro di feature-branch che sembra funzionare bene.

Ho anche visto alcuni individui del nostro team utilizzare il flusso di lavoro basato su git stash . Il flusso di lavoro è simile a questo:

  • Lavora su un ramo principale (come master )
  • Esegui i commit mentre vai
  • Se devi apportare modifiche o cambiare rami, inserisci le modifiche non salvate nella memoria
  • Una volta terminato l'aggiornamento, elimina le modifiche dalla memoria.

Dovrei menzionare che questo flusso di lavoro è usato invece di un flusso di lavoro di feature branch. Invece di prendere una filiale e lavorarci su, gli sviluppatori qui lavorano sempre e solo su un singolo ramo e spingono / spogli dallo stack come meglio credono.

In realtà non penso che questo sia un grande flusso di lavoro, e la ramificazione sarebbe più appropriata dell'uso di git stash in questo modo. Riesco a vedere il valore di git stash come un'operazione di emergenza, ma non per utilizzarlo in un flusso di lavoro quotidiano e regolare.

L'uso di git stash sarebbe considerato un anti-pattern? Se sì, quali sono alcuni problemi specifici che potrebbero sorgere? In caso contrario, quali sono i vantaggi?

    
posta joshin4colours 02.09.2014 - 17:29
fonte

4 risposte

30

Dal Git SCM Book :

Often, when you’ve been working on part of your project, things are in a messy state and you want to switch branches for a bit to work on something else. The problem is, you don’t want to do a commit of half-done work just so you can get back to this point later. The answer to this issue is the git stash command.

Stashing takes the dirty state of your working directory — that is, your modified tracked files and staged changes — and saves it on a stack of unfinished changes that you can reapply at any time.

Data questa descrizione, direi che questo è un Anti Pattern. Una spiegazione eccessivamente semplificata di Git Stash sarebbe che si tratta del "Taglia e incolla" del controllo del codice sorgente. Prendi un mucchio di file modificati, li "riponi" in una penna di tenuta al di fuori del normale flusso di lavoro di branching di Git e poi riapplichi quelle modifiche a un altro ramo in un secondo momento.

Tornando un po 'oltre, impegnarsi a padroneggiare è il modello anti qui. Usa i rami. Questo è quello per cui sono stati progettati.

Si riduce davvero a questo:

Puoi martellare una vite nel muro e questo mostrerà un'immagine, ma usare un cacciavite è ciò che dovresti fare. Non usare un martello quando il cacciavite è seduto proprio accanto a te.

Informazioni sulla registrazione del codice "interrotto"

Mentre il seguente è opinione, sono giunto a questa opinione per esperienza.

Impegnati presto e commetti spesso. Impegna tanto codice spezzato quanto vuoi. Visualizza la tua cronologia di commit locale come "salva punti" mentre fai a pezzi qualcosa. Una volta che hai fatto un lavoro logico, fai un commit. Certo, potrebbe rompere tutto, ma non importa finché non spinge quei commit. Prima di spingere, rebase e schiaccia i tuoi commit.

  1. Crea nuovo ramo
  2. Hack hack hack
  3. Impegna il codice danneggiato
  4. Lucida il codice e fallo funzionare
  5. Impegna codice di lavoro
  6. Rebase e Squash
  7. Prova
  8. Spingi quando i test stanno passando

Per l'OP, questo thread di messaggi kernal di Linux potrebbe essere interessante, perché è un tipo di suoni come alcuni membri del team dell'OP utilizzano Git in modo simile.

@RibaldEddie ha detto in un commento qui sotto:

First of all, a stash is not outside of a "branching workflow" since under the hood a stash is just another branch.

(a rischio di incorrere nell'ira di molte persone)

Linus ha detto:

With "git stash", you can have multiple different stashed things too, but they don't queue up on each other - they are just random independent patches that you've stashed away because they were inconvenient at some point.

Quello che penso che @RibaldEddie stia cercando di dire è che puoi usare git stash in un flusso di lavoro di una feature branch - e questo è vero. Non è l'uso di git stash che è il problema. È la combinazione di commit su master e utilizzo di git stash . Questo è un pattern anti.

Chiarire git rebase

Dal commento di @ RibaldEddie:

Rebasing is much more like copy-pasting and even worse modifies committed history.

(Enfasi mia)

La modifica della cronologia dei commit non è una cosa negativa, purché sia cronologia dei commit locali . Se esegui il rebase di commit che hai già spinto, sarai praticamente orfano di chiunque altro usando il tuo branch. Questo è male.

Ora, dì che hai commesso diversi commit nel corso della giornata. Alcuni commit erano buoni. Alcuni ... non così buoni. Il comando git rebase in combinazione con lo schiacciamento dei tuoi commit è un buon modo per ripulire la cronologia dei commit locale. È bello unire un solo commit ai rami pubblici perché mantiene pulita la cronologia dei commit dei rami condivisi del tuo team. Dopo la ridefinizione, dovrai testare di nuovo, ma se i test passano, puoi spingere un commit pulito invece di alcuni dirty.

C'è un altro interessante thread del kernel di Linux su cancella la cronologia dei commit .

Di nuovo, da Linus:

I want clean history, but that really means (a) clean and (b) history.

People can (and probably should) rebase their private trees (their own work). That's a cleanup. But never other peoples code. That's a "destroy history"

So the history part is fairly easy. There's only one major rule, and one minor clarification:

  • You must never EVER destroy other peoples history. You must not rebase commits other people did. Basically, if it doesn't have your sign-off on it, it's off limits: you can't rebase it, because it's not yours.

    Notice that this really is about other peoples history, not about other peoples code. If they sent stuff to you as an emailed patch, and you applied it with "git am -s", then it's their code, but it's your history.

    So you can go wild on the "git rebase" thing on it, even though you didn't write the code, as long as the commit itself is your private one.

  • Minor clarification to the rule: once you've published your history in some public site, other people may be using it, and so now it's clearly not your private history any more.

    So the minor clarification really is that it's not just about "your commit", it's also about it being private to your tree, and you haven't pushed it out and announced it yet.

...

Now the "clean" part is a bit more subtle, although the first rules are pretty obvious and easy:

  • Keep your own history readable

    Some people do this by just working things out in their head first, and not making mistakes. but that's very rare, and for the rest of us, we use "git rebase" etc while we work on our problems.

    So "git rebase" is not wrong. But it's right only if it's YOUR VERY OWN PRIVATE git tree.

  • Don't expose your crap.

    This means: if you're still in the "git rebase" phase, you don't push it out. If it's not ready, you send patches around, or use private git trees (just as a "patch series replacement") that you don't tell the public at large about.

(sottolineatura mia)

Conclusione

Alla fine, l'OP ha alcuni sviluppatori che fanno questo:

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

Qui ci sono due problemi:

  1. Gli sviluppatori si stanno impegnando a padroneggiare. Bloccalo subito. In realtà, questo è il il più grande problema.
  2. Gli sviluppatori utilizzano costantemente git stash e git pull sul livello principale quando devono utilizzare i rami di funzionalità.

Non c'è niente di sbagliato nell'usare git stash - specialmente prima di un pull - ma usare git stash in questo modo è un pattern anti quando ci sono migliori flussi di lavoro in Git.

Il loro uso di git stash un'aringa rossa. Non è il problema. Il commit del master è il problema.

    
risposta data 02.09.2014 - 18:59
fonte
7

Personalmente uso solo stash per brevi interruzioni inaspettate, come qualcuno che fa una domanda che richiede di passare a un ramo diverso. Lo faccio perché mi sono dimenticato delle cianfrusaglie prima, quindi non si applicano in modo pulito. I commit regolari su feature branch sono molto più difficili da dimenticare e più facili da unire, quindi ora tendo a fare solo un commit interrotto, quindi faccio un git reset HEAD~1 o un rebase se non voglio tenerlo più tardi.

Tuttavia, il bello del controllo della versione distribuita è che le persone possono utilizzare il proprio flusso di lavoro preferito nei propri repository, a patto che i repository condivisi soddisfino gli standard. Mi assicurerei che le persone non utilizzassero solo un flusso di lavoro stash perché non hanno abbastanza formazione o consapevolezza delle alternative, ma se scelgono comunque un flusso di lavoro che si trova non ottimale, lo lascerei.

    
risposta data 03.09.2014 - 05:37
fonte
1

git stash è uno strumento. Di per sé non è un modello, né un anti-modello. È uno strumento, proprio come un martello è uno strumento. Usare un martello per guidare le unghie è un modello e usare un martello per guidare le viti è un modello anti. Allo stesso modo, ci sono flussi di lavoro e ambienti in cui git stash è lo strumento corretto da utilizzare, e flussi di lavoro e ambienti in cui è sbagliato.

Il flusso di lavoro di "tutti si impegnano e spingono alla linea principale" è quello che funziona abbastanza ragionevolmente dove non ci sono cambiamenti ad alto rischio. È visto spesso usato in ambienti svn in cui esiste un server centrale autorevole con il codice.

Git, comunque, è un legame con l'unico server centrale. Se tutti gli sviluppatori fanno commit , pull (o rebase se ci sei dentro), push può fare un gran casino.

I problemi maggiori si verificano quando hai qualcosa in corso che è rotto e devi lavorare su un bug di priorità. Ciò significa che devi mettere da parte quel lavoro per un po ', prendere l'ultimo, lavorare su quel senza che ha il lavoro in corso causa problemi con la build che stai cercando di fare.

Per questo, git stash sarebbe lo strumento adatto da usare.

C'è tuttavia un problema più grande che si nasconde nel cuore di questo flusso di lavoro. È che tutti i ruoli dei rami di controllo versione sono su un singolo ramo. Mainline, sviluppo, manutenzione, accumulo e packaging sono tutti su Master. Questo è un problema. (Vedi Advanced SCM Branching Strategies per ulteriori informazioni su questo approccio alle filiali)

E sì, hai fatto notare che non è un grande flusso di lavoro e che ci sono problemi con esso. Tuttavia, il problema non è con lo strumento git stash . Il problema è la mancanza di ramificazioni distinte per i ruoli o per norme incompatibili .

git stash tuttavia, è qualcosa che ho usato quando ho avuto una situazione in cui ho costruito per un po ', ho avuto uno stato appiccicoso che non ero sicuro se fosse quello giusto .. Così ho nascosto i miei cambiamenti e poi ho esplorato un altro approccio per risolvere il problema. Se ha funzionato, bene, getta via la roba sulla scorta e continua. Se l'altra esplorazione diventa più appiccicosa, ripristina la modifica precedente e riapplica la scorta per lavorarci. L'alternativa sarebbe quella di eseguire il commit, checkout, ramo e quindi continuare su questo nuovo ramo o tornare indietro e ripristinarlo. La domanda è: vale davvero la pena inserirla nella storia quando è solo qualcosa che voglio esplorare per un po '?

git stash non è un pattern anti. L'utilizzo di git stash come alternativa alla ramificazione mentre tutti si impegna sul Master è un pattern anti - ma non a causa di git stash .

Se non l'hai ancora colpito, attendi fino a quando non hai problemi con le build , quando qualcuno ha bisogno per apportare modifiche architettoniche significative a molti file (e ai conflitti di unione) o ad un codice di lavoro in corso non testato che si estende alla produzione per questo anti-pattern per raggiungerti.

    
risposta data 04.09.2014 - 04:51
fonte
0

Penso che la parte della tua domanda che è un anti-pattern sia l'uso di un singolo ramo master condiviso. Tuttavia, se dovessi includere un ramo sviluppare oltre al ramo principale e poi usare le sequenze per gestire le tue opzioni di contesto nel ramo di sviluppo, questo non sarebbe un anti-pattern, e molto da vicino rispecchia alcuni dei flussi di lavoro descritti da organizzazioni come Etsy e Facebook.

Detto questo, la risposta di @Greg Burghardt sopra è un po 'troppo favorevole al cosiddetto flusso di lavoro git-flow o feature-branch. Ero solito sostenere una strategia simile, ma dopo aver compreso che aggiunge complessità inutile e crea un falso senso di sicurezza, non lo faccio più. È anche un residuo dei tempi dei sistemi di controllo delle versioni non decentralizzati come subversion.

Innanzi tutto, dal momento che Git è un sistema di controllo della versione decentralizzato a differenza di quello di subversion, il repository locale di uno sviluppatore è essenzialmente un ramo gigante del codice in sé e per sé. Ciò che uno sviluppatore fa localmente non ha e non dovrebbe avere un impatto sugli altri membri del team a meno che il codice rotto o buggy non venga trasferito su qualsiasi branch condiviso in un repository condiviso.

Il comando rebase, tuttavia, può danneggiare la cronologia del ramo quando si verifica un conflitto di unione in uno dei commit ripetuti. Da link

The rest of the rebase goes along smoothly, tests all seem to pass. A PR is made.

And then some more code is written that relies on the commentsForAllPosts property and everything is broken. But who do we go and ask for help? git blame shows that line of code has only been written by the server side engineer and he throws up his hands.

Now your front-end engineer is out on vacation, sick leave, or who knows. No one can figure out what that code should look like!

Rebase has killed the team's ability to look at the history to find what went wrong because any merge conflicts on the child branch are killed and the original code is lost forever.

If this same merge conflict came up and merge was used, the blame would show that that line of code had been touched in the merge process, the commit on the parent branch, and the commit on the child branch. Some toying around with the three permutations and you can get the original intent back into the code base and working without a ton of head scratching a finger pointing. And all you really had was another commit

Inoltre, un modello di ramificazione multipla presuppone che non ci siano due rami in grado di contenere modifiche di codice interdipendenti. Quando ciò accade inevitabilmente, lo sviluppatore deve ora manipolare ancora più rami per funzionare in modo efficiente.

L'anti-pattern fondamentale che vedo non è correlato a branch vs. stashes, ma piuttosto al tipo di problemi di cui alcune persone molto intelligenti hanno parlato per un po 'di tempo: hai fiducia nel tuo codice tramite l'uso di test unitari e una buona architettura? Sei in grado di apportare modifiche incrementali al tuo codice in modo tale che i tuoi sviluppatori possano ragionare facilmente sui cambiamenti e capire cosa cambierà? I tuoi sviluppatori riescono persino a eseguire il nuovo codice una volta per vedere se effettivamente funziona? (Sì, ho visto prima).

Se la risposta a queste domande è no, allora non importa quanti rami hai ... gli sviluppatori diranno che il codice è pronto, funzionante e adatto alla produzione quando in realtà non lo è, e nessun numero delle filiali ti aiuterà quando il codice salirà comunque alla produzione.

    
risposta data 03.09.2014 - 17:13
fonte

Leggi altre domande sui tag