Salta el contingut
 

Estratègies de ramificació

Joan Puigcerver Ibáñez

j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Estratègies de ramificació

Quan es treballa en un projecte, sobretot quan moltes persones estan involucrades, és imprescindible adoptar una metodologia de treball que facilite la gestió i el desenvolupament del projecte.

Si a més, s'utilitza Git com a sistema de control de versions, necessitem una estratègia de ramificació; un conjunt de regles i pautes que defineixen el flux de treball mitjançant branques, amb els següents objectius:

  • Proporciona un flux de treball clar i coherent per gestionar els canvis de codi.
  • Permet el desenvolupament paral·lel.
  • Facilita la col·laboració entre els membres de l'equip.
  • Ajuda a mantindre un codi estable i preparat per posat en producció.
  • Manté un ordre coherent en la història del projecte.

A més, les estratègies poden ser utilitzades en combinació amb altres ferramentes com les Pull Requests, que veurem en el Bloc 6: Gestió de projectes.

No obstant això, fer ús d'una estratègia de ramificació pot suposar una sobrecàrrega en projectes xicotets o amb pocs membres. És important adaptar la metodologia a les necessitats del projecte i no seguir-la de forma estricta si no aporta valor afegit.

Nota

No és necessari utilitzar tots els tipus de branques.

