Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:git_control_codigo_fuente_programadores:branching_merging

¡Esta es una revisión vieja del documento!


Branching y Merging

Módulo perteneciente al curso Git: Control de código fuente para programadores

Una rama o branch es una bifurcación dentro del historial de código que nos permite gestionar los cambios de los mismos archivos en dos historias paralelas. Las ramas en Git, al contrario que en otros VCS, son extremadamente ágiles y livianas y no penalizan ni el almacenamiento ni la velocidad. Por eso en Git se recomienda usar tantas ramas como creamos necesarias sin preocuparnos por su impacto.

De este modo, por ejemplo, en un proyecto es posible abrir una rama nueva por cada característica diferente de la aplicación en la que se esté trabajando, sin miedo a interferir en el trabajo de otras personas ni “ensuciar” la rama “maestra” con código a medio terminar.

Gracias a esta característica podríamos tener la rama master (u otra) con el código estable, tal cual está en el servidor para los clientes, e ir desarrollando cosas nuevas en otras ramas. Si de repente se produce un error en producción que tenemos que arreglar, podemos cambiarnos a la rama master y abrir desde ella otra rama exclusivamente para resolver el bug, sabiendo que en ella partimos del código exacto que hay en producción y que no nos interferirán los nuevos desarrollos que tengamos en marcha:

Una vez terminado de arreglar el bug y habiéndolo probado bien, podemos mezclar la rama de nuevo en nuestro master para almacenar el estado final, e incluso deshacernos de la rama que ya no necesitamos:

Al mismo tiempo, la otra rama, en la que se está desarrollando la característica grande, puede haber evolucionado por su cuenta, totalmente ajena a los cambios que se han hecho en otras ramas, como la que hemos utilizado para solucionar el bug, hasta que la mezclemos con el master u otra rama.

En este módulo vamos a presentar las ramas y la funcionalidad básica de éstas que se utiliza en el día a día.

Introducción a las ramas y sus conceptos principales

Hasta ahora hemos aprendido a registrar cambios haciendo commits directamente sobre el master, aunque no entramos a definirlo todavía para no complicarte más. Entonces, ¿qué es el master cuando trabajamos con Git?

  El master es el branch (o rama) por defecto de Git.

Cuando inicias un repositorio en Git, creas un repositorio vacío. Al registrar tu primer cambio ocurren tres cosas:

  Se crea el branch principal de Git llamado por defecto master
  Se actualiza un puntero llamado HEAD que es lo que indica a Git en dónde estamos situados dentro del repositorio
  Se registra ese primer commit sobre la rama master

Por regla general, a master se la considera la rama principal y la raíz de la mayoría de las demás ramas. Lo más habitual es que en master se encuentre el “código definitivo”, que luego va a producción. Es la rama en la que se mezclan todas las demás, tarde o temprano, para dar por finalizada una tarea e incorporarla al producto final, aunque no siempre es así.

Como ya hemos comentado, en un repositorio puedes tener un número ilimitado de ramas, que puedes crear por cada característica en desarrollo, bug, etc…:

Ejemplo de ramificación

Estos branches adicionales son muy útiles para trabajar en tu propio entorno sin que nadie te moleste, evitando, en la medida de lo posible, los famosos conflictos que veremos un poco más adelante en este mismo módulo. Grafo de commits

Git recoge en su histórico los diferentes commits que has realizado. Cada commit se relaciona con los demás mediante un puntero, único, que apunta hacia atrás de modo que se forma un grafo. El histórico de Git no es más que un conjunto de commits relacionados de esta manera y la representación más correcta de un repositorio y sus ramas debería ser más bien así:

Esquema de Git con flechas de commits apuntando hacia atrás a otros commits

Como puedes observar, cada commit apunta siempre hacia el commit anterior que le precede y solamente hacia éste. Analizando estas relaciones es fácil determinar las rutas/ramas que sigue el histórico dentro del repositorio de código.

  Un commit no puede apuntar hacia más de un commit anterior, aunque un commit sí que puede recibir referencias de más de un commit, como se ve en la figura anterior en las ramas. Por ejemplo, el primer commit de master, a la izquierda, recibe referencias desde otros dos commits, el siguiente en master y el primero de la rama llamada "Característica pequeña".

