L'uso di Git Stash come flusso di lavoro è un antipattern?


25

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 del ramo delle caratteristiche che sembra funzionare bene.

Ho anche visto alcune persone nel nostro team utilizzare il flusso di lavoro basato su git stash . Il flusso di lavoro va in questo modo:

  • Lavora su un ramo principale (come master)
  • Impegnati mentre procedi
  • Se è necessario ottenere modifiche o cambiare ramo, spingere le modifiche senza commit sullo stash
  • Al termine dell'aggiornamento, rimuovere le modifiche dalla scorta.

Dovrei menzionare che questo flusso di lavoro viene utilizzato al posto di un flusso di lavoro di diramazione di funzionalità. Invece di prendere un ramo e lavorarci su, gli sviluppatori qui lavorano sempre e solo su un singolo ramo e spingono / saltano fuori dallo stack come ritengono opportuno.

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

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


2
Potresti provare a chiedere ai tuoi colleghi se hanno avuto problemi con il flusso di lavoro. Se non lo hanno, non lo considero dannoso.
AlexFoxGill

@AlexG Questo è un punto valido. Sto facendo la domanda qui per vedere se ci sono "gotchas" che la gente ha trovato.
joshin4colours,

3
Se lo capisco correttamente ... If you need to get changes or switch branches, push your uncommitted changes onto the stash- questo è esattamente lo scopo della scorta.

3
@MichaelT La mia filiale locale consente tutto. Incondizionatamente.
maaartinus,

2
Il mio modello è: -> non usare git stash -> usa i rami delle caratteristiche -> salva i lavori in corso con un messaggio di commit di 'wip'. -> rebase interattivo sul ramo per schiacciare le salviette in un unico commit significativo ma solo per le modifiche locali e non eliminate . -> push to remote -> unisci in master (e premi) come appropriato per il tuo flusso di lavoro git.
Michael Durrant,

Risposte:


31

Dal libro Git SCM :

Spesso, quando hai lavorato su una parte del tuo progetto, le cose sono in uno stato disordinato e vuoi cambiare un po 'i rami per lavorare su qualcos'altro. Il problema è che non vuoi impegnarti a metà del lavoro solo per tornare più tardi a questo punto. La risposta a questo problema è il comando git stash.

Lo stashing prende lo stato sporco della directory di lavoro, ovvero i file tracciati modificati e le modifiche graduali, e lo salva su una serie di modifiche non completate che è possibile riapplicare in qualsiasi momento.

Data questa descrizione, direi che si tratta di un modello anti. Una spiegazione eccessivamente semplificata di Git Stash sarebbe che si tratta del "taglia e incolla" del controllo del codice sorgente. Prendi un sacco di file modificati, li "nascondi" in una penna di tenuta al di fuori del normale flusso di lavoro di ramificazione di Git, quindi riapplica quelle modifiche a un ramo diverso in un secondo momento.

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

Si riduce davvero a questo:

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

Informazioni sul commit del codice "non funzionante"

Mentre quanto segue è opinione, sono arrivato a questa opinione per esperienza.

Impegnarsi presto e impegnarsi spesso. Impegna tutto il codice non funzionante che desideri. Visualizza la cronologia di commit locale come "punti di salvataggio" mentre fai qualcosa. Dopo aver svolto un lavoro logico, fai un commit. Certo, potrebbe spezzare tutto, ma non importa se non spingi questi impegni. Prima di spingere, rebase e schiaccia i tuoi commit.

  1. Crea una nuova filiale
  2. Hack hack hack
  3. Commettere codice non funzionante
  4. Lucida il codice e fallo funzionare
  5. Commettere il codice di lavoro
  6. Rebase e Squash
  7. Test
  8. Spingere al superamento dei test

Per l'OP, questo thread di messaggi kernal di Linux potrebbe essere interessante, perché sembra che alcuni membri del team dell'OP stiano usando Git in modo simile.

@RibaldEddie ha detto in un commento qui sotto:

Prima di tutto, una scorta non è al di fuori di un "flusso di lavoro ramificato" poiché sotto il cofano una scorta è solo un altro ramo.

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

Linus disse:

Con "git stash", puoi avere anche più cose stash diverse, ma non si mettono in coda l'una sull'altra - sono solo patch indipendenti casuali che hai nascosto perché erano scomode a un certo punto.

Quello che penso che @RibaldEddie sta cercando di dire è che è possibile utilizzare git stashin un flusso di lavoro del ramo delle funzionalità - e questo è vero. Non è l'uso di git stashquesto è il problema. È la combinazione di impegnarsi a padroneggiare e usare git stash. Questo è un modello anti.

chiarire git rebase

Dal commento di @ RibaldEddie:

Il rifacimento è molto più simile al copia-incolla e ancora peggio modifica la cronologia impegnata.

(Enfasi mia)

