GitHub Flow

Problemi con git-flow

Viaggio dappertutto insegnando Git alla gente e quasi ogni classe e workshop che ho fatto recentemente mi ha chiesto cosa penso di git-flow. Rispondo sempre che penso che sia fantastico – ha preso un sistema (Git) che ha un milione di possibili flussi di lavoro e ha documentato un flusso di lavoro ben testato e flessibile che funziona per molti sviluppatori in un modo abbastanza semplice. È diventato una specie di standard in modo che gli sviluppatori possano muoversi tra progetti o aziende e avere familiarità con questo flusso di lavoro standardizzato.

Tuttavia, ha i suoi problemi. Ho sentito un certo numero di opinioni da parte della gente sulla falsariga del fatto che non mi piace che i rami delle nuove caratteristiche siano iniziati da develop piuttosto che da master, o il modo in cui gestisce gli hotfix, ma questi sono abbastanza minori.

Uno dei problemi più grandi per me è che è più complicato di quanto penso che la maggior parte degli sviluppatori e dei team di sviluppo abbiano effettivamente bisogno. È abbastanza complicato che è stato sviluppato un grande script di aiuto per aiutare a far rispettare il flusso. Anche se questo è bello, il problema è che non può essere applicato in una GUI di Git, solo sulla linea di comando, quindi le uniche persone che devono imparare davvero bene il complesso flusso di lavoro, perché devono fare tutti i passi manualmente, sono le stesse persone che non sono abbastanza a loro agio con il sistema per usarlo dalla linea di comando. Questo può essere un problema enorme.

Entrambi questi problemi possono essere risolti facilmente semplicemente avendo un processo molto più semplificato. A GitHub, non usiamo git-flow. Usiamo, e abbiamo sempre usato, un flusso di lavoro Git molto più semplice.

La sua semplicità gli dà una serie di vantaggi. Uno è che è facile da capire per le persone, il che significa che possono impararlo velocemente e raramente, se non mai, fanno casino o devono annullare i passi che hanno fatto male. Un altro è che non abbiamo bisogno di uno script wrapper per aiutarci ad applicarlo o seguirlo, quindi l’uso di GUI e simili non sono un problema.

GitHub Flow

Perché non usiamo git-flow su GitHub? Beh, il problema principale è che facciamo deploy tutto il tempo. Il processo git-flow è progettato in gran parte intorno al “rilascio”. Noi non abbiamo davvero “rilasci” perché facciamo il deploy in produzione ogni giorno – spesso più volte al giorno. Possiamo farlo attraverso il nostro robot della chat, che è lo stesso posto in cui vengono visualizzati i nostri risultati CI. Cerchiamo di rendere il processo di test e spedizione il più semplice possibile in modo che ogni dipendente si senta a suo agio nel farlo.

Ci sono una serie di vantaggi nel distribuire così regolarmente. Se si distribuisce ogni poche ore, è quasi impossibile introdurre un gran numero di grossi bug. Piccoli problemi possono essere introdotti, ma poi possono essere corretti e distribuiti nuovamente molto rapidamente. Normalmente si dovrebbe fare un ‘hotfix’ o qualcosa al di fuori del normale processo, ma è semplicemente parte del nostro normale processo – non c’è differenza nel flusso di GitHub tra un hotfix e una caratteristica molto piccola.

Un altro vantaggio di distribuire sempre è la capacità di affrontare rapidamente problemi di ogni tipo. Possiamo rispondere ai problemi di sicurezza che vengono portati alla nostra attenzione o implementare piccole ma interessanti richieste di funzionalità in modo incredibilmente rapido, ma possiamo usare lo stesso identico processo per affrontare questi cambiamenti come facciamo per gestire lo sviluppo di normali o anche grandi funzionalità. È lo stesso processo ed è tutto molto semplice.

Come lo facciamo

