Saltar al contenido
sudoquest@root
Git

El día a día

Lo que se usa a diario: ignorar lo que no va (.gitignore), guardar lo de a medias (stash), versiones (tag), traer un commit suelto (cherry-pick) y bisect.

40 min de lectura

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 carpeta viejos, 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