Tu multiverso con Git
20-08-2025
Git es una herramienta utilizada para la gestión de versiones de ficheros. Nos permite tener un control de versiones local. que opcionalmente podremos llevarlo a un sistema remoto.
Git fue pensado y siempre se ha explicado, haciendo la analogía con un árbol, sin embargo, a día de hoy, con la idea del multiverso muy presente podemos darle un enfoque más refrescante para las personas que se incorporan al mundo del desarrollo.
La sagrada línea temporal y los eventos canónicos
Iniciemos con el concepto de repositorio. Cuando hablamos de multiverso, hablamos de un conjunto de variaciones del mismo universo. El repositorio es el concepto que se encarga de englobar todas estas variantes (ramificaciones) y eventos canónicos (commits) en un mismo lugar y que nos permite trabajar con todas ellas.
Para indicar que queremos convertir un directorio en un repositorio Git, debemos ejecutar el comando:
git init
Esto creará un directorio .git
en el que se almacenará toda la información relativa al control de versiones.
Git funciona como una línea de tiempo en la cual podemos registrar cambios en los ficheros, como si de eventos canónicos se tratara, de nuestros directorios en un punto de tiempo determinado, al cual se le conoce como "commit".
Los sucesos ocurridos en esa línea del tiempo, no se almacenan en su totalidad para cada commit, sino que se añade información de forma incremental en base al commit anterior.
Es decir, sin la información previa, un evento en la línea de tiempo carecería de la información necesaria para poder ser reconstruido.
Para observar el estado de nuestra línea de tiempo podemos utilizar el comando:
git log
Cada vez que queramos indicar que los cambios que creamos deben ser contemplados en el stage
debemos añadirlos con:
git add [nombre de el/los ficheros]
O, como alternativa, podemos indicarle que añada todo lo que se encuentra en el directorio en el que nos encontramos:
git add .
Para visualizar el estado de nuestro stage podemos utilizar el comando:
git status
Una vez tenemos los cambios en nuestro stage, podemos decidir crear dicho "evento canónico" o "commit":
git commit -m "[el mensaje descriptivo que decidamos]"
También podemos unificar el comando de add
y commit
en uno solo de la siguiente forma:
git commit -a -m "[el mensaje descriptivo que decidamos]"
💡 Como habrás podido comprobar, es bastante incómodo tener que añadir a mano todos los ficheros, pero
git add .
añade todo. Existe un fichero llamado.gitignore
ubicado en la raíz del repositorio, en el cual podemos indicar todos los directorios y ficheros que queramos ignorar. Por ejemplo: directorios debuild
, dependencias instaladas, ficheros con variables de entorno o secrets...
💡 Existen convenciones para la creación de estos commits, como puede ser gitmoji, Conventional Commits
Las ramificaciones temporales
Como en cualquier viaje en el tiempo que da pie a un multiverso, pueden ocurrir alteraciones de la línea temporal por las que se creen ramificaciones que sigan su propio camino con respecto a la original.
En Git, además de la línea temporal principal (a menudo llamada main
o master
), podemos crear ramificaciones temporales o paralelas, conocidas como ramas. Las ramas nos permiten experimentar con nuevas funcionalidades, corregir errores o desarrollar nuevas características sin afectar la línea temporal principal.
Git checkout -b
Cuando queremos crear una nueva rama y movernos a ella, utilizamos el siguiente comando:
git checkout -b [nombre-de-la-rama]
Este comando crea una nueva rama y automáticamente nos posiciona en ella. Desde este punto, cualquier commit que hagamos se registrará en esta nueva rama, manteniendo la main
intacta.
Git checkout
Una vez que hemos terminado de trabajar en una rama y queremos regresar a otra (por ejemplo, la rama main
), utilizamos:
git checkout main
Este comando nos mueve a la rama main
, donde podemos continuar trabajando o combinar las ramas que hemos creado. Es importante notar que siempre debemos asegurarnos de que todos nuestros cambios estén guardados antes de cambiar de rama, ya que, de lo contrario, Git nos pedirá que resolvamos los cambios pendientes.
Una parte importante es que estas ramas pueden volver a integrarse en "La Sagrada Línea Temporal" o incluso entre ellas, aunque esto último no suele ser un hábito muy recomendado.
Ahora bien, la única forma que tenemos para poder unir dos líneas temporales es que estas sean congruentes entre sí y no creen conflictos. En caso de que esto suceda, deberemos ser nosotros quienes decidamos cuál debe ser el estado resultante.
Git merge (ramas sobre ramas)
Para integrar los cambios de una rama en otra, utilizamos el comando git merge
. Supongamos que estamos en la rama main
y queremos incorporar los cambios de una rama llamada feature
:
git merge feature
Esto combinará los cambios de la rama feature
en main
. Git intentará automáticamente fusionar los cambios, pero si ambos modificaron las mismas líneas de un archivo, se producirá un conflicto que deberá resolverse manualmente.
Resolución de conflictos
Cuando ocurre un conflicto, Git marca las áreas de conflicto en los archivos afectados. Debes editar estos archivos para resolver el conflicto y luego continuar con el proceso de fusión:
git add [archivos-resueltos]
git commit
Esto completará la fusión, aplicando los cambios combinados.
Compartiendo la línea temporal
Git no solo nos permite gestionar nuestras versiones de manera local, sino que también nos permite compartir esta información y colaborar con otras personas. Para ello, utilizamos repositorios remotos. Un repositorio remoto es una copia de nuestro repositorio alojada en un servidor externo, al que todos los miembros de un equipo pueden acceder. Esto es útil para mantener la consistencia entre diferentes entornos de desarrollo, asegurando que todas las personas colaboradoras estén en la misma "línea temporal".
Puestos a considerar "La Sagrada línea temporal" esta debería ser la rama principal que se encuentra en remoto.
Git Remote
Para trabajar con un repositorio remoto, primero necesitamos decirle a Git cuál es ese repositorio remoto. Esto se hace usando el comando:
git remote add origin [URL del repositorio]
Este comando enlaza nuestro repositorio local con un repositorio remoto que, por convención, suele llamarse origin
. La URL del repositorio es la dirección donde está alojado el proyecto (puede ser en GitHub, GitLab, Bitbucket, etc.).
Git Pull, Push
Una vez que tenemos configurado nuestro repositorio remoto, podemos sincronizar nuestros cambios. Cuando queremos enviar nuestras versiones locales al repositorio remoto, utilizamos el comando git push
:
git push origin main
Esto envía los commits de nuestra rama local main
al repositorio remoto origin
. Pero si queremos obtener los últimos cambios desde el repositorio remoto y aplicarlos a nuestra línea temporal local, utilizamos el comando git pull
:
git pull origin main
Este comando descarga los cambios desde el repositorio remoto y los integra en nuestra rama local.
Finalmente, si en algún momento queremos ver los repositorios remotos configurados o cambiar alguno de ellos, podemos usar:
git remote -v
Este comando muestra las URLs de los repositorios remotos asociados con nuestro repositorio local.
De la misma forma, al tratar de combinar la línea de tiempo remota con la local pueden ocurrir conflictos, que deberán solucionarse tal y como indicábamos anteriormente.
Git Fetch
Antes de adentrarnos en los detalles de sincronización y fusión de cambios, es fundamental entender cómo Git nos permite estar al tanto de los cambios en el repositorio remoto sin necesariamente integrarlos en nuestra línea temporal local de inmediato. Aquí es donde entra en juego el comando git fetch
.
git fetch origin
Descarga los últimos commits, archivos y ramas desde el repositorio remoto origin
, pero no los fusiona con nuestra rama actual. De este modo, podemos revisar las nuevas líneas temporales (los cambios en las ramas remotas) sin comprometer nuestro trabajo actual.
Manteniendo la sagrada línea temporal
Con el tiempo, querrás combinar los cambios de diferentes ramas para integrar todas las nuevas funcionalidades o correcciones en la línea temporal principal en un entorno remoto y colaborativo. Aquí es donde entran en juego las revisiones de código.
Concepto de PR o MR
En proyectos colaborativos, antes de fusionar ramas, es común realizar una revisión de código a través de una Pull Request (PR) o Merge Request (MR). Esto implica que otra persona del equipo revise los cambios propuestos antes de que sean integrados en la línea temporal principal. Este proceso asegura que el código cumple con los estándares del proyecto y reduce la posibilidad de introducir errores.
Mejorar la legibilidad de la sagrada línea temporal
Una parte muy importante de la gestión temporal no es solo poder acceder a cada punto de ella cuando sea necesario, sino también entender qué ha ocurrido. Por ello que en los últimos años se han establecido hábitos que intentan mejorar esta parte, independientemente de la cantidad de commits que se generen durante el desarrollo.
Para mantener una historia de commits limpia y legible, Git ofrece varias herramientas. Dos de las más útiles son squash
y rebase
.
Squash
El comando squash
permite combinar múltiples commits en uno solo. Esto es útil cuando hemos realizado muchos pequeños commits mientras desarrollábamos una funcionalidad, y ahora queremos que todo ese trabajo aparezca como un único commit en la línea temporal.
git rebase -i [commit-antecesor]
Usando el rebase interactivo (-i
), puedes seleccionar los commits que deseas "aplastar" (squash) y combinarlos en un solo commit.
Rebase
El comando rebase
es otra herramienta poderosa que permite reorganizar o reescribir el historial de commits de una rama. En lugar de simplemente fusionar ramas, rebase
re-aplica los cambios de una rama sobre otra, creando una historia lineal y más limpia:
git rebase [rama-destino]
Este comando toma todos los commits de la rama actual y los aplica sobre la rama-destino
, eliminando bifurcaciones en la línea temporal.
Por ejemplo, si has estado trabajando en una rama feature
y quieres traer los últimos cambios de main
sin un merge tradicional, puedes hacer:
git rebase main
Al final de este proceso, los commits de feature
aparecerán como si hubieran sido realizados después de los commits más recientes en main
, lo que hace que la historia sea más lineal y fácil de seguir.
Cuando realicemos estas acciones, podría darse el caso de que no seamos capaces de subirlos a la rama remota, debido a que existe una incongruencia en cuanto a los commits existentes. Es por ello que debemos "forzar" la subida de código.
git push --force
Esto último debemos hacerlo con mucho cuidado y solo cuando nos aseguremos de que en nuestro local tenemos todos los cambios introducidos en la rama remota. Es decir, que ninguna persona haya subido código mientras estábamos trabajando en el entorno local.
Otra forma de hacerlo es utilizando --force-with-lease
que hace lo mismo que --force
pero se asegura que no hay cambios en la rama remota.
git push --force-with-lease
Una buena forma de garantizar esto y solucionar los conflictos que puedan existir previo a mezclar el código es utilizar el siguiente comando:
git pull origin main --rebase
Este comando realiza un rebase de nuestros cambios locales sobre los cambios más recientes del repositorio remoto. Es decir, en lugar de crear un commit de fusión (merge commit), Git aplica nuestros commits locales "por encima" de los commits que han sido añadidos al repositorio remoto. Esto permite mantener una historia de commits lineal, eliminando bifurcaciones y haciendo que la línea temporal sea más fácil de seguir.
El uso de --rebase
es especialmente útil en equipos grandes, donde la historia del proyecto puede volverse rápidamente compleja debido a múltiples ramas y fusiones. Al usar rebase
, facilitamos la navegación por el historial de commits y hacemos que la integración continua sea más sencilla y limpia.