Una rama simplemente es un nombre otorgado a una de estas bifurcaciones para poder trabajar con esa historia paralela en concreto. Moverse entre ramas implica solamente cambiarse al commit apropiado. El concepto de HEAD

En Git se denomina HEAD al commit en el que está tu repositorio posicionado en cada momento.

Por regla general HEAD suele coincidir con el último commit de la rama en la que estés, ya que habitualmente estás trabajando en lo último. Pero si te mueves hacia cualquier otro commit anterior, entonces el HEAD estará más atrás.

  A este estado, cuando HEAD no está en el último commit de la rama, se le denomina "Detached HEAD" o "HEAD desvinculado" en español (aunque raramente lo verás utilizado en este idioma).

Siempre es posible referirse al commit actual usando el nombre HEAD y, de hecho, es posible referirse a otros commits usando su relación con HEAD de forma relativa.

Así, por ejemplo, puedes referirte a un commit que está dos por detrás del actual usando la expresión HEAD~2 (es una “virgulilla”, no un “menos”):

git log HEAD~2

Con él se ven los detalles de todos los commit a partir del “abuelo” del commit actual (2 por detrás).

El símbolo ~ siempre sigue al primer “padre” del commit referenciado (el HEAD en nuestro ejemplo). Pero si existe más de una rama que parte de un commit, podemos movernos por éstas usando el símbolo ^ para indicar el orden de las mismas. Por ejemplo: HEAD^2 obtendría el primer commit de la segunda rama que parte del commit en el que está HEAD en ese momento.

Se pueden combinar ambos para moverse por las ramas. Así, HEAD^2~3 indica que se obtendrá el tercer commit a partir del primer commit de la segunda rama que parte del commit actual, es decir, 4 commits hacia atrás por la segunda rama (el primer ^ se refiere al primer commit hacia atrás por esa rama y luego indicamos otros 3).

Puede parecer lioso, pero no lo es tanto si lo ves en un diagrama. Este nos muestra todas las formas de llegar al commit A desde los distintos commits existentes en el grafo:

Diferentes referencias de un mismo commit

Como ves, estas referencias relativas valen para cualquier commit, no solo para HEAD, y se referencia a partir de su hash (en la figura, por simplicidad hemos usado letras). Trabajando sobre master

El flujo de trabajo que hemos aprendido hasta ahora se denomina comúnmente “trabajar sobre master”, cuando todos los commits se hacen sobre la rama de dicho nombre, que es la rama por defecto. Si trabajas sobre master significa que todos los cambios los vas a registrar directamente sobre la rama master, sin crear ramas diferentes.

Esta forma de trabajar se usa muchas veces con proyectos personales o de poca complejidad, en los que sabes, de antemano, que será raro coincidir con otro desarrollador subiendo cambios. Ventajas

Es un flujo muy fácil de aprender y muy rápido de ejecutar. Básicamente lo que necesitas es crear el repositorio y empezar a trabajar con lo que ya conoces. Desventajas

No es apto, en general, para proyectos grandes, con más de un desarrollador o que necesiten de un sistema de despliegue y versiones más o menos serio. Trabajo con ramas

La forma habitual de trabajar en equipo con Git es haciendo uso de los branches. Si trabajas directamente sobre el master con varias personas, te encontrarás, más temprano que tarde, con un conflicto en algún archivo que te impedirá subirlo a tu repositorio y continuar trabajando.

Las ramas también tienen un beneficio muy interesante a la hora de usarlas y, es que, por naturaleza, a nosotros los desarrolladores no nos gusta que nos toquen nuestras cosas mientras trabajamos (¡y menos otro desarrollador!). Al crear un branch local estamos creando un entorno de desarrollo propio donde sólo nosotros registramos cambios que más adelante llevaremos al master a través de un merge.

  Nota: otra opción puede ser que trabajes con muchos desarrolladores en un mismo equipo y que unos pocos queráis trabajar en un desarrollo aparte. Lo que tendrías que hacer sería tomar ese branch local y subirlo al repositorio remoto para compartirlo transformándolo en un branch remoto al que todo el equipo tuviese acceso.

Las ramas son un recurso muy útil en Git. En próximas lecciones y módulos aprenderemos algunos de los flujos más comunes y adaptativos que hay basados en este sistema.

informatica/programacion/cursos/git_control_codigo_fuente_programadores/branching_merging.1739892380.txt.gz · Última modificación: por tempwin