Skip to content
This page has been auto-translated and may contain errors.View in English

Ramas en Git ​

docs.scrimba.com

Estás a mitad de camino construyendo weather-app, y quieres probar agregar una función de pronóstico de cinco días. Puede que necesites varios commits para lograrlo bien, y hasta que lo consigas, no quieres que código a medio terminar quede junto a la app que ya funciona para todos los que la usan. Una rama es la manera en que Git resuelve esto: una línea de trabajo separada donde vive el experimento, mientras main sigue funcionando exactamente como antes de que empezaras.

Qué es en realidad una rama ​

Aquí la tienes en acción:

bash
$ git branch forecast
$ git switch forecast
Switched to branch 'forecast'

Dos comandos: el primero crea una nueva rama llamada forecast, el segundo te mueve a ella. Desde este punto, cada commit que hagas queda en forecast mientras main se mantiene exactamente donde está.

Una rama es una etiqueta movible que apunta a un commit. En este momento, main y forecast apuntan ambas al mismo commit, el que estabas parado sobre cuando ejecutaste git branch forecast. En el instante en que hagas otro commit estando en forecast, esa etiqueta avanza al nuevo commit. main se mantiene exactamente donde estaba hasta que cambies a ella y hagas un commit ahí tú mismo.

Puedes ver ambas etiquetas con git branch:

bash
$ git branch
  forecast
* main

El asterisco marca la rama en la que estás actualmente. Una rama es solo un nombre que apunta a un commit. Ese es todo el mecanismo. Todo lo demás en este capítulo es una variación de mover esas etiquetas de un lado a otro.

En un proyecto real, los nombres de las ramas transmiten información. Una convención común es un prefijo corto que describe el tipo de cambio, seguido de una descripción: feature/five-day-forecast, fix/broken-date-picker, chore/upgrade-eslint. Algunos equipos agregan un número de ticket (feature/wa-142-forecast). Cualquiera que sea la convención que elijas, mantenla consistente en todo el proyecto para que cualquiera pueda saber para qué sirve una rama sin necesidad de abrirla.

El flujo de trabajo que estos nombres respaldan son las ramas de funcionalidad de corta duración: crea una rama para una pieza de trabajo, haz commits en ella, consigue que revisen el cambio y lo fusionen, y luego elimina la rama. Una rama que vive durante semanas se aleja cada vez más de main, y la fusión eventual se vuelve más difícil mientras más tiempo dure ese distanciamiento. Las ramas más sanas se terminan en días.

Una rama es apenas un poco más que un pequeño archivo que contiene un hash de commit, guardado dentro de la contabilidad interna de Git. Crear una significa escribir esa única línea, por eso git branch termina de forma instantánea incluso en un repositorio con años de historia detrás. Esa misma ligereza es la razón por la que las convenciones de nombres y las ramas de corta duración importan en la práctica: eliminar una rama obsoleta tampoco le cuesta nada a Git, así que nada impide que las ramas abandonadas se vayan acumulando, salvo la disciplina propia del equipo.

JunoQué es en realidad una ramagit branch forecast crea una nueva etiqueta que apunta a tu commit actual, y git switch forecast te mueve a ella. Nada de tus archivos cambia hasta que realmente hagas un commit ahí. Me gusta imaginar las ramas como notas adhesivas sobre un commit: baratas de agregar, baratas de mover, baratas de despegar cuando terminas.
JunoQué es en realidad una rama El nombre de una rama es un puntero, así que crear una no cuesta nada y cambiar entre ellas es instantáneo. Dale a las ramas nombres que describan el trabajo, como feature/five-day-forecast, y mantenlas de corta duración: crea, haz commit, fusiona, elimina. Las ramas de larga duración son las que convierten una fusión de rutina en un verdadero dolor de cabeza.
JunoQué es en realidad una rama Una rama realmente es un pequeño archivo que contiene un hash de commit, por eso crear una es una de las operaciones más baratas en Git. Las convenciones de nombres y las ramas de corta duración son la manera en que un equipo mantiene legible su trabajo en paralelo; Git en sí mismo no impone nada de esto. He limpiado suficientes ramas abandonadas de hace seis meses como para tener opiniones firmes sobre esto.

