Con lo de los temas anteriores ya trabajas con Git de verdad: commits, ramas, conflictos y un servidor compartido. Este tema reúne las herramientas que se usan a diario para que ese trabajo sea cómodo: que Git no vea lo que no debe, apartar lo que estás haciendo cuando llega algo urgente, marcar versiones, llevar un commit suelto de una rama a otra y encontrar el commit que rompió algo.
En este tema trabajas en un observatorio astronómico: el programa que mueve el telescopio vive
en Git, en ~/telescopio. Como siempre, cada sección tiene un ejercicio con una terminal.
Lo que no va en Git: .gitignore
El telescopio deja registros (*.log), una carpeta cache/ con datos de usar y tirar… Nada de eso
debe ir a Git, y git status no para de recordarlo. Un archivo .gitignore en la carpeta del
repositorio le dice a Git qué no mirar, un patrón por línea:
tecnico@observatorio:~/telescopio$ printf '*.log\ncache/\n' > .gitignore
*.log: cualquier archivo acabado en.log, esté donde esté.cache/: la barra final dice que es una carpeta (y todo lo de dentro)./secreto.txt: con la barra delante, solo el de la raíz;docs/*.pdf, los de esa carpeta.**/viejos/: la carpetaviejos, a cualquier hondura.!importante.log: vuelve a incluir algo que un patrón de antes ignoraba.- Las líneas que empiezan por
#son comentarios.
Ahora git status solo enseña el propio .gitignore, que sí se guarda en un commit: así vale
para todos los que tengan el repositorio. Si dudas de por qué algo se ignora,
git check-ignore -v dice qué línea lo hace:
tecnico@observatorio:~/telescopio$ git check-ignore -v error.log cache/estrellas.tmp .gitignore:1:*.log error.log .gitignore:2:cache/ cache/estrellas.tmp
tecnico@observatorio:~/telescopio$ git rm --cached registro.log rm 'registro.log'
Si de verdad quieres añadir algo ignorado, git add te avisa y te pide -f.
Ejercicio
Lo que no va en Git
El programa deja registros (*.log) y una carpeta cache/ que no deben ir a Git, y alguien guardó por error registro.log. Haz que Git los ignore con un .gitignore (guardado en un commit) y saca registro.log de Git sin borrarlo del disco.
Preparando la máquina…
Guardar lo de a medias: git stash
Estás cambiando la velocidad de seguimiento, a medias, y llega un aviso: hay un error en otro
archivo que hay que arreglar ya, en un commit que no lleve lo tuyo sin terminar. git stash
guarda lo que tienes sin guardar (lo preparado y lo cambiado) en un sitio aparte y deja la carpeta
como el último commit:
tecnico@observatorio:~/telescopio$ git stash Saved working directory and index state WIP on main: e09724e El programa del telescopio
Con la carpeta limpia haces el arreglo y su commit. Después, git stash pop devuelve lo que
guardaste (y lo quita del stash):
tecnico@observatorio:~/telescopio$ git stash pop On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: seguimiento.txt no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (b88bbc57be704e947571f29b000289c8ddf851ca)
Por defecto, git stash no se lleva los archivos que Git no sigue; con -u también. Y con
-m "mensaje" le pones nombre, para reconocerlo después. Si lo que vuelve choca con lo que has
cambiado entretanto, sale un conflicto como en un merge (lo guardado se queda en el stash hasta que
lo resuelves y haces git stash drop).
Ejercicio
Un arreglo urgente
Estás a medias cambiando la velocidad en seguimiento.txt, y llega un aviso: la latitud de montura.txt está mal (40.4, y es 40.5) y hay que arreglarlo ya, en main, en un commit que no lleve lo de a medias. Guárdalo con git stash, haz el arreglo y después recupera lo de a medias.
Preparando la máquina…
Varias cosas guardadas: la pila del stash
El stash es una pila: lo último guardado es stash@{0}, lo de antes stash@{1}, y así.
git stash list la enseña:
tecnico@observatorio:~/telescopio$ git stash list stash@{0}: On main: Prueba del filtro azul stash@{1}: On main: La lista de objetivos
Todas las órdenes aceptan cuál: git stash show -p stash@{1} enseña lo que tiene,
git stash pop stash@{1} lo devuelve y lo quita, git stash apply stash@{1} lo devuelve
sin quitarlo, y git stash drop stash@{1} lo tira sin aplicarlo. git stash clear vacía la
pila entera (sin vuelta atrás). Ojo: si se guardó con -u, git stash show -p no enseña los
archivos nuevos (solo los cambios de los que Git ya seguía); para verlos, git stash apply, que
no lo quita de la pila.
Ejercicio
La lista de objetivos
Hace días guardaste en el stash dos cosas: una prueba del filtro que no sirvió y la lista de objetivos de esta noche (objetivos.txt). Recupera solo la lista y deja la prueba del filtro en el stash.
Preparando la máquina…
Versiones: git tag
Una etiqueta es un nombre fijo para un commit: la versión que se usó en una campaña, la que se
publicó… A diferencia de una rama, no se mueve. Las hay ligeras (git tag v1.0, solo el
nombre) y anotadas (-a), que guardan además quién la puso, cuándo y un mensaje; para marcar
versiones se usan las anotadas:
tecnico@observatorio:~/telescopio$ git tag -a v2.0 -m "Campaña de invierno"
git tag las lista, git log las enseña junto a su commit (tag: v2.0) y git show v2.0 enseña
la etiqueta y su commit:
tecnico@observatorio:~/telescopio$ git show v2.0 --stat tag v2.0 Tagger: Ana Técnica <[email protected]> Date: Mon Mar 8 22:03:03 2027 +0000 Campaña de invierno commit 354c830b7b4d0c2f0b1c15790d1761b32923b101 (HEAD -> main, tag: v2.0, origin/main) Author: Ana Técnica <[email protected]> Date: Sun Feb 7 22:01:08 2027 +0000 Noche 2 ...
Las etiquetas no se suben solas con git push: hay que subirlas aparte, una
(git push origin v2.0) o todas (git push --tags):
tecnico@observatorio:~/telescopio$ git push origin v2.0 Enumerating objects: 1, done. Counting objects: 100% (1/1), done. Writing objects: 100% (1/1), 156 bytes | 156.00 KiB/s, done. Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 To /srv/git/telescopio.git * [new tag] v2.0 -> v2.0
Para volver a ver el programa como estaba en una versión: git switch --detach v1.0 (o
git checkout v1.0), con HEAD suelto, como en el tema 2. Y git describe nombra el commit de
ahora a partir de la última versión (v2.0, o v2.0-3-g1a2b3c4: tres commits después).
La etiqueta va al commit en el que estás, salvo que le digas otro al final:
git tag -a v1.1 -m "…" 1a2b3c4 marca ese commit sin moverte a él. Si el nombre ya existe,
git tag -f la vuelve a poner (y para subirla otra vez, git push -f origin v1.1).
Ejercicio
La versión de invierno
El programa de ahora es el que va a usar la campaña de invierno. Márcalo como v2.0 con una etiqueta anotada (con el mensaje que quieras) y súbela al repositorio compartido (origin), para que el resto del equipo la tenga.
Preparando la máquina…
Traer un commit suelto: git cherry-pick
La rama estable es lo que usa el telescopio esta noche y tiene un fallo. En main ya está
arreglado, pero main lleva más cosas que aún no van (un merge las traería todas).
git cherry-pick <commit> copia solo lo que hizo ese commit encima de la rama de ahora, en
un commit nuevo con el mismo mensaje y el mismo autor:
tecnico@observatorio:~/telescopio$ git log --oneline main 70640c1 (HEAD -> main) Noche 1 442a7ee Arreglo: la velocidad de seguimiento fc5dd03 El espectrógrafo, en pruebas 5954198 (estable) Velocidad nueva e09724e El programa del telescopio
tecnico@observatorio:~/telescopio$ git switch estable && git cherry-pick 442a7ee Switched to branch 'estable' [estable abfb253] Arreglo: la velocidad de seguimiento Date: Fri Mar 5 22:00:03 2027 +0000 1 file changed, 1 insertion(+), 1 deletion(-)
Es un commit nuevo (otro hash): el de main sigue allí. Con -x, el mensaje dice de qué
commit viene. Si lo que trae choca con lo de la rama, se queda a medias como un merge: lo resuelves,
git add y git cherry-pick --continue (o --skip para saltarlo, --abort para dejarlo
todo como estaba).
Una rama es solo un nombre que apunta a un commit: si un git reset --hard de más (o borrarla)
la deja sin commits que tenía, siguen ahí. git reflog dice dónde estaba, y git merge <ese commit>
se los devuelve sin perder lo nuevo (o, borrada, git branch <rama> <ese commit> la vuelve a crear).
Ejercicio
El arreglo, a la estable
En la rama estable está lo que usa el telescopio esta noche, con un fallo en la velocidad. En main ya está arreglado (el commit "Arreglo: la velocidad de seguimiento"), pero main lleva más cosas que aún no van. Lleva a estable solo ese arreglo.
Preparando la máquina…
¿Cuándo se rompió? git bisect
En la versión de otoño la velocidad de seguimiento era 15, y ahora es 0. Entre medias hay muchos
commits. Mirarlos uno a uno es lento; git bisect busca a mitades: le dices uno malo y uno
bueno, y Git te deja en el de en medio. Lo pruebas, le dices si está bien o mal, y vuelve a partir
lo que queda. Con 10 commits, en 3 o 4 pasos lo tienes.
tecnico@observatorio:~/telescopio$ git bisect start && git bisect bad && git bisect good v1.0 Bisecting: 4 revisions left to test after this (roughly 2 steps) [a5e8e2a6fe9f07f39b46cfdb591d60a7ba23138c] Noche 5
Ahora la carpeta está en ese commit (con HEAD suelto). Lo pruebas (aquí, mirando
seguimiento.txt) y se lo dices: git bisect good si está bien, git bisect bad si no
(y git bisect skip si no se puede probar). Al final:
tecnico@observatorio:~/telescopio$ git bisect bad a5e8e2a6fe9f07f39b46cfdb591d60a7ba23138c is the first bad commit commit a5e8e2a6fe9f07f39b46cfdb591d60a7ba23138c Author: Ana Técnica <[email protected]> Date: Sun Feb 21 22:00:01 2027 +0000 Noche 5 campanas.md | 1 + seguimiento.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
Si la prueba es una orden, git bisect run la lanza en cada paso y decide solo (si acaba bien,
el commit es bueno; si falla, malo): git bisect run sh -c "grep -q 'velocidad = 15' seguimiento.txt".
Ejercicio
¿Cuándo se rompió?
En la v1.0 la velocidad de seguimiento era 15, y ahora es 0: alguna de las noches de después la estropeó. Encuéntrala con git bisect, escribe su hash (con siete cifras basta) en ~/culpable.txt y deja el repositorio como estaba (git bisect reset).
Preparando la máquina…
Resumen
| Orden | Qué hace |
|---|---|
.gitignore |
los patrones de lo que Git no mira (*.log, cache/, !esto) |
git check-ignore -v ruta |
qué línea de qué .gitignore la ignora |
git rm --cached archivo |
que Git deje de seguirlo, sin borrarlo de la carpeta |
git stash (-u, -m "…") |
guarda lo de a medias y deja la carpeta como el último commit |
git stash list / show |
la pila de lo guardado / lo que tiene una entrada |
git stash pop / apply / drop |
devolver (y quitar) / devolver sin quitar / tirar |
git tag -a v2.0 -m "…" |
una etiqueta anotada en el commit de ahora |
git push origin v2.0 / --tags |
subir una etiqueta / todas |
git describe |
el commit de ahora, a partir de la última versión |
git cherry-pick <commit> |
copiar lo que hizo un commit encima de la rama de ahora |
git bisect start / good / bad / reset |
buscar a mitades el commit que lo rompió |
git bisect run <orden> |
que la búsqueda pruebe sola cada commit |