Debido a que no debemos demorar las tareas de otras personas en un equipo, el enfoque de realizar un commit tras otro de forma lineal resulta poco práctico. Para agregar nuevas funciones o resolver bugs en una aplicación es necesario adaptar nuestro flujo de trabajo. Por esa razón, en esta guía aprenderás a usar ramas en Git para colaborar en un proyecto. Esta herramienta te permitirá llevar a cabo desarrollos y pruebas por separado y luego incorporar el resultado en el producto principal.
Requisitos previos
- Completar las instrucciones que detallamos en Primeros pasos con Git.
Paso 1: Crear una nueva rama
Hasta el momento, estos son los únicos dos commits que tenemos en la rama master según vimos en la guía anterior. La línea entre ambos representa una secuencia lineal en la que d11b583 ocurrió antes que 55373dc.
Al revisar el historial de commits con git log
, ten en cuenta que los hashes serán diferentes en tu caso.
Para crear una nueva rama y comenzar a trabajar en ella, usa git switch -c
seguido del nombre que desees darle. En este caso, utilizaremos tabla-contenidos-inicial. Como lo sugiere el nombre, la nueva característica que nos proponemos agregar es una tabla de contenidos para nuestra lista de archivos.
Una buena práctica a la hora de decidir el nombre para una rama es describir la funcionalidad que incluye o el problema que soluciona.
git switch -c tabla-contenidos-inicial
El listado de ramas (que puedes ver con git branch
) incluye ahora tabla-contenidos-inicial con un asterisco y en color. Otra forma de averiguar cuál es la rama actual es agregar la opción --show-current
al mismo comando.
En este momento, el historial de la nueva rama coincide con el de master. El último commit (indicado por HEAD
) es el mismo en ambas ramas:
A continuación, agrega un nuevo archivo con el contenido que indicamos abajo:
nano indice.txt
INDICE
======
1. archivo1
2. archivo2
A esta altura, git status
(o su forma breve con la opción -s
) muestra que Git no está llevando cuenta de indice.txt todavía:
Para agregarlo al área de staging y hacer un commit, haz lo que aprendiste anteriormente:
git add indice.txt
git commit -m “Agregar tabla de contenidos inicial”
git log
Como observamos en la imagen de arriba, ahora HEAD
apunta únicamente a la rama tabla-contenidos-inicial y particularmente al último commit de esta. En otras palabras, tabla-contenidos-inicial está un commit (be80706) por delante de master (55373dc) y la secuencia de desarrollo toma esta forma:
Recuerda que cada círculo representa una instantánea del repositorio en un momento dado.
Paso 2: Agregar más archivos en la rama actual
Para continuar, crea los siguientes archivos y luego actualiza el índice con los datos correspondientes en commits separados:
echo "Soy el archivo 3" > archivo3.txt
git add archivo3.txt && git commit -m "Commit inicial del archivo 3"
echo "Soy el archivo 4" > archivo4.txt
git add archivo4.txt && git commit -m "Commit inicial del archivo 4"
echo "3. archivo3" >> indice.txt
echo "4. archivo4" >> indice.txt
git commit -am "Actualización de tabla de contenidos"
En el último comando notarás que en vez de agregar el archivo al área de staging mediante git add
empleamos una nueva opción de git commit
. Al combinar -a
con -m
podemos completar ambos pasos simultáneamente siempre y cuando hayamos hecho cambios en archivos existentes.
La versión corta de git log
muestra los últimos commits y la diferencia entre la rama actual y master:
git log --oneline
Supongamos que agregar archivo3.txt fue un error. ¿Hay alguna forma de deshacer el commit 3142163? De hecho, hay dos formas: git reset
y git revert
. El primer comando modifica el historial, por lo que solamente debe usarse cuando los commits en cuestión NO se han enviado a un servidor remoto. De hacerlo, podría perjudicar el trabajo de otras personas que dependan de registros eliminados en el historial. En cambio, la segunda alternativa crea un nuevo commit que deshace los cambios.
En nuestro caso, utilizaremos git revert
para acostumbrarnos y no cometer errores cuando en algún momento enviemos nuestro código a un repositorio remoto.
git revert HEAD~2
o
git revert 3142163
Cuando usamos HEAD~
seguido de un número, revertimos el commit que se encuentre en esa posición contando desde la ubicación actual hacia atrás. En otras palabras, git revert HEAD
deshace el último commit, HEAD~1
el penúltimo, HEAD~2
el antepenúltimo y así sucesivamente.
Como podemos apreciar, el contenido del directorio actual no incluye más al archivo3.txt:
Pero como todavía aparece en el índice, edita ese archivo para eliminar la referencia y toma una nueva instantánea:
nano indice.txt
INDICE
======
1. archivo1
2. archivo2
3. archivo4
git commit -am "Eliminar archivo de la tabla de contenidos"
Más allá de lo curioso que es tener una línea que indique 3. archivo4
, este ejemplo nos ha permitido explicar cómo deshacer los cambios que introdujimos en un commit. En este punto, la secuencia queda de la siguiente forma:
Con todo ese historial de commits, ya es hora de incorporarlos a la rama principal.
Paso 3: Combinar cambios
El proceso de incorporar las instantáneas de una rama en otra distinta se conoce como merge. En este ejemplo, nos proponemos incluir en master todos los cambios que hemos hecho en tabla-contenidos-inicial hasta el momento. Para hacerlo, usa los siguientes comandos:
git switch master
git merge tabla-contenidos-inicial
Es importante aclarar que en este caso el merge fue sencillo debido a que no había cambios en master posteriores a la creación de la rama tabla-contenidos-inicial. De esa forma, Git se limitó a mover el HEAD
de la primera para que coincidiera con el de esta última. Este escenario se denomina fast forward. La imagen de abajo muestra la ubicación del HEAD
de ambas ramas:
git branch -v
La secuencia de cambios queda así:
Si master hubiera tenido cambios posteriores, no hubiéramos podido hacer un fast forward. El merge es todavía posible con los mismos comandos, pero se utiliza una estrategia llamada recursiva que está fuera del alcance de esta guía. Otra complicación posible es que dos ramas distintas incluyan cambios sobre las mismas líneas de un determinado archivo. Esta situación se conoce como merge conflicts y debe solucionarse (indicando qué cambios deseamos mantener) antes de proceder con el merge.
Conclusión
En esta guía aprendiste a crear ramas, agregar cambios o revertirlos, y finalmente incorporarlos a la línea principal de desarrollo. El ejemplo que empleamos, si bien simple, sirve para explicar los conceptos de una manera fácil de comprender. Un caso real tendrá más archivos y cambios no triviales, pero al final de cuentas los fundamentos son los mismos.