La modifica della cronologia di commit non è una cosa negativa, purché si tratti di cronologia di commit locale . Se rebase si impegna per aver già spinto, in sostanza rimarrai orfano chiunque utilizzi il tuo ramo. Questo non va bene.

Ora, supponi di aver fatto diversi commit nel corso di una giornata. Alcuni impegni sono stati buoni. Alcuni ... non così bene. Il git rebasecomando in combinazione con la compressione dei commit è un buon modo per ripulire la cronologia dei commit locali. È bello unirsi in un commit per le filiali pubbliche perché mantiene pulita la cronologia delle commit delle filiali condivise del tuo team. Dopo il rebasing, ti consigliamo di eseguire nuovamente il test, ma se i test vengono superati puoi eseguire un commit pulito anziché più sporco.

C'è un altro thread del kernel Linux interessante nella cronologia di commit pulita .

Ancora una volta, da Linus:

Voglio una storia pulita, ma ciò significa davvero (a) storia pulita (b).

Le persone possono (e probabilmente dovrebbero) rifare il proprio albero privato (il proprio lavoro). Questa è una pulizia . Ma mai il codice di altre persone. Questa è una "storia distrutta"

Quindi la parte della storia è abbastanza semplice. C'è solo una regola principale e un piccolo chiarimento:

  • Non devi mai MAI distruggere la storia di altre persone. Non devi reimpostare gli impegni presi da altre persone. Fondamentalmente, se non ha il tuo consenso, è vietato: non puoi rifarlo, perché non è tuo.

    Si noti che si tratta davvero della storia di altre persone , non del codice di altre persone . Se ti hanno inviato materiale come patch via e-mail e l'hai applicato con "git am -s", allora è il loro codice, ma è la tua cronologia.

    Quindi puoi scatenarti sulla cosa "git rebase", anche se non hai scritto il codice, purché il commit stesso sia il tuo privato.

  • Minori chiarimenti sulla regola: una volta che hai pubblicato la tua cronologia in un sito pubblico, altre persone potrebbero usarla, quindi ora chiaramente non è più la tua storia privata .

    Quindi il piccolo chiarimento è che non si tratta solo del "tuo impegno", ma anche del fatto che è privato per il tuo albero, e non l'hai spinto fuori e non lo hai ancora annunciato.

...

Ora la parte "pulita" è un po 'più sottile, sebbene le prime regole siano abbastanza ovvie e facili:

  • Mantieni la tua cronologia leggibile

    Alcune persone lo fanno semplicemente risolvendo prima le cose e non commettendo errori. ma è molto raro, e per il resto di noi, usiamo "git rebase" ecc. mentre lavoriamo sui nostri problemi.

    Quindi "git rebase" non è sbagliato. Ma è giusto solo se è il tuo albero git PRIVATO MOLTO PROPRIO.

  • Non esporre la tua merda.

    Questo significa: se sei ancora nella fase di "git rebase", non lo spingi fuori. Se non è pronto, invii patch in giro o usi git tree privati ​​(proprio come una "sostituzione di serie di patch") di cui non parli al grande pubblico.

(enfatizzare il mio)

Conclusione

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

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

Ci sono due problemi qui:

  1. Gli sviluppatori si stanno impegnando a padroneggiare. Bloccalo immediatamente. Davvero, questo è il problema più grande .
  2. Gli sviluppatori utilizzano git stashe git pullpadroneggiano costantemente quando dovrebbero utilizzare i rami delle funzionalità.

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

Il loro uso di git stashun'aringa rossa. Non è il problema. Impegnarsi a padroneggiare è il problema.


4
Wow, questo non è giusto. Prima di tutto, una scorta non è al di fuori di un "flusso di lavoro ramificato" poiché sotto il cofano una scorta è solo un altro ramo. L'idea che si tratti di un flusso di lavoro copia-incolla non ha senso. Rebasing è molto più simile al copia-incolla e ancora peggio modifica la cronologia impegnata. Infine, il flusso di lavoro è completamente inutile non appena è necessario condividere i lavori in corso con i colleghi poiché si interrompe non appena si spingono le modifiche. Come questo abbia sei voti positivi è sbalorditivo.
RibaldEddie,

8
@RibaldEddie: non c'è nulla di sbagliato nel reimpostare e riscrivere la cronologia di commit purché sia ​​la cronologia di commit locale. Una volta che spingi questi commit, il tuo commento sarebbe corretto, ma rileggi la mia risposta. Dice: "Prima di spingere, rebase e schiaccia i tuoi impegni". Questa è la cronologia di commit locale , che è interamente sotto il tuo controllo.
Greg Burghardt,

1
@RibaldEddie: ho chiarito la mia risposta. Aveva bisogno di un po 'di pulizia.
Greg Burghardt,

Fornirò un po 'più di contesto in una mia risposta.
RibaldEddie,