Quindi, cos’è GitHub Flow?

  • Tutto ciò che si trova nel ramo master è distribuibile
  • Per lavorare su qualcosa di nuovo, crea un ramo dal nome descrittivo di master (es: new-oauth2-scopes)
  • Commetti su quel ramo localmente e spingi regolarmente il tuo lavoro al ramo con lo stesso nome sul server
  • Quando hai bisogno di feedback o di aiuto, o pensi che il ramo sia pronto per la fusione, apri una richiesta di pull
  • Dopo che qualcun altro ha rivisto e firmato la caratteristica, puoi fonderla in master
  • Una volta che è fusa e spinta in ‘master’, puoi e dovresti distribuirla immediatamente

Questo è l’intero flusso. È molto semplice, molto efficace e funziona per team abbastanza grandi – GitHub ha 35 dipendenti ora, forse 15-20 dei quali lavorano sullo stesso progetto (github.com) allo stesso tempo. Penso che la maggior parte dei team di sviluppo – gruppi che lavorano sullo stesso codice logico allo stesso tempo che potrebbe produrre conflitti – sono intorno a queste dimensioni o più piccoli. Specialmente quelli che sono abbastanza progressivi da fare deployment rapidi e coerenti.

Quindi, guardiamo ognuno di questi passi a turno.

#1 – qualsiasi cosa nel ramo master è deployabile

Questa è fondamentalmente l’unica regola dura del sistema. C’è solo un ramo che ha un significato specifico e coerente e lo abbiamo chiamato master. Per noi, questo significa che è stato distribuito o al peggio sarà distribuito entro poche ore. È incredibilmente raro che questo venga riavvolto (il ramo viene spostato indietro ad un vecchio commit per ripristinare il lavoro) – se c’è un problema, i commit verranno ripristinati o verranno introdotti nuovi commit che risolvono il problema, ma il ramo stesso non viene quasi mai riavvolto.

Il ramo master è stabile ed è sempre, sempre sicuro distribuire da esso o creare nuovi rami da esso. Se spingi qualcosa a master che non è testato o rompe la compilazione, rompi il contratto sociale del team di sviluppo e normalmente ti senti piuttosto male per questo. Ogni ramo che spingiamo ha dei test eseguiti su di esso e riportati nella chat room, quindi se non li hai eseguiti localmente, puoi semplicemente spingere ad un ramo topic (anche un ramo con un singolo commit) sul server e aspettare che Jenkins ti dica se passa tutto.

Si potrebbe avere un ramo deployed che viene aggiornato solo quando si distribuisce, ma noi non lo facciamo. Semplicemente esponiamo il SHA attualmente distribuito attraverso la webapp stessa e lo curlse abbiamo bisogno di un confronto.

#2 – creare rami descrittivi fuori dal master

Quando si vuole iniziare a lavorare su qualcosa, si crea un ramo dal nome descrittivo fuori dal ramo stabile master. Alcuni esempi nel codebase di GitHub in questo momento sarebbero user-content-cache-key, submodules-init-task o redis2-transition. Questo ha diversi vantaggi – uno è che quando si fa il fetch, si possono vedere gli argomenti su cui tutti gli altri hanno lavorato. Un altro è che se si abbandona un ramo per un po’ e ci si ritorna più tardi, è abbastanza facile ricordare cosa fosse.

Questo è bello perché quando andiamo alla pagina della lista dei rami di GitHub possiamo facilmente vedere quali rami sono stati lavorati di recente e approssimativamente quanto lavoro hanno su di essi.

Lista rami di GitHub

E’ quasi come una lista di caratteristiche in arrivo con lo stato attuale approssimativo. Questa pagina è fantastica se non la stai usando – ti mostra solo i rami che hanno un lavoro unico su di loro rispetto al tuo ramo attualmente selezionato e li ordina in modo che quelli su cui si è lavorato più recentemente siano in cima. Se sono davvero curioso, posso fare clic sul pulsante ‘Confronta’ per vedere quale sia l’effettiva lista unificata di diff e commit che è unica per quel ramo.

Così, al momento in cui scrivo, abbiamo 44 rami nel nostro repository con lavoro unmerged in essi, ma posso anche vedere che solo circa 9 o 10 di essi sono stati spinti nell’ultima settimana.

#3 – spingere ai rami nominati costantemente

