BRANCHING PATTERNS

SCV: Source Code Versioning

SCV systems

VCS: Version Control Systems             SCM: Source Code Management

¿Para qué sirven?

  • Rastrear cambios y restaurar versiones anteriores del software
  • Gestionar y coordinar el código fuente en equipos de desarrollo de software
  • Seguimiento de varias líneas de trabajo y ayudar a fusionar líneas
SCV centralizado
SCV distribuido

SCV centralizado o distribuido

¿Git es descentralidado o centralizado?

Git logo

Repos git

¿Git descentralizado?

Repo central con la verdad

  • origin centraliza pull/push

¿Hacer pull de otros repos?

  • Subequipos: Alice & Bob, Alice & David, David & Clair
  • Alice define remotes bob y david, etc.

Git: repositorios remotos

📙 Definiciones
fork Una copia de un repositorio en el que se puede trabajar de forma independiente (te haces propietario)
clone Copia de un repo remoto (origin) en la máquina local, para trabajar independientemente (pero no eres propietario)
origin Nombre para referirse al repositorio remoto del que se clonó un repo local
upstream Nombre para referirse al repositorio original desde el que se forkeó un repo
SCV

Workflow y branching patterns

  • Patrones para ayudar a manejar la división del desarrollo en líneas de trabajo que se dividen y fusionan (split/merge) en ramas (branch)
  • No son estándares definitivos
  • Dependen de la estructura social del equipo y sus prácticas habituales
Workflow patterns

Patrones de workflow habituales

SCV

Conceptos de branching

source branching = crear una copia del código fuente para registrar en ella todos los cambios de forma independiente

  • ¿Qué es un commit?
  • ¿Qué es staging?
  • ¿Qué es una rama?
  • ¿Qué es un head?
  • ¿Qué es un fork?
📙 Definiciones
commit Conjunto de cambios en el código fuente que se registra en el repositorio
branch Una secuencia de commits
head Último commit de una rama
staging Preparar los cambios para el próximo commit

¡Cuidado! Confusión terminológica sobre qué es una rama

  • ¿Cuando se clona un repo, se crea una nueva rama?
  • Distintos DVCS: Mercurial branch \neq Git branch \approx Mercurial bookmark
📙 Definiciones
branching Crear una copia del código fuente para registrar en ella todos los cambios en el código de forma independiente
merge Integrar los cambios de una rama en otra
codeline Secuencia particular de versiones de una base de código (codebase)
clone Clonar un repo es hacer un checkout de una rama en una nueva codeline
mainline Una rama única compartida por todos que sirve como estado actual del producto

En cada commit, pasar pruebas automáticas para asegurar que la rama no tiene defectos

Codeline

  • Cada desarrollador tiene (en cuanto hace cambios locales) al menos una codeline personal en la working copy de su equipo local
  • En un DVCS como git...
    • ...cuando se clona un repo git, se hace un checkout de main y se actualiza algo, se obtiene una codeline nueva, aunque no se hagan commits
    • ...obtenemos ramas adicionales cada vez que clonamos un repositorio; las ramas pueden ser locales o remotas

Merge vs rebase vs cherry-pick

Conflicts

Tutorial recomendado

JJ Merelo: Aprende Git

Patrones habituales de Workflow

1. Git Flow

Más estructurado y utiliza diferentes tipos de ramas para diversas etapas del desarrollo.
No es muy adecuado para hacer CD o CDEP.

  1. La rama develop es la base para nuevas características.
  2. Se crean ramas feature de características y se fusionan de nuevo en develop.
  3. Se crean ramas release para preparar las versiones a entregar.
  4. Una vez probadas, las ramas se fusionan en master y develop.
  5. Las ramas hotfix corrigen problemas en producción y se fusionan en master y develop.
  6. Cuando los cambios en develop son estables, se fusionan en master y se le asigna una tag con el número de release.

Alex Hyett: Comparativa GitHub flow vs GitFlow

Git flow
Github flow

2. GitHub Flow

Enfoque sencillo para CD/CDEP. No para características complejas con muchos desarrolladores en paralelo.
Despliegues deben estar automatizados.

  1. Una rama main o master como rama principal.
  2. Se trabaja en ramas aparte para nuevas características.
  3. Las correcciones rápidas se tratan como características.
  4. Se crean pull requests para discutir y revisar los cambios.
  5. Una vez aprobados, los cambios se fusionan en la rama main.
  6. Todo en la rama main está listo para ser desplegado.

Scott Chacon: GitHub Flow

Git Flow vs GitHub Flow

Git Flow GitHub Flow
Adaptabilidad Puede ser excesivo para proyectos pequeños Más simple y adaptable para proyectos ágiles
Releases Varias versiones en producción Una versión en producción
Colaboración Énfasis en separación de roles Colaboración más sencilla y continua
Despliegue Potencialmente más lento (muchas ramas) Más rápido (CI se hace en main)
Automatización Se beneficia de herramientas específicas Requiere despliegue automático

