Herramientas de Git

Revision por Seleccion

Revision por Seleccion

Git te permite especificar commits o rangos de commits de varias formas. No son necesariamente obvias, pero vale la pena conocerlas.


checksum SHA-1 Corto

Git es lo suficientemente inteligente como para deducir el commit al que te refieres si le das los primeros caracteres del checksum SHA-1, siempre que sea lo suficientemente largo para ser unico (al menos 4 caracteres). Por ejemplo:

git log --abbrev-commit --pretty=oneline
734713b changed the version number
d921970 removed unnecessary test code
1c002dd first commit

La opcion --abbrev-commit muestra los valores cortos pero manteniendolos unicos. (por defecto muestra 7 caracteres)


Puedes hacer referencia a cualquiera de esos commits usando los primeros caracteres unicos de su checksum SHA-1. Por ejemplo:

# Los 3 comandos son equivalentes
git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
git show 1c002dd4b536e7479f
git show 1c002d

Referencias de Rama

La forma mas sencilla de referirse a un commit especifico es usar el nombre de una rama que apunte a el. Por ejemplo, si quieres ver a que objeto commit apunta la rama topic1:

git show topic1

Si quieres ver a que checksum SHA-1 apunta una rama, puedes usar el comando de fontaneria git rev-parse:

git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949

Reflog

Mientras trabajas, Git registra silenciosamente donde han estado HEAD y tus ramas en los ultimos meses en el reflog. Puedes consultarlo con:

git reflog
734713b HEAD@{0}: commit: fixed refs handling
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd HEAD@{2}: commit: added some blame and merge stuff

Cada vez que la ultima referencia de tu rama es actualizada por cualquier motivo, Git guarda esa informacion en el historial temporal del reflog. Puedes usar la sintaxis @{n} para referirte a confirmaciones anteriores:

git show HEAD@{5}           # quinto HEAD anterior
git show master@{yesterday} # donde estaba master ayer

Es importante destacar que el reflog es estrictamente local. Solo existe en tu propio repositorio y refleja lo que tu has hecho. No tiene ninguna relacion con lo que otros hayan hecho en su copia del repositorio.


Seleccion por Ancestro

La otra forma principal de especificar un commit es a traves de su ancestro. Si colocas ^ al final de una referencia, Git lo resuelve como el padre de ese commit:

git show HEAD^     # padre de HEAD
git show HEAD^^    # abuelo de HEAD

En caso de que un commit tenga mas de 1 padre (en un merge commit por ejemplo), podriamos hacer algo como esto:

# Supongamos un merge topic1 -> dev
git show HEAD^ # El primer padre de HEAD (dev)
git show HEAD^2 # segundo padre de HEAD (topic1)

La otra sintaxis de ancestro es el tilde ~. HEAD~ es equivalente a HEAD^. La diferencia aparece cuando se combina con un numero: HEAD~3 significa el bisabuelo (primer padre, tres niveles atras), mientras que HEAD^3 seria el tercer padre de un merge commit.

git show HEAD~3 # 3 commits atras
git show HEAD^^^ # 3 commits atras

Ejercicio 01

Seleccion de revision

Entrar al kahoot y esperar el codigo de la sala, o presionar la opcion “Aprende” para responder de forma individual.


Rangos de Commits

Ahora que ya sabes como especificar commits individuales, veamos como especificar rangos. Supongamos un historial como el siguiente:

Commits alcanzables por master o experiment pero no por ambos

Doble punto

La sintaxis mas comun es el rango con doble punto .., que le dice a Git que resuelva todos los commits que son alcanzables desde una referencia pero no desde la otra:

git log master..experiment # Commits de experiment no alcanzados por master
D
C

Esto muestra todos los commits en experiment que aun no han sido fusionados en master. Si lo inviertes, ves los commits de master que no estan en experiment:

git log experiment..master # Commits de master no alcanzados por experiment
F
E

Esto es muy util para saber que vas a enviar a un remoto antes de hacer push:

git log origin/master..HEAD # Commits de HEAD no alcanzados por origin/master

Si HEAD no tiene nada que origin/master no tenga, el comando no devuelve nada.


Multiples puntos

Si necesitas filtrar por mas de dos ramas, puedes usar ^ o --not delante de cualquier referencia de la que no quieras ver confirmaciones:

# Comandos equivalentes
git log refA..refB          # commits en refB que no esten en refA
git log ^refA refB          # commits en refB que no esten en refA
git log refB --not refA     # commits en refB que no esten en refA

Esto es muy potente porque permite hacer lo mismo con mas de dos referencias, algo que la sintaxis de doble punto no puede hacer:

git log refA refB ^refC # commits en refA o refB pero no en refC
git log refA refB --not refC # commits en refA o refB pero no en refC

Triple punto

La sintaxis de triple punto especifica todos los commits que son alcanzables por cualquiera de las dos referencias pero no por ambas a la vez (diferencia simetrica):

git log master...experiment
F
E
D
C

Esto te muestra los commits de cada rama que no estan en la otra. Para que la salida sea mas clara, puedes añadir --left-right, que muestra de que lado del rango viene cada commit:

git log --left-right master...experiment
< F
< E
> D
> C

Con estos tres tipos de sintaxis (checksum SHA-1 corto, referencias de rama, y rangos) tienes un control muy preciso sobre cualquier punto o tramo del historial de tu proyecto.


Ejercicio 02

Rangos de commits

  • Descargar targz
  • Descomprimir con tar -xzf 11-rangos-commits.tar.gz
  • Entrar a la carpeta con cd 11-rangos-commits/
  • Abre tu editor de codigo (ej: code .) y lee el README.md

Recursos