Per exemple, en projectes xicotets, potser no és necessària una branca de desenvolupament develop o branques de llançament release/*.

Branques amb un propòsit únic

Les estratègies de ramificació més comuns es basen en la creació de diferents tipologies branques, cadascuna amb un propòsit concret i una sèrie de regles per crear-les, incorporar-les i destruir-les.

  • Branca principal (main): Branca on es troba la versió estable del projecte.

  • Branca de desenvolupament (develop): Branca on es troba l'estat actual del projecte, on s'incorporen les funcionalitats provades i acabades.

    • En un primer moment, es crea a partir de la branca main.
    • S'utilitza per integrar les branques de funcionalitat feature/*, que anirà avançant respecte a la branca main.
    • Es fusiona amb la branca main quan es prepara una nova versió del projecte.
  • Branques de funcionalitat (feature/*): Per cada nova funcionalitat es crea una branca independent, on es codifica i es prova la nova funcionalitat.

    • Es creen a partir de la branca develop.
    • Es fusionen amb la branca develop una vegada acabades.
    • Poden ser eliminades després de ser integrades.
  • Branques de llançament (release/*): Branca on es preparen els canvis per poder publicar una nova versió del projecte.

    • Es creen a partir de la branca develop.
    • Es fusionen amb les branques develop i main una vegada acabades.
    • Es poden eliminar una vegada fusionades.
    • Normalment, es crea una etiqueta amb la versió publicada.
  • Branques de correcció (hotfix/*): Branca per corregir errors crítics en la versió publicada del projecte.

    • Es creen a partir de la branca main.
    • Es fusionen amb les branques develop i main una vegada acabades.

Branca principal i de desenvolupament

La branca principal és la branca on es troba la versió publicada i estable del projecte, normalment anomenada main.

La branca de desenvolupament és la branca on es troba l'estat actual del projecte, on s'incorporen les noves funcionalitats que ja estan implementades i provades, però encara no s'han publicat. Aquesta branca és normalment rep el nom de dev, develop o development.

Branca principal i de desenvolupament

Figura 1. Branca principal i de desenvolupament

Branques de funcionalitat

Les branques de funcionalitat són les branques on cada desenvolupador realitza les seues contribucions, de manera paral·lela i independent de la resta.

Normalment, s'utilitza un prefix comú identificar aquestes branques. El prefix més comú és feature/, seguit del nom de la funcionalitat.

No obstant això, el prefix utilitzat pot variar, fins i tot per indicar el tipus de funcionalitat o la naturalesa dels canvis: feat/, feature/, fix/, bugfix/, enhancement/, ...

Branques de funcionalitat

Figura 2. Branques de funcionalitat

El flux de treball amb aquestes branques és el següent:

  • Són creades a partir de la branca develop.

    En la figura anterior, poden veure que totes les branques feature/ han segut creades a partir de la branca develop, però no necessàriament en el mateix punt.

  • S'integren a la branca develop una vegada s'han implementat i provat els canvis.

  • Poden ser eliminades després de ser integrades.

Recomanació

  • Utilitzeu noms descriptius i coherents, que indiquen clarament el propòsit i contingut de les branques, evitant noms genèrics o massa concrets.

  • Incorporeu els canvis de develop de forma regular.

    És preferible mantindre les branques de funcionalitat actualitzades amb els canvis del projecte, i d'aquesta manera, evitar resolucions de conflictes immenses en el moment d'integrar-les.

Integració

El procés per integrar les funcionalitats a la branca de desenvolupament develop és el següent:

  1. Sincronitzar l'estat del repositori local amb el remot.

    git fetch
    
  2. Actualitzar la branca local develop amb els canvis del remot git pull.

    git checkout develop
    git pull --ff-only #(1)!
    
    1. Per evitar possibles conflictes i errors, es recomana configurar git pull perquè sols puga incorporar els canvis de manera directa (fast-forward).

      git config [--global] pull.ff only
      
  3. Actualitzar la branca feature/* amb els nous canvis de develop.

    Varia d'acord amb la tècnica triada per a la integració.

    Vegeu les seccions dedicades a cada tècnica per a més informació.

    git checkout feature/nom-funcionalitat
    git merge --no-ff develop
    

    No és necessari, però es recomana per mantindre la branca de funcionalitat actualitzada.

    git checkout feature/nom-funcionalitat
    git merge --no-ff develop
    
    git checkout feature/nom-funcionalitat
    git rebase develop
    
    git checkout feature/nom-funcionalitat
    git rebase develop
    
  4. Incorporar els canvis de la branca feature/* amb la branca develop amb la tècnica triada.

    git checkout develop
    git merge --squash --ff-only feature/nom-funcionalitat
    git commit
    
    git checkout develop
    git merge --no-ff feature/nom-funcionalitat
    
    git checkout develop
    git merge --ff-only feature/nom-funcionalitat
    
    git checkout develop
    git merge --no-ff feature/nom-funcionalitat
    
  5. Publicar els canvis de la branca develop al repositori remot amb git push.

    Danger

    En aquest punt podria donar-se el cas que, mentres has realitzat aquest procés, altres desenvolupadors han publicat nous canvis a la branca develop i per tant, la teua branca develop no està actualitzada i no pot ser publicada.

    En aquest cas, caldrà tornar la branca develop a l'estat del repositori remot i tornar a fer el procés d'integració.

    git checkout develop
    git reset --hard origin/develop
    
  6. Eliminar la branca feature/* del repositori local i del remot.

    git branch -D feature/nom-funcionalitat
    git push -d origin feature/nom-funcionalitat
    

merge --no-ff

Gitflow és una de les estratègies de ramificació més conegudes i utilitzades en projectes de desenvolupament de programari.

Aquesta metodologia es basa en la creació de les branques main, develop, feature/*, release/* i hotfix/*.

Esquema de branques amb Gitflow

Figura 3. Esquema de branques amb Gitflow

La particularitat d'aquesta estratègia és que la fusió de les branques de funcionalitat feature/* amb la branca de desenvolupament develop és realitza mitjançant merge --no-ff, de manera que es conserva la història de les branques de funcionalitat que es fusionen mitjançant un commit de fusió.

git checkout develop
git merge --no-ff feature/A

Fusió de branques mitjançant merge --no-ff

Figura 4. Fusió de branques mitjançant merge --no-ff

Les característiques d'aquesta opció són:

  • Manté tot l'històric de canvis1.
  • No manté una història lineal.
  • Permet revertir una funcionalitat fàcilment, ja que sols cal revertir un únic commit.
  • En projectes amb moltes funcionalitats, la història pot ser difícil de seguir.

rebase + merge --ff-only

Aquest mètode per fusionar les branques de funcionalitat es basa en la utilització del canvi de base rebase, per després fusionar-la de manera lineal amb merge --ff-only.

git checkout feature/A
git rebase develop
git checkout develop
git merge --ff-only feature/A

Fusió de branques mitjançant rebase

Figura 5. Fusió de branques mitjançant rebase + merge --ff-only

Les característiques d'aquesta opció són:

  • Manté tot l'històric de canvis1.
  • Manté la història lineal.
  • Realitzar el canvi de base de funcionalitats amb molts commits pot ser complicat quan hi ha conflictes.
  • Revertir una funcionalitat no és trivial, ja que cal revertir múltiples commits.

rebase + merge --no-ff

Aquesta opció combina les dues opcions anteriors per tal d'aprofitar els avantatges de cadascuna i a la vegada minimitzar els seus desavantatges.

Aquest mètode es basa en realitzar un canvi de base rebase i després fusionar la branca de funcionalitat mitjançant un commit de fusió amb merge --no-ff.

git checkout feature/A
git rebase develop
git checkout develop
git merge --no-ff feature/A

Fusió de branques mitjançant rebase + merge --no-ff

Figura 6. Fusió de branques mitjançant rebase + merge --no-ff

Les característiques d'aquesta opció són:

  • Manté tot l'històric de canvis1.
  • Manté la història neta i semi-lineal, on les funcionalitats s'integren una després de l'altra.
  • Permet revertir una funcionalitat fàcilment, ja que sols cal revertir un únic commit.
  • Realitzar el canvi de base de funcionalitats amb molts commits pot ser complicat.

merge --squash --ff-only

Opció recomanada

Aquesta opció consisteix a fusionar les branques de funcionalitat amb la branca de desenvolupament develop mitjançant merge --squash --ff-only, de manera que tots els commits de la branca de funcionalitat es fusionen en un únic commit.

git checkout develop
git merge --squash --ff-only feature/A
git commit -m <missatge>

Fusió de branques mitjançant merge --squash --ff-only

Figura 7. Fusió de branques mitjançant merge --squash --ff-only

En el cas que la branca de funcionalitat no estiga actualitzada respecte de la branca de desenvolupament. es considera una bona pràctica és integrar els canvis de develop a la branca de funcionalitat per actualitzar-la. A més, en aquest procés, es poden resoldre els conflictes en cas que n'hi haja.

Per realitzar aquesta integració de canvis, es recomana utilitzar git merge --no-ff.

git checkout feature/A
git merge --no-ff develop
git checkout develop
git merge --squash --ff-only feature/A
git commit -m <missatge>

Fusió de branques mitjançant merge --no-ff + merge --squash --ff-only

Figura 8. Fusió de branques mitjançant merge --no-ff + merge --squash --ff-only

Com que la branca de funcionalitat serà eliminada després de la fusió, no importa si la història de la branca de funcionalitat es manté neta o no.

Advertència

També es podria realitzar la fusió amb rebase, però en cas de conflicte, s'hauria de resoldre en cada commit de la branca de funcionalitat.

Les característiques d'aquesta opció són:

  • No manté tot l'històric de canvis1.
  • Manté la història lineal.
  • Permet revertir una funcionalitat fàcilment, ja que sols cal revertir un únic commit.
  • Facilita la revisió de codi, ja que tots els canvis es troben en un únic commit.
  • Evita la sobrecàrrega de commits en la branca de desenvolupament develop.
  • Els desenvolupador poden despreocupar-se de com queda la història de la branca de funcionalitat, on es poden permetre escriure micro-commits, ja que aquests desapareixeran quan la branca s'esborre després d'integrar-la1.

Branques de llançament

Les branques de llançament són branques temporals que s'utilitzen per a preparar el llançament d'una versió.

Normalment, el prefix de les branques de llançament és release/.

Aquestes branques es creen a partir de la branca de desenvolupament develop i s'utilitzen per a realitzar tasques com:

  • Actualitzar la versió del projecte.
  • Preparar paràmetres de configuració específics per a el llançament.

Consell

Si el teu projecte no requereix de tasques específiques per a preparar el llançament, pots prescindir d'aquestes branques i fusionar directament la branca de desenvolupament develop amb la branca principal main.

El flux de treball amb aquestes branques és el següent:

  • Es creen a partir de la branca de desenvolupament develop.
  • Es realitzen les tasques de preparació per a el llançament.
  • S'integren els canvis a la branca de desenvolupament develop.
  • S'integren els canvis a la branca de desenvolupament main.

Branques de llançament

Figura 9. Branques de llançament

Consell

Si el procés de publicació es realitza amb múltiples commits, pots fer ús de merge --squash per a integrar els canvis en un únic commit a la branca de desenvolupament develop.

Branques de correcció

Les branques de correcció són branques temporals que s'utilitzen per a corregir errors crítics en el codi estable del projecte, quan la seua correcció no pot esperar a la següent versió.

Perill

Aquestes branques sols han de ser utilitzades per corregir errors crítics que afecten la versió publicada del projecte i han de corregir-se immediatament.

Aquestes branques poden dificultar el flux de treball, sobretot si es tracta de mantindre una història lineal del projecte.

Normalment, el prefix de les branques de correcció és hotfix/.

El flux de treball amb aquestes branques és el següent:

  • Es creen a partir de la branca principal main.
  • Es realitzen les correccions necessàries.
  • S'integren els canvis a la branca de desenvolupament develop.
  • S'integren els canvis a la branca de desenvolupament main.

Branques de correcció

Figura 10. Branques de correcció

Bibliografia


  1. Segons el punt de vista, mantindre l'històric de tots els commits pot ser un avantatge o un inconvenient. 

📌 Aquest document pot quedar desactualitzat després d’imprimir-lo. Pots consultar la versió més recent a la pàgina web.
🌿 Abans d’imprimir aquest document, considera si és realment necessari. Redueix el consum de paper i ajuda a protegir el nostre entorn.