Un’altra grande differenza da git-flow è che spingiamo ai rami nominati sul server costantemente. Dal momento che l’unica cosa di cui dobbiamo veramente preoccuparci è master dal punto di vista del deployment, spingere sul server non incasina nessuno o confonde le cose – tutto ciò che non è master è semplicemente qualcosa su cui si sta lavorando.

Fa anche in modo che il nostro lavoro abbia sempre un backup in caso di perdita del portatile o di guasto del disco rigido. Ancora più importante, mette tutti in costante comunicazione. Un semplice ‘git fetch’ ti darà fondamentalmente una lista TODO di ciò su cui ognuno sta attualmente lavorando.

$ git fetchremote: Counting objects: 3032, done.remote: Compressing objects: 100% (947/947), done.remote: Total 2672 (delta 1993), reused 2328 (delta 1689)Receiving objects: 100% (2672/2672), 16.45 MiB | 1.04 MiB/s, done.Resolving deltas: 100% (1993/1993), completed with 213 local objects.From github.com:github/github * charlock-linguist -> origin/charlock-linguist * enterprise-non-config -> origin/enterprise-non-config * fi-signup -> origin/fi-signup 2647a42..4d6d2c2 git-http-server -> origin/git-http-server * knyle-style-commits -> origin/knyle-style-commits 157d2b0..d33e00d master -> origin/master * menu-behavior-act-i -> origin/menu-behavior-act-i ea1c5e2..dfd315a no-inline-js-config -> origin/no-inline-js-config * svg-tests -> origin/svg-tests 87bb870..9da23f3 view-modes -> origin/view-modes * wild-renaming -> origin/wild-renaming

Consente anche a tutti di vedere, guardando la pagina GitHub Branch List, su cosa stanno lavorando gli altri in modo da poterli controllare e vedere se vogliono aiutare con qualcosa.

#4 – aprire una richiesta di pull in qualsiasi momento

GitHub ha un incredibile sistema di revisione del codice chiamato Pull Requests che temo non sia conosciuto da abbastanza persone. Molte persone lo usano per il lavoro open source – fare un fork di un progetto, aggiornare il progetto, inviare una richiesta di pull al manutentore. Tuttavia, può anche essere facilmente usato come un sistema interno di revisione del codice, che è quello che facciamo noi.

In realtà, lo usiamo più come una vista di conversazione di ramo più che una richiesta di pull. Puoi inviare richieste di pull da un ramo ad un altro in un singolo progetto (pubblico o privato) in GitHub, così puoi usarle per dire “Ho bisogno di aiuto o di una revisione su questo” oltre a “Per favore unisci questo in”.

primo messaggio pr

Qui puoi vedere Josh che manda in cc Brian per una revisione e Brian che arriva con alcuni consigli su una delle linee di codice. Più in basso possiamo vedere Josh che riconosce le preoccupazioni di Brian e spinge più codice per risolverle.

più discussione

Infine potete vedere che siamo ancora nella fase di prova – questo non è ancora un ramo pronto per il deployment, usiamo le Pull Requests per rivedere il codice molto prima che vogliamo effettivamente fonderlo in master per il deployment.

Se sei bloccato nel progresso della tua caratteristica o ramo e hai bisogno di aiuto o consigli, o se sei uno sviluppatore e hai bisogno di un designer per rivedere il tuo lavoro (o viceversa), o anche se hai poco o nessun codice ma alcuni screenshot comps o idee generali, apri una richiesta di pull. È possibile contattare le persone nel sistema GitHub aggiungendo un @username, quindi se vuoi la revisione o il feedback di persone specifiche, devi semplicemente contattarle nel messaggio PR (come hai visto fare a Josh sopra).

Questo è bello perché la funzione Pull Request ti permette di commentare le singole linee nel diff unificato, su singoli commit o sulla richiesta pull stessa e tira tutto in linea in una singola vista di conversazione.Ti permette anche di continuare a spingere al ramo, quindi se qualcuno commenta che hai dimenticato di fare qualcosa o c’è un bug nel codice, puoi correggerlo e spingere al ramo, GitHub mostrerà i nuovi commit nella vista di conversazione e puoi continuare a iterare su un ramo come quello.

