Antes ya revisamos la instalación de Git, conceptos y comandos básicos de Git, que junto con el tema de este post, prácticamente cubren la mayoría de los comandos que usarás en el día a día. Vamos a ver cómo funcionan las ramas en git.
Contenido de ramas en Git
¿Qué son las ramas en Git?
Una rama es una línea de desarrollo, tomada desde un punto específico del desarrollo, sin afectar al proyecto global.
Git, en cada confirmación (o commit
), almacena la copia de los archivos tal y como están en ese momento y una serie de apuntadores a los commits anteriores. Un solo apuntador para un commit normal y múltiples para cuando se hace una fusión (merge) de ramas. Entonces, cada vez que se hace un nuevo commit, se generan un objeto con los archivos modificados, hashes y cualquier metadato añadido y avanzamos otro paso en nuestra lista de confirmaciones.
La primera rama es main
por convención (antes master
). Y aunque es la primera no tiene por qué ser la principal ni nada parecido, simplemente es como la semilla del árbol donde le saldrán ramas. Para efectos prácticos, dejaremos a main
como nuestra rama principal.
En nuestro proyecto (iniciado en el post anterior) vemos dos commits, el más nuevo aparece en primer lugar.
Crear una rama
Para crear una rama hay dos maneras de hacerlo, una que consta de un solo paso y otra con dos pasos:
# Un paso
git checkout -b mi-rama
# Dos pasos
git branch mi-rama
git checkout mi-rama
Para fines educativos, iremos por la de dos pasos para explicar lo que va pasando.
git branch feature-add
Si hacemos git log --oneline --decorate
veremos en la primera línea que el último commit tiene asignadas las dos ramas: main
y feature-add
. Entonces ¿cómo sé en cuál de las ramas estoy modificando en este momento?
En el comando que ejecutamos anteriormente para crear la rama feature-add
solo la creamos, no le hemos dicho a Git que queremos cambiarnos a ella. Ok, pero esto lo sé porque acabo de hacerlo. Si lo olvido ¿cómo sé en dónde estoy? Bueno, hay dos maneras, veamos.
La primera es simplemente ejecutar git branch
. Esto regresará el nombre de la rama en la que estás señalado con un asterisco (*
).
La segunda manera nos introduce un nuevo e importante concepto: HEAD
. Este se refiere a la rama que está apuntando actualmente. OJO: no se refiere al commit más nuevo, sino en el que te encuentras trabajando. Si vemos en la imagen anterior, vemos el texto HEAD -> main, feature-add
. Esto quiere decir que aunque creamos la rama feature-add
el HEAD
todavía está apuntando al main
.
Cambiar de rama
En nuestro ejemplo, yo quiero ir a la rama feature-add
porque necesito agregar una función nueva a mi programa. Para pasar de la rama main
a la nueva hacemos lo siguiente:
git checkout feature-add
git log --oneline --decorate
Ahora vemos que el HEAD
apunta a feature-add
. En esta rama es donde las modificaciones van a tener efecto, dejando a main
sin tocarse.
Modificamos nuestro archivo main.go
para agregar la función (voy a omitir el código en este post para no mezclar) y luego hacemos el commit para meterlo a nuestro repositorio.
git commit -a -m "funcion de suma agregada"
Ahora vemos que la rama feature-add
ha avanzado, con el HEAD
apuntando a él, mientras que main
se ha quedado un “pasito atrás”. Esto es solo una forma de hablar, nada está más o menos adelante, simplemente, la nueva rama tiene más historial que la rama principal.
Ahora cambiamos de rama nuevamente: git checkout main
y mostramos el log.
Vemos que solo hay dos registros, los mismos que ya teníamos antes de hacer el commit en la rama feature-add
.
Pero no solo es algo visual, si revisamos nuestros archivos, veremos que han regresado al estado antes de agregar nuestra “función de suma”, con el contenido diferente a la rama feature-add
.
Ahora, en la rama main
vamos a hacer un cambio y mandamos los cambios al repository (commit). Vemos el log, pero ahora ejecutamos lo siguiente:
git log --oneline --decorate --graph --all
Esto nos muestra cómo se han separado las ramas y cada una seguirá avanzado en su línea hasta que decidamos que se tienen que unir en algún punto.
Antes de empezar con la fusión de ramas, vamos a avanzar un par de commits en feature-add
y uno en main
.
Aquí vemos que el commit de main
se encuentra en primer lugar, porque es más nuevo que los de la rama feature-add
. Luego hacemos otro commit en feature-add
.
Como vemos, ahora el commit de feature-add
se encuentra primero porque es el más nuevo.
En las dos imágenes, las dos ramas parten del commit 7250dac
, donde fue que creamos la bifurcación.
Fusionar ramas
Ahora que nuestro feature-add
está listo, vamos unir esta rama con main
. Esto se hace con el comando git merge
.
Primero nos cambiamos a la rama donde se unirán los cambios, en este caso será main
y luego hacemos el merge
con la rama que tiene las nuevas funciones:
git checkout master
git merge feature-add
Conflictos
Git tratará de hacer el merge automáticamente, pero si encuentra que las líneas que debe combinar su cruzan, surgen los conflictos. Que aprovecharemos para conocer.
Acá vemos algunas líneas raras. Al abrir el archivo, vemos los cambios de nuestro HEAD
después de la línea <<<<<<< HEAD
. Luego está la siguiente línea =======
, que divide los cambios de los de la otra rama, seguido de >>>>>>> feature-add
.
En este punto debemos decidir los cambios que queremos. Simplemente debemos eliminar esos marcadores y hacer un nuevo commit.
# Generamos el nuevo commit
git commit -a -m "fusion de ramas main y feature-add"
# Vemos el log
git log --oneline --decorate --graph --all
Acá ya vemos cómo la rama feature-add
se une con main.
Borrar una rama
En la imagen anterior notamos cómo las ramas se unen en el último commit, pero feature-add
sigue en el historial, por así decirlo. Como ya no la necesitaremos, entonces la vamos a borrar. Esto se hace así:
git branch -d feature-add
# Salida del comando
Deleted branch feature-add (was cf0ac1a).
El commit cf0ac1a
fue borrado. Ahora revisamos el log.
Ahora ya no vemos a feature-add
pero el árbol de cambios mantiene el historial de la rama.
Por ahora aquí lo vamos dejar cómo funcionan las ramas en Git, pero espero poder hacer otro usando rebase
. Que es un comando que sirve para fusionar dos ramas, pero mantiene nuestro árbol de commits más limpio.
Si quieres explorar más sobre el cómo funcionan las ramas en Git puedes visitar estos enlaces:
https://ohmygit.org/
https://learngitbranching.js.org/
Descarga este proyecto acá: https://github.com/manuelhdez/git-ramas-ejemplo
Gracias por leer.