Quali modelli di ramificazione Git funzionano per te?



1 Answers

Penso, e potrei sbagliarmi, che una delle cose che è più fraintesa del git è la sua natura distribuita. Questo rende molto diverso il dire sovversione nei modi in cui puoi lavorare anche se puoi simulare il comportamento SVN se vuoi. Il problema è praticamente qualunque sia il flusso di lavoro, che è ottimo ma anche fuorviante.

Se ho la mia comprensione dello sviluppo del kernel (mi concentrerò su questo), tutti hanno il loro repository git per lo sviluppo del kernel. Esiste un repository, linux-2.6.git, curato da Torvalds, che funge da repository di release. Le persone clonate da qui se desiderano iniziare a sviluppare una funzione contro il ramo "release".

Altri repository fanno qualche sviluppo. L'idea è di clonare da Linux-2.6, espandersi tutte le volte che vuoi fino a quando non hai una funzione "nuova" funzionante. Quindi, quando questo è pronto, puoi renderlo disponibile a qualcuno considerato affidabile, che estrarrà questo ramo dal tuo repository nel loro e lo unirà nel mainstream. Nel kernel linux questo accade su diversi livelli (fidati luogotenenti) fino a raggiungere linux-2.6.git, a quel punto diventa "il kernel".

Ora qui è dove si confonde. I nomi delle filiali non devono necessariamente essere coerenti tra i repository. Quindi posso git pull origin master:vanilla-code e ottenere un ramo dal master di origin in un ramo nel mio repository chiamato vanilla-code . A condizione di sapere cosa sta succedendo, in realtà non importa: è distribuito nel senso che tutti i repository sono peer tra loro e non solo condivisi su più computer come SVN.

Quindi, con tutto questo in mente:

  1. Penso che spetti a ciascun programmatore come fanno la loro ramificazione. Tutto ciò di cui hai bisogno è un repository centrale per la gestione delle versioni, ecc. Trunk potrebbe essere la head . Le versioni potrebbero essere tag o rami e gli hotfix sono probabilmente rami in sé stessi. In effetti, probabilmente farei i rilasci come branch in modo da poterli aggiornare.
  2. Mi unirei e non rebase. Se ad esempio si prende un repository, si clona, ​​si dirama e si esegue qualche dev, quindi si tira dalla propria origin , nel proprio repository, probabilmente si crea un altro ramo e si uniscono l'ultimo master a yourbranch in modo che qualcun altro possa estrarre le modifiche con piccolo sforzo possibile. Raramente c'è un bisogno di rebase veramente, nella mia esperienza.
  3. Penso che sia un caso di capire come funziona Git e cosa può fare. Ci vuole un po 'di tempo e molta buona comunicazione - ho solo iniziato a capire veramente cosa sta succedendo quando ho iniziato a usare git con altri sviluppatori e anche adesso, alcune cose di cui non sono sicuro.
  4. I conflitti di unione sono utili. Lo so, lo so, vuoi che tutto funzioni, ma il fatto è che il codice è cambiato e hai bisogno di unire i risultati in qualcosa che funzioni. Unisci conflitti sono di fatto solo più programmazione. Non ho mai trovato una spiegazione facile su cosa fare su di loro, quindi eccolo qui: annota i file che hanno unire i conflitti, vai e cambiali in quello che dovrebbero essere, git add . e poi git commit .
  5. Comunque si adatta. Come ho detto, ogni repository git di ciascun utente è il proprio con cui giocare e i nomi delle filiali non devono necessariamente essere gli stessi . Se si dispone di un repository di staging, ad esempio, è possibile applicare uno schema di denominazione, ma non è necessario per ogni sviluppatore, solo nel repository di distribuzione.
  6. Questa è la fase di unione. Ti unisci solo ai rami di rilascio ecc. Quando consideri che il codice è sottoposto a revisione / supera i test di qualità.

Spero che aiuti. Mi rendo conto che VonC ha appena pubblicato una spiegazione molto simile ... Non riesco a digitare abbastanza velocemente!

Modifica alcuni ulteriori pensieri su come usare git in un contesto commerciale, poiché questo sembra rilevante per l'OP dai commenti:

  • Il repository di rilascio, lo chiameremo product.git , è accessibile da un certo numero di programmatori senior / tecnici che si occupano di curare realmente il prodotto stesso. Sono analoghi al ruolo dei manutentori nell'OSS.
  • Questi programmatori probabilmente anche in parte hanno portato allo sviluppo di nuove versioni, quindi potrebbero anche programmare se stessi e mantenere vari repository. Potrebbero gestire repository di staging per funzionalità davvero nuove e potrebbero anche avere i propri repository.
  • Sotto di loro ci sono i programmatori responsabili dello sviluppo di singoli bit. Ad esempio, qualcuno potrebbe essere responsabile per il lavoro dell'interfaccia utente. Gestiscono quindi il repository UI.git.
  • Sotto di loro ci sono i veri programmatori che sviluppano le funzionalità come il loro lavoro quotidiano.