Se il ramo è stato aperto per troppo tempo e senti che sta diventando fuori sincrono con il ramo master, puoi unire master nel tuo ramo dell’argomento e continuare. Puoi facilmente vedere nella discussione della richiesta di pull o nella lista dei commit quando il ramo è stato aggiornato l’ultima volta con il ‘master’.

master merge

Quando tutto è veramente e veramente fatto sul ramo e senti che è pronto per il deploy, puoi passare al passo successivo.

#5 – unire solo dopo la revisione della richiesta di pull

Non facciamo semplicemente del lavoro direttamente su master o lavoriamo su un ramo tematico e lo uniamo quando pensiamo che sia fatto – cerchiamo di ottenere il consenso da qualcun altro nella compagnia. Questo è generalmente un +1 o un emoji o un commento “:shipit:“, ma cerchiamo di far dare un’occhiata a qualcun altro.

commento di shipit

Una volta che lo otteniamo, e il ramo passa il CI, possiamo fonderlo in master per la distribuzione, che chiuderà automaticamente la Pull Request quando la spingiamo.

#6 – distribuire immediatamente dopo la revisione

Finalmente, il tuo lavoro è fatto e fuso nel ramo master. Questo significa che anche se non lo distribuisci ora, la gente baserà il nuovo lavoro su di esso e il prossimo deploy, che probabilmente avverrà in poche ore, lo spingerà fuori. Quindi, dato che non vuoi davvero che qualcun altro spinga qualcosa che hai scritto e che rompe le cose, le persone tendono ad assicurarsi che sia davvero stabile quando viene unito e le persone tendono anche a spingere i propri cambiamenti.

Il nostro bot campfire, hubot, può fare il deploy per qualsiasi dipendente, quindi un semplice:

hubot depoy github to production

distribuirà il codice e zero-downtime riavvierà tutti i processi necessari. Potete vedere quanto questo sia comune su GitHub:

i nostri log del falò

Si possono vedere 6 persone diverse (inclusi un ragazzo del supporto e un designer) che fanno il deploy di circa 24 volte in un giorno.

L’ho fatto per rami con un commit contenente un cambiamento di una riga. Il processo è semplice, diretto, scalabile e potente. Potete farlo con rami di funzionalità con 50 commit su di essi che hanno richiesto 2 settimane, o 1 commit che ha richiesto 10 minuti. È un processo così semplice e senza attrito che non ci si infastidisce di doverlo fare anche per 1 commit, il che significa che le persone raramente cercano di saltare o bypassare il processo a meno che il cambiamento sia così piccolo o insignificante che semplicemente non importa.

Questo è un processo incredibilmente semplice e potente. Penso che la maggior parte delle persone sarebbero d’accordo sul fatto che GitHub ha una piattaforma molto stabile, che i problemi sono affrontati rapidamente, se mai si presentano, e che le nuove caratteristiche sono introdotte ad un ritmo rapido. Non c’è alcun compromesso sulla qualità o la stabilità in modo da poter ottenere più velocità o semplicità o meno processo.

Conclusione

Git stesso è abbastanza complesso da capire, rendere il flusso di lavoro che si usa con esso più complesso del necessario è semplicemente aggiungere più spese mentali alla giornata di tutti. Consiglierei sempre di usare il sistema più semplice possibile che funzioni per il tuo team e di farlo fino a quando non funziona più e poi aggiungere complessità solo se assolutamente necessario.

Per i team che devono fare rilasci formali a lungo termine (da qualche settimana a qualche mese tra un rilascio e l’altro), ed essere in grado di fare hot-fixes e rami di manutenzione e altre cose che nascono dalle spedizioni così poco frequenti, git-flow ha senso e ne raccomando caldamente l’uso.

Per i team che hanno impostato una cultura di spedizione, che spingono alla produzione ogni giorno, che testano e distribuiscono costantemente, consiglierei di scegliere qualcosa di più semplice come GitHub Flow.

Leave a Reply