Crear y cambiar entre ramas ​

git branch forecast por sí solo crea la etiqueta sin moverte a ella. La mayoría de las veces quieres ambas cosas a la vez, así que git switch tiene un atajo:

bash
$ git switch -c forecast
Switched to a new branch 'forecast'

-c significa "create" (crear). git switch -c crea la rama y te mueve a ella al mismo tiempo. Ese único comando es al que recurrirás casi siempre que empieces un trabajo nuevo.

Cambiar de rama cambia qué instantánea muestran tus archivos. Pruébalo: la línea echo de abajo es una forma rápida de crear un nuevo archivo, src/forecast.js, con una sola línea de contenido, y todo lo demás son comandos que ya conoces:

bash
$ git switch forecast
$ echo "// lógica del pronóstico de cinco días" > src/forecast.js
$ git add src/forecast.js
$ git commit -m "Start forecast module"
$ ls src
forecast.js  index.js
$ git switch main
Switched to branch 'main'
$ ls src
index.js

El archivo no ha desaparecido. Vive en la rama forecast, y la instantánea de la rama main nunca lo incluyó. Cambia de vuelta a forecast y reaparece exactamente como lo dejaste.

Verás un verbo más antiguo para esto en código y tutoriales existentes: git checkout forecast hace lo mismo que git switch forecast. checkout es más antiguo y hace más de una cosa: según lo que le pases, puede cambiar de rama o restaurar un archivo a una versión anterior, y solo con el nombre del comando no puedes saber cuál de las dos cosas va a pasar. switch y restore dividen esas dos tareas en comandos separados para que el nombre te lo diga de entrada: switch te mueve entre ramas, restore devuelve un archivo a como se veía en un commit dado. Usa los verbos nuevos; reconoce checkout cuando te lo encuentres por ahí.

checkout decide qué hacer según lo que le pases: un nombre de rama cambia de rama, una ruta de archivo restaura ese archivo, y si un nombre coincide con ambos casos, Git tiene que adivinar cuál quisiste decir. Esa ambigüedad es exactamente la razón por la que el comando se dividió en dos. switch solo cambia de rama y restore solo cambia archivos, así que una ruta mal escrita ya no puede hacerte cambiar de rama por accidente. Espera encontrar checkout en scripts y tutoriales antiguos durante años todavía; escribe switch y restore en cualquier cosa nueva.

JunoCrear y cambiar entre ramasgit switch -c forecast crea una rama y te mueve a ella en un solo paso, que es lo que usarás casi siempre. Cambiar de rama intercambia qué versión de tus archivos ves, así que un archivo agregado en una rama está ausente en otra hasta que vuelvas a cambiar. No se pierde nada, queda guardado en la otra rama.
JunoCrear y cambiar entre ramasgit switch -c nombre crea y mueve en un solo paso. Encontrarás git checkout nombre haciendo lo mismo en tutoriales y bases de código más antiguas; es la misma idea bajo un comando más antiguo y con más funciones encimadas. Usa switch en el día a día y lee checkout sin dudar cuando lo veas.
JunoCrear y cambiar entre ramascheckout maneja tanto el cambio de rama como la restauración de archivos según sus argumentos, que es exactamente la ambigüedad que switch y restore se crearon para eliminar. Espera leer checkout en scripts y tutoriales antiguos durante años todavía; sigue funcionando, pero ya no es el comando que deberías escribir por defecto.

HEAD y HEAD desacoplado ​

Git registra en qué punto estás en este momento con un marcador llamado HEAD. Normalmente HEAD apunta a tu rama actual, y esa rama apunta a un commit, así que HEAD se mueve automáticamente cada vez que cambias de rama o haces un commit. Si haces checkout a un commit específico usando su hash, o a un tag (una etiqueta fija anclada a un solo commit, que a menudo marca una versión de lanzamiento), en lugar de un nombre de rama, HEAD se adjunta directamente a ese commit en vez de a una etiqueta de rama. A este estado se le llama HEAD desacoplado.