Vedi la mia risposta qui sotto-- mentre impegnarsi a padroneggiare è un anti-schema, non è il vero problema.
RibaldEddie,

7

Personalmente lo uso solo stashper brevi e inaspettate interruzioni, come qualcuno che fa una domanda che richiede il passaggio a un altro ramo. Lo faccio perché prima mi ero dimenticato degli stash, quindi non si sarebbero applicati in modo pulito. I commit regolari sui rami delle caratteristiche sono molto più difficili da dimenticare e più facili da unire, quindi ora tendo a fare solo un commit non funzionante, quindi fare un git reset HEAD~1o un rebase se non voglio mantenerlo in seguito.

Tuttavia, la cosa grandiosa del controllo della versione distribuita è che le persone possono usare il loro flusso di lavoro preferito nei propri repository, purché i repository condivisi soddisfino gli standard. Mi assicurerei che le persone non stiano semplicemente usando un stashflusso di lavoro perché non hanno abbastanza formazione o consapevolezza delle alternative, ma se scelgono ancora un flusso di lavoro trovi subottimale, lo lascerei.


1

Penso che la parte della tua domanda che sia un anti-pattern sia l'uso di un singolo ramo master condiviso . Tuttavia, se dovessi includere un ramo di sviluppo oltre al ramo principale e quindi utilizzare gli stash per gestire i tuoi cambi di contesto nel ramo di sviluppo, questo non sarebbe un anti-modello e rispecchia molto da vicino parte del flusso di lavoro descrivono da organizzazioni come Etsy e Facebook.

Detto questo, la risposta di @Greg Burghardt sopra è un po 'troppo favorevole per il cosiddetto flusso di lavoro git-flow o ramo di feature. Sostenevo una strategia simile, ma dopo aver realizzato che aggiunge complessità inutili e crea un falso senso di sicurezza, non lo faccio più. È anche un passaggio dai tempi dei sistemi di controllo della versione non decentralizzati come la sovversione.

In primo luogo poiché Git è un sistema di controllo della versione decentralizzato a differenza della sovversione, il repository locale di uno sviluppatore è essenzialmente un ramo gigante del codice in sé e per sé. Ciò che un individuo sviluppa localmente non lo fa e non dovrebbe avere un impatto sugli altri membri del team a meno che il codice non funzionante o errato venga trasferito a qualsiasi ramo condiviso in un repository condiviso.

Il comando rebase, tuttavia, può danneggiare la cronologia del ramo in caso di conflitto di unione in uno dei commit riprodotti. Da http://ryantablada.com/post/the-dangers-of-rebasing-a-branch

Il resto del rebase procede senza intoppi, tutti i test sembrano passare. Viene effettuata una PR.

E poi viene scritto altro codice che si basa sulla proprietà commentiForAllPosts e tutto viene interrotto. Ma chi andiamo a chiedere aiuto? git blame mostra che la riga di codice è stata scritta solo dall'ingegnere lato server e alza le mani.

Ora il tuo ingegnere front-end è in vacanza, congedo per malattia o chi lo sa. Nessuno può capire come dovrebbe essere quel codice!

Rebase ha ucciso la capacità della squadra di guardare la storia per scoprire cosa è andato storto perché tutti i conflitti di unione sul ramo figlio vengono uccisi e il codice originale viene perso per sempre.

Se lo stesso conflitto di unione emergesse e si utilizzasse l'unione, la colpa mostrerebbe che quella riga di codice era stata toccata nel processo di unione, il commit sul ramo padre e il commit sul ramo figlio. Alcuni giocano con le tre permutazioni e puoi riportare l'intento originale nella base di codice e lavorare senza una tonnellata di testa che gratta un dito puntato. E tutto ciò che hai davvero avuto è stato un altro impegno

Inoltre, un modello di diramazione multipla presuppone che due rami non possano mai contenere modifiche di codice interdipendenti. Quando ciò si verifica inevitabilmente, lo sviluppatore deve ora destreggiarsi tra più rami per funzionare in modo efficiente.

L'anti-pattern fondamentale che vedo non è legato ai rami rispetto agli stash, ma piuttosto ai tipi di problemi di cui alcune persone molto intelligenti parlano da un po 'di tempo: hai fiducia nel tuo codice usando l'uso di unit test e una buona architettura? Sei in grado di apportare modifiche incrementali al tuo codice in modo tale che i tuoi sviluppatori possano ragionare facilmente sulle modifiche e capire cosa farà una modifica? I tuoi sviluppatori hanno persino eseguito il nuovo codice una volta per vedere se funziona davvero? (Sì, l'ho già visto prima).

Se la risposta a queste domande è no, allora non importa davvero quanti rami hai-- gli sviluppatori diranno che il codice è pronto, funzionante e adatto alla produzione quando non lo è davvero, e nessun numero di filiali lo farà aiutarti quando quel codice arriva alla produzione comunque.


