El cliente quiere ver la casa con buhardilla. Y con piscina. Y quizá con un garaje. Si todo eso se dibuja sobre el proyecto aprobado, se mezcla, y deshacer lo que no guste es un lío. Las ramas lo resuelven: cada propuesta va en su propia línea de commits, sin tocar las demás, y la que se aprueba se junta con la principal.
En este tema trabajas con Trazo, un estudio de arquitectura que guarda en Git los planos de sus proyectos. Como en los anteriores, cada sección tiene un ejercicio con una terminal.
Crear una rama y cambiarse a ella
git branch enseña las ramas; la de ahora, con un *. Con un nombre, crea una nueva, que
apunta al mismo commit que la actual (sin cambiarse a ella):
tecnico@srv-pruebas:~/estudio$ git branch buhardilla
tecnico@srv-pruebas:~/estudio$ git branch buhardilla * main
git switch rama te cambia a ella: los archivos de la carpeta pasan a ser los de esa rama, y
los commits que hagas irán a ella.
tecnico@srv-pruebas:~/estudio$ git switch buhardilla Switched to branch 'buhardilla'
Las dos cosas a la vez: git switch -c rama (crear y cambiarse). Antes de switch se usaba
git checkout rama y git checkout -b rama, que siguen funcionando y verás en muchas guías.
Tras un commit en buhardilla, cada rama apunta a lo suyo:
tecnico@srv-pruebas:~/estudio$ git log --oneline --all b309db4 (HEAD -> buhardilla) La buhardilla 10a2b50 (main) El proyecto básico
--all enseña todas las ramas, no solo la actual. Y al volver a main, el plano de la buhardilla
no está en la carpeta: es de la otra rama.
tecnico@srv-pruebas:~/estudio$ git switch main Switched to branch 'main'
tecnico@srv-pruebas:~/estudio$ ls planos planta-baja.txt
Ejercicio
Una rama para la propuesta
El cliente quiere ver cómo quedaría la casa con buhardilla, sin tocar el proyecto aprobado (main). Haz una rama buhardilla, cámbiate a ella y guarda allí el plano planos/buhardilla.txt (con "estudio 20" y "bano 4", una cosa por línea).
Preparando la máquina…
Cambiar de rama con cambios sin guardar
Si tienes cambios sin guardar, Git se los lleva contigo al cambiar de rama, siempre que el
archivo sea igual en las dos (y lo dice: M y el archivo):
tecnico@srv-pruebas:~/estudio$ git switch -c prueba M planos/planta-baja.txt Switched to a new branch 'prueba'
Si el archivo es distinto en la otra rama, cambiar pisaría tu trabajo, y Git no te deja:
tecnico@srv-pruebas:~/estudio$ git switch garaje error: Your local changes to the following files would be overwritten by checkout: planos/planta-baja.txt Please commit your changes or stash them before you switch branches. Aborting
¿Ya lo guardaste en main y era de otra rama? Como una rama es solo un nombre, git branch rama
crea una ahí mismo, con ese commit dentro; después, en main, git reset --hard HEAD~1 (tema 2)
lo quita de main, y la rama lo conserva.
Ejercicio
Cambiar de rama sin mezclar
Estás en la rama piscina, con la memoria a medio escribir (sin guardar). Urge corregir el presupuesto en main: las instalaciones son 22000. Guarda tu trabajo en piscina, cámbiate a main, corrige y guarda; lo de la piscina no puede llegar a main.
Preparando la máquina…
Juntar: git merge (fast-forward)
git merge rama junta esa rama con la actual. Si la actual no ha cambiado desde que salió la
otra, no hace falta mezclar nada: la rama actual simplemente avanza hasta la otra
(fast-forward):
tecnico@srv-pruebas:~/estudio$ git merge buhardilla Updating 10a2b50..b309db4 Fast-forward planos/buhardilla.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 planos/buhardilla.txt
Siempre se junta en la rama en la que estás: para llevar buhardilla a main, primero
git switch main. Si ya estaba todo, Git dice Already up to date.
Ejercicio
Main, al día
La rama garaje tiene dos commits que el cliente ya ha aprobado, y main no ha cambiado desde que se creó. Junta garaje con main.
Preparando la máquina…
Juntar dos ramas que han avanzado: el commit de merge
Si las dos ramas tienen commits nuevos, no basta con avanzar: Git hace un commit nuevo con dos
padres que junta lo de las dos (la estrategia se llama ort). Para el mensaje abre el editor con
uno ya escrito (Merge branch 'piscina'); con --no-edit lo usa sin preguntar:
tecnico@srv-pruebas:~/estudio$ git merge --no-edit piscina Merge made by the 'ort' strategy. planos/jardin.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 planos/jardin.txt
Si las dos ramas cambiaron lo mismo (las mismas líneas de un archivo), Git no sabe con cuál
quedarse: es un conflicto, y eso es el tema 4. Con --no-ff, Git hace el commit de merge
aunque pudiera avanzar, para que quede a la vista que ahí se juntó una rama.
¿Juntaste la que no era? git reflog (tema 2) dice dónde estaba main antes del merge, y
git reset --hard a ese commit la devuelve allí; la otra rama no se toca, y sigue sin juntar.
Ejercicio
Juntar dos ramas que han avanzado
El cliente aprueba la piscina. Pero mientras se dibujaba, en main también se guardó algo (el presupuesto nuevo). Junta piscina con main: un commit que lleve lo de las dos.
Preparando la máquina…
Borrar las ramas que ya no hacen falta
Una rama ya juntada sobra: su trabajo está en main. git branch --merged dice cuáles lo
están, y git branch -d rama la borra:
tecnico@srv-pruebas:~/estudio$ git branch -d buhardilla Deleted branch buhardilla (was b309db4).
Si no está juntada, -d no la borra (perderías sus commits); -D sí, si de verdad sobran:
tecnico@srv-pruebas:~/estudio$ git branch -d sotano error: The branch 'sotano' is not fully merged. If you are sure you want to delete it, run 'git branch -D sotano'.
Borrar una rama solo borra el nombre: sus commits siguen ahí un tiempo. Si al final no sobraba,
git branch sotano <hash> la vuelve a crear tal como estaba, con el hash que dijo Git al
borrarla (was …); y si no lo viste, git reflog (tema 2) apunta por dónde ha pasado HEAD,
también por sus commits. Lo mismo vale para main, si un reset de más la deja sin lo aprobado.
Otras: git branch -m vieja nueva la renombra; git branch -v, con su último commit;
git branch --no-merged, las que aún no están juntadas.
Ejercicio
Ramas que ya no hacen falta
En el estudio se acumulan ramas: las ya juntadas con main sobran, pero sotano aún no se ha juntado (el cliente no ha decidido). Borra las que ya están en main y deja sotano.
Preparando la máquina…
El gráfico: git log –graph
Con varias ramas, el historial ya no es una línea. git log --oneline --graph --all lo
dibuja: cada * es un commit, y las líneas, por dónde va cada rama; |\ es donde un merge junta
dos y |/ donde una rama salió de otra.
tecnico@srv-pruebas:~/estudio$ git log --oneline --graph --all * 71e085b (HEAD -> main) Merge branch 'piscina' |\ | * f3f2ccb (piscina) La piscina * | b309db4 (buhardilla) La buhardilla |/ * 10a2b50 El proyecto básico
Se lee de arriba abajo, de lo más nuevo a lo más viejo. Y para comparar ramas:
git log main..piscina enseña los commits de piscina que aún no están en main.
Ejercicio
Leer el gráfico
De las tres propuestas (ventanales, porche y chimenea), una aún no está en main. Mírala en el gráfico del historial y apunta su nombre en ~/respuesta.txt.
Preparando la máquina…
El HEAD suelto (detached HEAD)
git switch (o checkout) a un commit, no a una rama, deja HEAD suelto: miras cómo era el
proyecto entonces, pero no estás en ninguna rama. Git lo avisa con un mensaje largo:
tecnico@srv-pruebas:~/estudio$ git checkout HEAD~1 Note: switching to 'HEAD~1'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. … HEAD is now at b309db4 La buhardilla
Los commits que hagas así no son de ninguna rama: al volver (git switch main), Git avisa de que
se quedan atrás. Para quedártelos, crea una rama ahí mismo: git switch -c nueva.
Resumen
| Orden | Qué hace |
|---|---|
git branch (-v, -a) |
las ramas, y en cuál estás |
git branch nombre |
crea una rama (sin cambiarse) |
git switch rama / git switch -c rama |
cambiarse / crearla y cambiarse |
git checkout rama / checkout -b rama |
lo mismo, la forma antigua |
git merge rama |
junta esa rama con la actual (avanza o hace un commit de merge) |
git merge --no-edit / --no-ff |
sin editor / siempre con commit de merge |
git branch -d rama / -D |
borra una rama juntada / aunque no lo esté |
git branch --merged / --no-merged |
las juntadas / las que no |
git log --oneline --graph --all |
el historial de todas las ramas, dibujado |
git log a..b |
lo que tiene b y no tiene a |