3. GitLab Flow

Versión simplificada y más orientada a la entrega continua

  1. Se trabaja con ramas feature y fix para nuevas características y correcciones de errores.
  2. Se crean merge requests para revisar y discutir los cambios.
  3. Una vez aprobados, se fusionan en main.
  4. Se crean ramas production y stable para producción.
  5. Define un conjunto de buenas prácticas.

NOTA: Los merge requests se llaman pull requests en git

Ejercicio recomendado

Tutorial de git-flow

Tipos de patrones

Martin Fowler: Patterns for managing source code branching

  • Patrones de integración: cómo combinar el trabajo de varios desarrolladores
  • Patrones de entrega: cómo llevar una codebase a producción
  • Otros patrones de base

Patrones de integración

Patrones de integración

  • Mainline integration: Los desarrolladores integran su trabajo haciendo pull de la mainline, fusionando y haciendo push a la mainline que debe quedar saludable.
  • Feature branching: Una rama propia para todo el trabajo de cada característica e integrarla en la mainline al completar la característica.
  • Continuous integration: Los desarrolladores integran su trabajo en la mainline tan pronto como tienen un commit saludable que compartir (normalmente < 1 día).
  • Pre-integration review: pull/merge requests

Martin Fowler: Patterns for managing source code branching
Integration patterns

Mainline integration

Checkout:

Mainline integration

  • Pull + push
  • Mainline: healthy branch
  • Conflictos semánticos: self-testing code

Mainline integration

Update:

Mainline integration

  • Pull + push
  • Mainline: healthy branch
  • Conflictos semánticos: self-testing code

Mainline integration

Pull:

Mainline integration

  • Pull + push
  • Mainline: healthy branch
  • Conflictos semánticos: self-testing code

Mainline integration

Merge:

Mainline integration

  • Pull + push
  • Mainline: healthy branch
  • Conflictos semánticos: self-testing code

Mainline integration

Integrate:

Mainline integration

  • Pull + push
  • Mainline: healthy branch
  • Conflictos semánticos: self-testing code

¿Cuál debe ser la frecuencia de integración?

Integration frecuency

Frecuencia de integración

Cantidad de trabajo

Integration frecuency conflict

Frecuencia de integración

Riesgo de conflictos

¿Cuándo se detecta un posible conflicto en 1er. commit?

  • baja frecuencia: merge final S1 y V1
  • alta frecuencia: primer merge

Feature branching

Branch:

Feature branching

Feature branching

Pull:

Feature branching

  • Llegan otros commits a la mainline

Feature branching

Integrate:

Feature branching

  • Mainline integration

¿Es compatible el feature branching con la integración continua?

Feature branching y CI

  • Depende de la frecuencia de integración
  • Depende del tiempo que se tarda en completar una característica
  • Continuous integration (CI)
    • Todos los commits de una característica van juntos
    • El código de cada característica siempre está en el producto
    • Feature flags para switch on/off
  • Feature branching
    • No obliga a mantener ramas saludables
    • Puede disuadir de hacer refactoring (que introducen conflictos)

Feature Branching y Open Source

En proyectos open-source:

  • Una o pocas personas como mantenedores y programadores
  • Un grupo más grande de contribuidores (desconocidos para el mantenedor)
  • Calidad de código discutible
  • Incertidumbre total sobre el tiempo que dedicarán los contribuidores y su eficacia

En proyectos comerciales:

  • Un equipo de personas conocidas y comprometidas a tiempo completo
  • Expectativas fiables de la calidad del código y la capacidad de entrega
  • Empleados remunerados y mayor control sobre el tiempo dedicado, estándares de codificación y hábitos del grupo

En proyectos open source, ¿qué se adapta mejor, feature branching o CI?

Patrones de entrega continua

Mainline release

Martin Fowler: Patterns for managing source code branching
The path from mainline to production release

Entrega desde la mainline

  • Release branch: Una rama que solo acepta los commits ya aceptados para una versión estable del producto, lista para su release
  • Maturity branch: Una rama cuyo head marca la versión para producción de la codebase
  • Environment branch: Contiene los commits necesarios para reconfigurar el producto para un entorno nuevo de ejecución
  • Hotfix branch: Cada rama que captura el trabajo necesario para corregir un defecto urgente de producción
  • Release train: Releases a intervalos regulares; desarrolladores eligen la suya
  • Release-ready mainline: Mantener la mainline lo suficientemente saludable como para que el head pueda ir directamente a producción
Mainline release

Release branch

  • Release branch: única
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train
  • Release-ready mainline
Mainline release

Release branch

  • Release branch: múltiples
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train
  • Release-ready mainline
Hotfix branch

Hotfix branch

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train
  • Release-ready mainline
Hotfix branch