Quindi cosa succede? Bene, ognuno tira all'inizio di ogni giorno dalla fonte "upstream" cioè il repository di rilascio (che conterrà probabilmente anche il materiale più recente dallo sviluppo dei giorni precedenti). Tutti lo fanno, direttamente. Questo andrà su un ramo nel loro repository, probabilmente chiamato "master" o forse se tu sei me chiamato "latest". Il programmatore farà quindi del lavoro. Questo lavoro potrebbe essere qualcosa di cui non sono sicuro, quindi fanno un ramo, fanno il lavoro. Se non funziona, possono eliminare il ramo e tornare indietro. Se lo fa, dovranno unirsi al ramo principale su cui stanno lavorando. Diremo che si tratta di un programmatore UI che lavora su latest-ui quindi git checkout latest-ui seguito da git merge abc-ui-mywhizzynewfeature . Poi dice al suo capo tecnico (il leader dell'UI) hey, ho completato un simile compito, tiro da me. Quindi l'interfaccia utente fa git pull user-repo lastest-ui:lastest-ui-suchafeature-abc . L'UI guida quindi lo guarda su quel ramo e dice, in realtà, che è molto buono, lo unisco in ui-latest . Potrebbe quindi dire a tutti quelli che sono sotto di lui di tirare da lui sui loro ui-latest rami ui-latest o qualunque nome gli abbiano dato, e così la funzione viene esplorata dagli sviluppatori. Se la squadra è felice, il lead dell'UI potrebbe chiedere al lead testing di estrarre da lui e unire le modifiche. Questo si propaga a tutti (a valle del cambiamento) che lo testano e invia segnalazioni di bug ecc. Infine, se la funzione supera il test, ecc. Uno dei principali lead tecnici potrebbe unirlo alla copia di lavoro corrente del programma, a quel punto tutte le modifiche vengono quindi propagate nuovamente. E così via.

Non è un modo di lavorare "tradizionale" ed è progettato per essere "peer driven" piuttosto che "gerarchico" come SVN / CVS. In sostanza, tutti hanno accesso al commit, ma solo localmente. È l'accesso al repository e il repository designato come repository di rilascio che consente di utilizzare la gerarchia.

Question

La nostra azienda sta attualmente utilizzando un modello di diramazione trunk / release / hotfix semplice e desidera ricevere consigli su quali modelli di ramificazione funzionano meglio per la propria azienda o per il processo di sviluppo.

  1. Modelli di workflow / branching

    Di seguito sono elencate le tre principali descrizioni di questo argomento, ma sono parzialmente in contraddizione tra loro o non sono sufficientemente approfondite per risolvere i problemi successivi in ​​cui ci siamo imbattuti (come descritto di seguito). Di conseguenza, il nostro team non ha ancora adottato soluzioni così grandi. Stai facendo qualcosa di meglio?

  2. Unione / ribasso (intricata vs cronologia sequenziale)

    Si dovrebbe pull --rebase o aspettare con la fusione alla linea principale fino a quando l'attività è finita? Personalmente, mi propongo di fondermi, poiché questo conserva un'illustrazione visuale su quale base è stato avviato e terminato un compito, e io preferisco persino merge --no-ff per questo scopo. Ha tuttavia altri inconvenienti. Inoltre, molti non hanno realizzato la proprietà utile di unire - che non è commutative (la fusione di un ramo dell'argomento in master non significa unire il master nel ramo dell'argomento).

  3. Sto cercando un flusso di lavoro naturale

    A volte gli errori si verificano perché le nostre procedure non catturano una situazione specifica con semplici regole. Ad esempio, una correzione necessaria per le versioni precedenti dovrebbe ovviamente basarsi sufficientemente a valle per poter fondere a monte tutte le filiali necessarie (l'uso di questi termini è abbastanza chiaro?). Tuttavia succede che una correzione lo fa nel master prima che lo sviluppatore si accorga che avrebbe dovuto essere posizionato più a valle, e se questo è già stato spinto (anche peggio, unito o qualcosa basato su di esso) allora l'opzione rimanente è cherry-picking, con i suoi pericoli associati. Quali semplici regole come queste usi? Anche in questo è incluso l'imbarazzo di un ramo di un argomento che necessariamente esclude altri rami di argomento (supponendo che siano ramificati da una linea di base comune). Gli sviluppatori non vogliono terminare una funzione per avviarne un'altra sentendosi come se il codice che hanno appena scritto non ci sia più

  4. Come evitare di creare conflitti di fusione (dovuti a cherry-pick)?

    Quello che sembra un modo sicuro per creare un conflitto di unione è quello di scegliere tra i rami, non possono mai essere uniti di nuovo? Applicare lo stesso commit in fase di ripristino (come fare?) In entrambi i rami può risolvere questa situazione? Questa è una delle ragioni per cui non oso spingere per un flusso di lavoro basato in gran parte sull'unione.

  5. Come si decompone in rami d'attualità?

    Ci rendiamo conto che sarebbe fantastico assemblare un'integrazione completa dai rami dell'argomento, ma spesso i nostri sviluppatori non lavorano in modo chiaro (a volte semplice come "curiosare") e se qualche codice è già entrato in un argomento "misc", non può essere tolto di nuovo da lì, secondo la domanda di cui sopra? Come lavori con la definizione / approvazione / laurea / rilasciando le tue filiali tematiche?

  6. Procedure corrette come la revisione del codice e la laurea sarebbero ovviamente adorabili.

    Ma semplicemente non possiamo mantenere le cose abbastanza districate per gestirlo - qualche suggerimento? rami di integrazione, illustrazioni?

Di seguito è riportato un elenco di domande correlate:

Scopri anche cosa scrive Plastic SCM sullo sviluppo di task driven , e se Plastic non è la tua scelta, studia il modello di branching di nvie e i suoi script di supporto .




Personalmente, cerco di mantenere solo il codice pronto per la release nel ramo principale.

Quando lavoro su una nuova funzione o bugfix lo faccio in un ramo. Ho anche un test unitario nel ramo. Se tutto funziona OK, solo allora mi unisco / rebase di nuovo in master.

Cerco di utilizzare anche convenzioni di denominazione dei rami comuni, come ad esempio:

  • bugfix / recursive_loop
  • bugfix / sql_timeout
  • caratteristica / new_layout
  • caratteristica / enhanced_search





Related