Tags con Git

Anteriormente hemos hablado sobre el manejo de ramas con Git así como el Git stashing que nos permite guardar el estado de nuestros directorios de trabajo en cualquier momento para poder aplicarlo en la rama que queramos de forma sencila.

En Git, una etiqueta o tag sirve básicamente como una rama firmada que no permuta, es decir, siempre se mantiene inalterable. Sencillamente es una cadena arbitraria que apunta a un commit específico. Puede decirse que un tag es un nombre que puedes usar para marcar un punto específico en la historia de un repositorio.

Los tags pueden ser muy útiles para marcar hitos de progreso sobre todo si trabajamos con metodologías de desarrollo ágil. Si tenemos sprints semanales podemos marcar el estado del proyecto en la finalización de cada una de las iteraciones utilizando un nombre adecuado para ese momento en la historia del respositorio.

A fondo

En el último artículo sobre Git que escribí, un usuario hizo valiosos aportes acerca del funcionamiento interno de Git. Para este nuevo artículo, he decidido enriquecerlo aportando datos del funcionamiento interno del Git Tagging que espero que os resulten tan fascinantes como me resultan a mi.

Si por ejemplo queremos etiquetar nuestro código en base a cada vez que hacemos un despliegue a producción o cada vez que liberamos un binario, podemos hacerlo de forma realmente sencilla utilizando el comando git tag:

$ git tag -a v0.1 -m 'Release v0.1'
El comando anterior creará un nuevo objeto Git con una estructura similar a la siguiente:
tag: b45fb8
object 2bfd97
type commit
tag v0.1
tagger Oscar Campos [oscar .campos@************.com]
Release v0.1
Dicho objeto se almacenará en el directorio .git/objects/ y creará una referencia permanente en .git/refs/tags/v0.1 que contendrá el SHA-1 del tag.

Tags ligeros

También podemos crear tags que no almacenen objetos de tipo Tag en la base de datos pero que si creen la referencia en .git/refs/tags. Esto se hace ejecutando el comando:

$ git tag v0.1
Git creará el mismo archivo .git/refs/tags/v0.1, pero contendrá el SHA-1 que apunte al commit HEAD actual en si mismo y no a un SHA-1 que apunte a un objeto Tag que a su vez apunte a ese commit. Este tipo de tag puede mover su apuntador de forma sencilla lo cual es por regla general algo no deseado.

Tags firmados

Los objetos Tag pueden ser firmados utilizando una clave GPG para asegurar su integridad criptográfica. Si reemplazamos el parámetro -a con -s en la línea de comandos, crearemos un objeto Tag y será firmado que la clave GPG del del correo electrónico del usuario que realiza el tag. Si queremos especificar una clave podemos hacerlo con el parámetro -u:

$ git tag -s v0.1 -m 'Release v0.1'
Los Tags firmados pueden ser comprobados a posteriori utilizando el parámetro -v:
$ git tag -v v0.1

Marcando hitos con Tags

Conforme vas avanzando en el desarrollo de tu aplicación, será necesario ir marcando hitos del desarrollo de tu repositorio. Los tags pueden ser usados para marcar momentos en la línea temporal del repositorio. Se puede etiquetar cualquier commit en Git para cualquier cometido que se nos ocurra.

Como ya hemos dicho anteriormente, los tags son de solo lectura, a diferencia de a lo que estarás acostumbrado si provienes del mundo de Subversion. No es posible realizar cambios sobre un tag, este comportamiento es mucho más adecuado para trabajar con tags puesto que podemos estar seguros de que un tag es justamente aquello que etiquetamos y no ha sufrido cambios desde entonces.

Git crea los tags basándose en el commit del directorio de trabajo actual si no añadimos más argumentos que el nombre del tag. Podemos proveer al comando git tag de parámetros adicionales para especificar el commit que queremos etiquetar. Este parámetro adicional puede ser cualquier commit y lo más importante, cualquier nombre de rama válido.

Esto nos permite por ejemplo crear tags desde el último commit en nuestra rama de tontadas de esta manera:

$ git tag tontadas/v1.2 tontadas
$ git tag
v0.1
v0.5
v1.0
v1.2
tontadas/v1.2
Podemos usar los tags para volver al estado del respositorio que marcan y aunque no se pueden realizar cambios sobre un tag, si que puedes cambiar a ellos como si fuera una rama:
git checkout v1.0
Note: checking out 'v1.0'.
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 performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
  git checkout -b new_branch_name
HEAD is now at 10c3ee2... Initial Eltiodelavara Commit.
En este punto estamos en tierra de nadie. No estamos en ninguna rama por lo que no podemos hacer cambios ya que no quedarán reflejados en ningún sitio.
$ git branch
* (no branch)
  master
  v0.2
Pero si que podemos hacer cambios y crear una nueva rama donde alojar dichos cambios, esto nos permite hacer forks desde hitos específicos.

Conclusión

Hemos visto que son y como funcionan los tags en Git. Es evidente la gran diferencia entre un tag en Git y en Subversion, esto es debido a que Git funciona por un comportamiento basado en ramas y merges y no por tags (lo cual tiene sus defensores y sus detractores por supuesto). En próximos artículos seguiremos hablando de Git.


Más en Genbeta Dev | Ramas de desarrollo con Git
Más Información | Manual de git tag

Portada de Genbeta