Un Git Workflow è una ricetta o una raccomandazione su come usare Git per realizzare il lavoro in modo coerente e produttivo. I workflow di Git incoraggiano gli utenti a sfruttare Git in modo efficace e coerente. Git offre molta flessibilità nel modo in cui gli utenti gestiscono i cambiamenti. Dato il focus di Git sulla flessibilità, non c’è un processo standardizzato su come interagire con Git. Quando si lavora con un team su un progetto gestito con Git, è importante assicurarsi che il team sia tutto d’accordo su come il flusso delle modifiche sarà applicato. Per assicurarsi che il team sia sulla stessa pagina, dovrebbe essere sviluppato o selezionato un flusso di lavoro Git concordato. Ci sono diversi flussi di lavoro Git pubblicizzati che possono essere una buona soluzione per il tuo team. Qui, discuteremo alcune di queste opzioni di flusso di lavoro.
La serie di possibili flussi di lavoro può rendere difficile sapere da dove iniziare quando si implementa Git sul posto di lavoro. Questa pagina fornisce un punto di partenza esaminando i più comuni flussi di lavoro di Git per i team di software.
Nel leggere, ricorda che questi flussi di lavoro sono progettati per essere linee guida piuttosto che regole concrete. Vogliamo mostrarvi cosa è possibile fare, in modo che possiate mescolare e combinare aspetti di diversi flussi di lavoro per soddisfare le vostre esigenze individuali.
Cos’è un flusso di lavoro Git di successo?
Quando valutate un flusso di lavoro per il vostro team, è molto importante che consideriate la cultura del vostro team. Vuoi che il flusso di lavoro migliori l’efficacia del tuo team e non sia un peso che limita la produttività. Alcune cose da considerare quando si valuta un flusso di lavoro Git sono:
- Questo flusso di lavoro è scalabile con le dimensioni del team?
- È facile cancellare gli errori con questo flusso di lavoro?
- Questo flusso di lavoro impone un nuovo inutile sovraccarico cognitivo al team?
Flusso di lavoro centralizzato
Il flusso di lavoro centralizzato è un ottimo flusso di lavoro Git per i team in transizione da SVN. Come Subversion, il flusso di lavoro centralizzato usa un repository centrale per servire come unico punto di ingresso per tutte le modifiche al progetto. Invece di trunk
, il ramo di sviluppo predefinito si chiama master
e tutti i cambiamenti sono impegnati in questo ramo. Questo flusso di lavoro non richiede altri rami oltre a master
.
Il passaggio ad un sistema di controllo di versione distribuito può sembrare un compito arduo, ma non è necessario cambiare il flusso di lavoro esistente per trarre vantaggio da Git. Il tuo team può sviluppare progetti esattamente nello stesso modo in cui fa con Subversion.
Tuttavia, usare Git per alimentare il tuo flusso di lavoro di sviluppo presenta alcuni vantaggi rispetto a SVN. Primo, dà ad ogni sviluppatore la propria copia locale dell’intero progetto. Questo ambiente isolato permette ad ogni sviluppatore di lavorare indipendentemente da tutti gli altri cambiamenti al progetto – possono aggiungere commit al loro repository locale e dimenticarsi completamente degli sviluppi a monte fino a quando non è conveniente per loro.
Secondo, ti dà accesso al robusto modello di branching e merging di Git. A differenza di SVN, i rami di Git sono progettati per essere un meccanismo a prova di errore per integrare il codice e condividere le modifiche tra i repository. Il flusso di lavoro centralizzato è simile ad altri flussi di lavoro nel suo utilizzo di un repository remoto ospitato sul lato server che gli sviluppatori spingono e tirano. Rispetto ad altri flussi di lavoro, il flusso di lavoro centralizzato non ha una richiesta di pull definita o modelli di biforcazione. Un flusso di lavoro centralizzato è generalmente più adatto a team che migrano da SVN a Git e a team di piccole dimensioni.
Come funziona
Gli sviluppatori iniziano clonando il repository centrale. Nelle loro copie locali del progetto, modificano i file e commettono i cambiamenti come farebbero con SVN; tuttavia, questi nuovi commit sono memorizzati localmente – sono completamente isolati dal repository centrale. Questo permette agli sviluppatori di rimandare la sincronizzazione a monte finché non si trovano in un punto di rottura conveniente.
Per pubblicare le modifiche al progetto ufficiale, gli sviluppatori “spingono” il loro ramo locale master
al repository centrale. Questo è l’equivalente di svn commit
, eccetto che aggiunge tutti i commit locali che non sono già nel ramo centrale master
.
Inizializzare il repository centrale
Per prima cosa, qualcuno deve creare il repository centrale su un server. Se è un nuovo progetto, puoi inizializzare un repository vuoto. Altrimenti, è necessario importare un repository Git o SVN esistente.
I repository centrali dovrebbero sempre essere repository nudi (non dovrebbero avere una directory di lavoro), che possono essere creati come segue:
ssh user@host git init --bare /path/to/repo.git
Assicurati di usare un nome utente SSH valido per user
, il dominio o l’indirizzo IP del tuo server per host
, e la posizione in cui vorresti salvare il tuo repo per /path/to/repo.git
. Si noti che l’estensione .git
è convenzionalmente aggiunta al nome del repository per indicare che si tratta di un repository nudo.
Repository centrali ospitati
I repository centrali sono spesso creati attraverso servizi di hosting Git di terze parti come Bitbucket Cloud o Bitbucket Server. Il processo di inizializzazione di un repository nudo discusso sopra è gestito per te dal servizio di hosting. Il servizio di hosting fornirà quindi un indirizzo per il repository centrale a cui accedere dal tuo repository locale.
Clonare il repository centrale
In seguito, ogni sviluppatore crea una copia locale dell’intero progetto. Questo viene realizzato tramite il comando git clone
:
git clone ssh://user@host/path/to/repo.git
Quando si clona un repository, Git aggiunge automaticamente un collegamento chiamato origin
che punta al repository “padre”, assumendo che si voglia interagire con esso più avanti nel tempo.
Apportare modifiche e fare il commit
Una volta che il repository è clonato localmente, uno sviluppatore può apportare modifiche utilizzando il processo standard di commit di Git: modifica, fase e commit. Se non hai familiarità con l’area di staging, è un modo per preparare un commit senza dover includere ogni cambiamento nella directory di lavoro. Questo ti permette di creare commit altamente focalizzati, anche se hai fatto molti cambiamenti locali.
git status # View the state of the repo git add # Stage a file git commit # Commit a file
Ricorda che poiché questi comandi creano commit locali, John può ripetere questo processo quante volte vuole senza preoccuparsi di cosa sta succedendo nel repository centrale. Questo può essere molto utile per grandi funzionalità che hanno bisogno di essere suddivise in pezzi più semplici e atomici.
Spingere i nuovi commit al repository centrale
Una volta che il repository locale ha nuovi cambiamenti impegnati. Questi cambiamenti avranno bisogno di essere spinti per essere condivisi con gli altri sviluppatori del progetto.
git push origin master
Questo comando spingerà i nuovi cambiamenti impegnati al repository centrale. Quando si spingono le modifiche al repository centrale, è possibile che siano stati precedentemente spinti aggiornamenti da un altro sviluppatore che contengono codice in conflitto con gli aggiornamenti da spingere. Git emetterà un messaggio che indica questo conflitto. In questa situazione, git pull
dovrà prima essere eseguito. Questo scenario di conflitto sarà ampliato nella sezione seguente.
Gestire i conflitti
Il repository centrale rappresenta il progetto ufficiale, quindi la sua storia di commit dovrebbe essere trattata come sacra e immutabile. Se i commit locali di uno sviluppatore divergono dal repository centrale, Git rifiuterà di spingere i loro cambiamenti perché questo sovrascriverebbe i commit ufficiali.
Prima che lo sviluppatore possa pubblicare la sua caratteristica, ha bisogno di recuperare i commit centrali aggiornati e ribasare le sue modifiche su di essi. Questo è come dire, “Voglio aggiungere le mie modifiche a ciò che tutti gli altri hanno già fatto”. Il risultato è una storia perfettamente lineare, proprio come nei tradizionali flussi di lavoro SVN.
Se le modifiche locali entrano direttamente in conflitto con i commit a monte, Git mette in pausa il processo di rebase e ti dà la possibilità di risolvere manualmente i conflitti. La cosa bella di Git è che usa gli stessi comandi git status
e git add
sia per generare i commit che per risolvere i conflitti di fusione. Questo rende facile per i nuovi sviluppatori gestire le proprie fusioni. Inoltre, se si trovano nei guai, Git rende molto facile abortire l’intero rebase e riprovare (o andare a cercare aiuto).
Esempio
Facciamo un esempio generale di come un tipico piccolo team potrebbe collaborare usando questo flusso di lavoro. Vedremo come due sviluppatori, John e Mary, possono lavorare su feature separate e condividere i loro contributi attraverso un repository centralizzato.
John lavora sulla sua feature
Nel suo repository locale, John può sviluppare le feature usando il processo standard di commit di Git: edit, stage, e commit.
Ricorda che poiché questi comandi creano dei commit locali, John può ripetere questo processo tutte le volte che vuole senza preoccuparsi di cosa sta succedendo nel repository centrale.
Mary lavora alla sua feature
Nel frattempo, Mary sta lavorando alla sua caratteristica nel suo repository locale usando lo stesso processo di edit/stage/commit. Come John, a lei non importa cosa sta succedendo nel repository centrale, e non le importa davvero cosa John stia facendo nel suo repository locale, poiché tutti i repository locali sono privati.
John pubblica la sua caratteristica
Una volta che John ha finito la sua caratteristica, dovrebbe pubblicare i suoi commit locali sul repository centrale in modo che gli altri membri del team possano accedervi. Può farlo con il comando git push
, così:
git push origin master
Ricorda che origin
è la connessione remota al repository centrale che Git ha creato quando John lo ha clonato. L’argomento master
dice a Git di provare a rendere il origin
del master
ramo come il suo master
locale. Poiché il repository centrale non è stato aggiornato da quando John lo ha clonato, questo non causerà alcun conflitto e il push funzionerà come previsto.
Mary cerca di pubblicare la sua caratteristica
Vediamo cosa succede se Mary prova a fare il push della sua caratteristica dopo che John ha pubblicato con successo le sue modifiche al repository centrale. Può usare lo stesso identico comando push:
git push origin master
Ma, poiché la sua cronologia locale si è allontanata dal repository centrale, Git rifiuterà la richiesta con un messaggio di errore piuttosto verboso:
error: failed to push some refs to '/path/to/repo.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Merge the remote changes (e.g. 'git pull') hint: before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Questo impedisce a Mary di sovrascrivere i commit ufficiali. Ha bisogno di tirare gli aggiornamenti di John nel suo repository, integrarli con le sue modifiche locali, e poi riprovare.
Mary fa il rebase sopra i commit di John
Mary può usare git pull
per incorporare le modifiche a monte nel suo repository. Questo comando è una specie di svn update
– tira l’intera storia dei commit dell’upstream nel repository locale di Mary e cerca di integrarla con i suoi commit locali:
git pull --rebase origin master
L’opzione --rebase
dice a Git di spostare tutti i commit di Mary sulla punta del master
ramo dopo averlo sincronizzato con i cambiamenti dal repository centrale, come mostrato sotto:
Il pull funzionerebbe ancora se si dimenticasse questa opzione, ma si finirebbe con un superfluo “merge commit” ogni volta che qualcuno ha bisogno di sincronizzarsi con il repository centrale. Per questo flusso di lavoro, è sempre meglio fare il rebase invece di generare un merge commit.
Mary risolve un conflitto di merge
Il rebasing funziona trasferendo ogni commit locale al ramo aggiornato master
uno alla volta. Questo significa che si catturano i conflitti di merge su una base di commit per commit piuttosto che risolverli tutti in un unico massiccio commit di merge. Questo mantiene i tuoi commit il più concentrati possibile e rende la storia del progetto pulita. A sua volta, questo rende molto più facile capire dove sono stati introdotti i bug e, se necessario, rollbackare le modifiche con un impatto minimo sul progetto.
Se Mary e John stanno lavorando su caratteristiche non correlate, è improbabile che il processo di rebasing generi conflitti. Ma se succede, Git metterà in pausa il rebase al commit corrente e mostrerà il seguente messaggio, insieme ad alcune istruzioni rilevanti:
CONFLICT (content): Merge conflict in
La cosa bella di Git è che chiunque può risolvere i propri conflitti di fusione. Nel nostro esempio, Mary dovrebbe semplicemente eseguire un git status
per vedere dov’è il problema. I file in conflitto appariranno nella sezione Unmerged paths:
# Unmerged paths: # (use "git reset HEAD ..." to unstage) # (use "git add/rm ..." as appropriate to mark resolution) # # both modified:
Poi, modificherà i file a suo piacimento. Una volta che è soddisfatta del risultato, può mettere in scena i file nel solito modo e lasciare che git rebase
faccia il resto:
git add git rebase --continue
E questo è tutto. Git passerà al prossimo commit e ripeterà il processo per ogni altro commit che genera conflitti.
Se arrivate a questo punto e vi rendete conto che non avete idea di cosa stia succedendo, niente panico. Basta eseguire il seguente comando e sarete di nuovo al punto di partenza:
git rebase --abort
Mary pubblica con successo la sua caratteristica
Dopo aver finito la sincronizzazione con il repository centrale, Mary sarà in grado di pubblicare con successo le sue modifiche:
git push origin master
Dove andare da qui
Come potete vedere, è possibile replicare un tradizionale ambiente di sviluppo Subversion usando solo una manciata di comandi Git. Questo è ottimo per la transizione dei team da SVN, ma non sfrutta la natura distribuita di Git.
Il flusso di lavoro centralizzato è ottimo per piccoli team. Il processo di risoluzione dei conflitti descritto sopra può formare un collo di bottiglia quando il tuo team aumenta di dimensioni. Se il vostro team è a suo agio con il flusso di lavoro centralizzato ma vuole ottimizzare i suoi sforzi di collaborazione, vale sicuramente la pena esplorare i benefici del flusso di lavoro Feature Branch. Dedicando un ramo isolato ad ogni caratteristica, è possibile avviare discussioni approfondite sulle nuove aggiunte prima di integrarle nel progetto ufficiale.
Altri flussi di lavoro comuni
Il flusso di lavoro centralizzato è essenzialmente un blocco di costruzione per altri flussi di lavoro Git. La maggior parte dei flussi di lavoro Git popolari avranno una sorta di repo centralizzato da cui i singoli sviluppatori faranno push e pull. Di seguito discuteremo brevemente alcuni altri popolari flussi di lavoro Git. Questi flussi di lavoro estesi offrono modelli più specializzati per quanto riguarda la gestione dei rami per lo sviluppo di funzionalità, hot fix, ed eventuale rilascio.
Feature branching
Feature Branching è una logica estensione del flusso di lavoro centralizzato. L’idea centrale dietro il Feature Branch Workflow è che tutto lo sviluppo delle feature dovrebbe avvenire in un ramo dedicato invece che nel ramo master
. Questo incapsulamento rende facile per più sviluppatori lavorare su una particolare caratteristica senza disturbare la base di codice principale. Significa anche che il ramo master
non dovrebbe mai contenere codice rotto, che è un enorme vantaggio per gli ambienti di integrazione continua.
Gitflow Workflow
Il Gitflow Workflow è stato pubblicato per la prima volta in un post molto apprezzato del 2010 da Vincent Driessen a nvie. Il Gitflow Workflow definisce un rigido modello di branching progettato intorno al rilascio del progetto. Questo flusso di lavoro non aggiunge nessun nuovo concetto o comando oltre a quello richiesto dal Feature Branch Workflow. Invece, assegna ruoli molto specifici ai diversi rami e definisce come e quando dovrebbero interagire.
Forking Workflow
Il Forking Workflow è fondamentalmente diverso dagli altri flussi di lavoro discussi in questo tutorial. Invece di usare un singolo repository lato server per agire come codebase “centrale”, dà ad ogni sviluppatore un repository lato server. Questo significa che ogni collaboratore non ha uno, ma due repository Git: uno locale privato e uno pubblico lato server.
Linee guida
Non c’è un flusso di lavoro Git uguale per tutti. Come detto in precedenza, è importante sviluppare un flusso di lavoro Git che sia un miglioramento della produttività per il tuo team. Oltre alla cultura del team, un flusso di lavoro dovrebbe anche integrare la cultura aziendale. Le caratteristiche di Git come i rami e i tag dovrebbero integrare il programma di rilascio della tua azienda. Se il tuo team sta usando un software di gestione dei progetti per il tracciamento delle attività, potresti voler usare rami che corrispondono alle attività in corso. Inoltre, alcune linee guida da considerare quando si decide un flusso di lavoro sono:
Rami a vita breve
Più a lungo un ramo vive separato dal ramo di produzione, più alto è il rischio di conflitti di fusione e problemi di distribuzione. I rami a vita breve promuovono fusioni e deployment più puliti.
Minimizzare e semplificare le revoche
È importante avere un flusso di lavoro che aiuti a prevenire proattivamente le fusioni che dovranno essere revocate. Un flusso di lavoro che testa un ramo prima di permetterne la fusione nel ramo master
è un esempio. Tuttavia, gli incidenti accadono. Detto questo, è vantaggioso avere un flusso di lavoro che permetta facili rettifiche che non interrompano il flusso per gli altri membri del team.
Abbinare un programma di rilascio
Un flusso di lavoro dovrebbe integrare il ciclo di rilascio del software della vostra azienda. Se pensate di rilasciare più volte al giorno, vorrete mantenere stabile il vostro master
ramo. Se il tuo programma di rilascio è meno frequente, potresti voler considerare di usare i tag Git per etichettare un ramo ad una versione.
Riassunto
In questo documento abbiamo discusso i flussi di lavoro di Git. Abbiamo dato uno sguardo approfondito ad un flusso di lavoro centralizzato con esempi pratici. Espandendo il flusso di lavoro centralizzato abbiamo discusso ulteriori flussi di lavoro specializzati. Alcuni punti chiave di questo documento sono:
- Non esiste un flusso di lavoro Git uguale per tutti
- Un flusso di lavoro dovrebbe essere semplice e migliorare la produttività del tuo team
- I tuoi requisiti di business dovrebbero aiutare a modellare il tuo flusso di lavoro Git
Per leggere il prossimo flusso di lavoro Git guarda la nostra analisi completa del Feature Branch Workflow.