Puedes mirar libremente ahí, e incluso puedes hacer commits, pero nada apunta a esos nuevos commits por nombre. Si cambias a una rama sin haber creado una primero, esos commits se vuelven difíciles de encontrar de nuevo.

bash
$ git switch a1b2c3d
HEAD is now at a1b2c3d Add password strength meter

Ese mensaje, "HEAD is now at" ("HEAD ahora está en"), es la forma en que Git te dice que has salido del territorio de las ramas y que HEAD quedó adjunto a un único commit.

En el trabajo diario, raras veces llegas aquí por accidente. Ocurre con más frecuencia cuando haces checkout de un tag antiguo o de un commit específico para ver cómo se comportaba el código en ese punto, o cuando una herramienta de build hace checkout de un commit exacto para trabajar a partir de él. Si solo quieres mirar, no hay problema: explora los archivos, ejecuta la app, y luego vuelve a cambiar a una rama cuando termines. Si haces un cambio que vale la pena conservar mientras estás desacoplado, crea una rama antes de cambiar a otro lado: git switch -c fix/old-bug desde ese estado desacoplado le da al commit una etiqueta real para que sobreviva al cambio.

Un commit que queda atrás por un HEAD desacoplado no se elimina en el momento en que cambias de rama. Se vuelve inalcanzable: sigue almacenado, pero ya no hay ninguna rama, tag ni HEAD que apunte a él. Git tampoco lo limpia de inmediato. Mantiene un reflog, un registro de todos los lugares a los que HEAD ha apuntado, y un commit inalcanzable normalmente sobrevive durante semanas antes de que Git lo elimine definitivamente.

Eso te da tiempo real para recuperarlo, aunque no dura para siempre. Crear una rama antes de cambiar de lugar mantiene a salvo el trabajo desacoplado. Recuperar un commit desde el reflog funciona hoy, pero la entrada eventualmente expira y el hash de un commit se te olvida mucho antes de que eso pase, así que haz que crear ramas sea el hábito y guarda el reflog para esa rara vez que se te olvide, tema que se cubre en Deshacer cambios.

JunoHEAD y HEAD desacoplado HEAD marca el commit en el que estás parado actualmente, y por lo general se mueve junto con la rama en la que estés. Si haces checkout de un commit específico en lugar de una rama, obtienes un HEAD desacoplado, y cualquier commit nuevo que hagas ahí no tiene un nombre de rama que lo señale. Si eso llega a pasar y quieres conservar el trabajo, crea una rama ahí mismo antes de cambiar a cualquier otro lado.
JunoHEAD y HEAD desacoplado Lo más probable es que te encuentres con un HEAD desacoplado cuando hagas checkout de un tag o de un commit antiguo para revisar algo, y es inofensivo mientras solo estés leyendo. En el momento en que hagas un commit que valga la pena conservar, ejecuta git switch -c ahí mismo para darle una rama antes de moverte a cualquier otro lado.
JunoHEAD y HEAD desacoplado Normalmente HEAD apunta a una rama, y esa rama apunta a un commit. Desacoplado, HEAD apunta directamente al commit, así que cualquier cosa que agregues ahí no tiene un nombre de rama que la sostenga una vez que cambies de lugar. Rara vez se pierde para siempre, porque el reflog deja un rastro, pero no cuentes con recordar el hash del commit tres semanas después. Crea la rama antes de cambiar, siempre.

Hacia dónde va esto ​

Ya has creado ramas, te has movido entre ellas, y has visto cómo main permanece intacta mientras experimentas en otro lado. La siguiente pregunta es cómo el trabajo hecho en una rama vuelve a main, que es exactamente lo que cubre Fusiones y conflictos. Si quieres repasar cómo leer el historial de commits antes de seguir, Historial recorre git log, git show y git diff.