2
Il tuo commento sul rebasing che ha problemi con la risoluzione di unione non è vero. Un rebase è lo stesso tipo di unione di una fusione effettiva. Git sta solo fondendo impegni sotto il cofano. Il rifacimento e la risoluzione di un conflitto di unione non danneggiano la cronologia di commit. Riclassificare e risolvere in modo improprio un conflitto di unione danneggia le cose, il che è altrettanto probabile con una fusione normale. Devo ammettere che i rami delle funzionalità aggiungono complessità, ma ciò potrebbe essere una complessità necessaria se gli sviluppatori devono destreggiarsi tra più modifiche non correlate.
Greg Burghardt,

Quindi stai dicendo che le fusioni possono distruggere la storia ?! Sembra che sia solo una giustificazione in più per evitare di avere troppi rami!
RibaldEddie,

1
Le fusioni non possono distruggere la storia. Penso che potresti fraintendere il modo in cui il rebasing e la fusione funzionano. Quando viene attivato un conflitto di fusione, spetta all'umano risolverlo. Se l'umano lo risolve in modo errato, non puoi incolpare Git (o SVN, o CVS o {inserire qui il controllo del codice sorgente}).
Greg Burghardt,

Ora quello che stai dicendo è in conflitto con quello che hai detto prima. Hai letto l'articolo da cui ho citato? Comprendi il contesto in cui un rebase perderà la storia?
RibaldEddie,

1
Ho letto l'articolo. "Alla Keen proviamo a spingere il nostro codice dopo quasi ogni commit." Mi sembra folle. O stanno effettuando commit eccessivamente grandi, o stanno spingendo fuori codice che non è ancora pronto. Se rendi pubblici tutti i tuoi commit immediatamente, allora sì, il rebasing causerà problemi. È il principio "Dottore, dottore, mi fa male quando faccio questo".
Kyralessa,

1

git stashè uno strumento. Di per sé non è un modello, né un modello. È uno strumento, proprio come un martello è uno strumento. L'uso di un martello per guidare i chiodi è un modello e l'uso di un martello per guidare le viti è un modello anti. Allo stesso modo, ci sono flussi di lavoro e ambienti in cuigit stash è lo strumento corretto da usare e flussi di lavoro e ambienti in cui è sbagliato.

Il flusso di lavoro "tutti si impegnano e spingono verso la linea principale" è un flusso che funziona abbastanza ragionevolmente in assenza di cambiamenti ad alto rischio. Viene spesso utilizzato in ambienti svn in cui esiste un server centrale autorevole che ha il codice.

Git, tuttavia, lega per eliminare il server centrale unico. Avere tutti gli sviluppatori che fanno commit, pull(orebase se siete in quella), pushper tutto il tempo può fare un gran casino.

I maggiori problemi si presentano con che hai qualcosa in corso che è rotto e devi lavorare su un bug prioritario. Questo significa che devi mettere da parte quel lavoro per un po ', prendere l'ultimo, lavorare su quello senza che il precedente lavoro in corso causi problemi con la build che stai cercando di fare.

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

Vi è, tuttavia, un problema più grande in agguato 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 imballaggio sono tutti su Master. Questo è un problema (Vedi Strategie di ramificazione SCM avanzate per ulteriori informazioni su questo approccio alle filiali)

E sì, hai detto che non è un ottimo flusso di lavoro e che ci sono problemi. Tuttavia, il problema non è con lo strumento git stash. Il problema è la mancanza di ramificazioni distinte per ruoli o per politiche incompatibili .

git stashtuttavia, è qualcosa che ho usato quando ho avuto una situazione in cui ho costruito per un po ', sono entrato in uno stato appiccicoso che non ero sicuro se fosse quello giusto ... quindi ho nascosto le mie modifiche e quindi esplorato un altro approccio per risolvere il problema. Se ha funzionato, ottimo, scarta la roba sulla scorta e continua. Se l'altra esplorazione è diventata più rigida, ripristina la modifica precedente e riapplica lo stash per lavorarci su. L'alternativa sarebbe quella di eseguire il commit, il checkout, il branch e quindi continuare su questo nuovo branch o tornare indietro e ripristinarlo. La domanda è: vale davvero la pena metterlo nella storia quando è solo qualcosa che voglio esplorare per un po '?

git stashnon è un anti schema. Usare git stashcome alternativa alla ramificazione mentre tutti si impegnano con il Master è un modello anti - ma non a causa digit stash .

Se non l'hai ancora raggiunto, aspetta solo di avere problemi con le build , quando qualcuno deve apportare modifiche significative all'architettura a molti file (e i conflitti di unione) o un codice di lavoro in corso non testato che fuoriesce dalla produzione per questo anti-pattern per raggiungerti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.