Hotfix branch

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch: con release branch
  • Release train
  • Release-ready mainline
Hotfix branch

Hotfix branch

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch: desde mainline
  • Release train
  • Release-ready mainline
Maturity branch

Maturity branch

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train
  • Release-ready mainline
Environment branch

Environment branch

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train
  • Release-ready mainline
Release train

Release train

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train: múltiples
  • Release-ready mainline
Release train

Release train

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train: trenes futuros
  • Release-ready mainline
Release train

Release train

  • Release branch
  • Maturity branch
  • Environment branch
  • Hotfix branch
  • Release train: desde mainline
  • Release-ready mainline
Release train

Release-ready mainline

El código fuente es un activo vital para cualquier equipo de desarrollo de software. Las herramientas de gestión de código fuente sirven para rastrear cambios, lo que facilita la recreación de versiones anteriores del software y ver cómo se desarrolla con el tiempo. También sirven para coordinar a un equipo de programadores que trabajan en un código base común. Al registrar los cambios que cada desarrollador realiza, estos sistemas pueden hacer un seguimiento de múltiples líneas de trabajo al mismo tiempo y ayudar a los desarrolladores a fusionar estas líneas de trabajo.

Se han desarrollado varios patrones para ayudar a manejar la división del desarrollo en líneas de trabajo que se dividen y fusionan en el flujo de trabajo (workflow) de los equipos de desarrollo de software. Estos patrones no son estándares definitivos. El flujo de trabajo del desarrollo de software depende en gran medida del contexto, especialmente de la estructura social del equipo y otras prácticas que el equipo siga.

Git permite cambiar la historia a base de commits. Otros SCV no. Git representa los commits como snapshots, no como diffs. Eso hace que sea más rápido, pero ocupa más espacio. Staging es añadir ficheros al próximo commit.

En Mercurial, cada rama requiere su propio directorio En Git, cada rama es un puntero a un commit, todo dentro de un único directorio En Mercurial, cambiar de rama es cambiar de directorio En Git, cambiar de rama es cambiar el contenido del directorio (haciendo checkout) Mercurial tiene named branches (permanentes) para ramas dentro de un mismo directorio En Git las ramas son temporales y se borran cuando se fusionan

En GitHub Flow: - los desarrolladores trabajan con Feature branching - la Mainline integration usa PR (Pre-integration review) - no hay Continuous integration

M1 es un push de algún otro desarrollador El merge final de violeta es más complicado

Hacer pull "de vez en cuando". ¿Cada cuánto?

Una estrategia de branching para equipos comerciales no tiene por qué ser la misma que en el mundo open-source. CI es casi imposible para los contribuidores ocasionales al open-source, pero es una alternativa realista para el trabajo comercial.

Las nuevas features no se añaden a la release, sino a la mainline Los desarrolladores solo se preocupan de la release para arreglar defectos urgentes (hotfixes) Los hotfixes se aplican a la release y se fusionan en la mainline (¡Recordarlo!) Release: explícita en Git Flow; no necesaria en GitHub Flow

Algunos productos tendrán muchas versiones presentes en producción. El software que se ejecuta en el equipo de los clientes solo se actualizará cuando el cliente lo desee. Muchos clientes son reacios a actualizar por nuevas características. Pero siguen queriendo correcciones de errores, especialmente si implican problemas de seguridad. Se mantienen abiertas varias ramas para cada release y se aplican los hotfixes según sea necesario. Hotfix: explícita en Git Flow; no necesaria en GitHub Flow

Aplicar hotfix primero a producción y luego a la mainline También a la release branch si hay una abierta

Si el equipo usa release branches, los cambios del hotfix se puede hacer en la release branch y se hace una nueva release. Esto convierte la antigua release branch en una hotfix branch.

Si se hace CD, se pueden lanzar hotfixes directamente desde la mainline. Se lanza la hotfix desde el último commit, no desde del último released. La nueva release se etiqueta como 2.2.1, ya que si un equipo trabaja así es probable que M4 y M5 no incluyan nuevas características. Si lo hacen, entonces el hotfix se incluirá en una release 2.3. No permitir commits en la mainline hasta que el hotfix esté completado.

Los de QA quieren conocer la versión última del producto Una vez que el codebase llegue a un cierto nivel de preparación, se copia a una rama específica: v.g. production A veces basta con usar bien el tagging en vez de una maturity branch separada En Git Flow, la rama master es la maturity branch para producción

Cambios en una URL, en la configuración de acceso a la BD, ubicación del sistema de mensajería, etc.

Release train: - variación: trenes futuros - releases regulares desde la mainline

Release train: - variación: trenes futuros - releases regulares desde la mainline

Release train: - variación: trenes futuros - releases regulares desde la mainline

- En GitFlow hay release branches, luego no hay una release-ready mainline; - En GitHub Flow solo hay una versión en producción, que se integra como Release-ready mainline