cuando hago el checkout de la etiqueta git remota uso un comando como este:
git checkout -b local_branch_name origin/remote_tag_name
Tengo un error como este:
error: pathspec `origin/remote_tag_name` did not match any file(s) known to git.
Puedo encontrar remote_tag_name cuando uso el comando git tag.
[]
Una etiqueta se utiliza para etiquetar y marcar un commit específico en el historial.
Suele utilizarse para marcar puntos de lanzamiento (por ejemplo, v1.0, etc.).
Aunque una etiqueta puede parecer similar a una rama, una etiqueta, sin embargo, no cambia.
Apunta directamente a un compromiso específico en el historial.
[]
No podrá obtener las etiquetas si no están localmente en su repositorio, por lo que primero tiene que obtener
las etiquetas en su repositorio local.
**Primero, asegúrese de que la etiqueta existe localmente haciendo
# --all will fetch all the remotes.
# --tags will fetch all tags as well
git fetch --all --tags --prune
Luego comprueba la etiqueta ejecutando
git checkout tags/<tag_name> -b <branch_name>
En lugar de origin
utilice el prefijo tags/
.
En este ejemplo tienes 2 etiquetas versión 1.0 & versión 1.1 puedes comprobarlas con cualquiera de las siguientes:
git checkout A ...
git checkout version 1.0 ...
git checkout tags/version 1.0 ...
Todos los anteriores harán lo mismo, ya que la etiqueta es sólo un puntero a un commit determinado.
[] origen: https://backlog.com/git-tutorial/img/post/stepup/capture_stepup4_1_1.png
# list all tags
git tag
# list all tags with given pattern ex: v-
git tag --list 'v-*'
Hay dos maneras de crear una etiqueta:
# lightweight tag
git tag
# annotated tag
git tag -a
La diferencia entre las 2 es que al crear una etiqueta anotada se pueden añadir metadatos como en un commit de git:
nombre, correo electrónico, fecha, comentario & firma
[]
# delete any given tag
git tag -d <tag name>
# Don't forget to remove the deleted tag form the server with push tags
Para coger el contenido de una etiqueta determinada puedes utilizar el comando checkout
.
Como se ha explicado anteriormente, las etiquetas son como cualquier otro commit, por lo que podemos utilizar checkout
y en lugar de utilizar el SHA-1 simplemente sustituirlo por el nombre_de_la_etiqueta.
Opción 1:
# Update the local git repo with the latest tags from all remotes
git fetch --all
# checkout the specific tag
git checkout tags/<tag> -b <branch>
Opción 2:
Dado que git soporta shallow clone añadiendo el --branch
al comando clone podemos usar el nombre de la etiqueta en lugar del nombre de la rama. Git sabe cómo "traducir" el SHA-1 dado al commit correspondiente
# Clone a specific tag name using git clone
git clone <url> --branch=<tag_name>
git clone --branch=
--branch
también puede tomar etiquetas y separa el HEAD en ese commit en el repositorio resultante.
git push --tags
Para empujar todas las etiquetas:
git push --tags
Para empujar las etiquetas anotadas y las etiquetas de la cadena de la historia actual utilizar::
git push --follow-tags
Esta bandera --follow-tags
empuja ambos commits y sólo las etiquetas que son ambos:
A partir de Git 2.4 puedes establecerlo mediante la configuración
git config --global push.followTags true
No hay tal cosa como una "etiqueta remota Git". Sólo hay "etiquetas". Señalo todo esto no para ser pedante,1 sino porque hay una gran confusión sobre esto con los usuarios casuales de Git, y la documentación de Git no es muy útil2 para los principiantes. (No está claro si la confusión se debe a la pobre documentación, o la pobre documentación se debe a que esto es inherentemente algo confuso, o qué).
Hay subsidiarias remotas, más propiamente llamadas "sucursales de seguimiento remoto", pero vale la pena señalar que éstas son en realidad entidades locales. Sin embargo, no hay etiquetas remotas (a menos que las (re)inventes). Sólo hay etiquetas locales, por lo que es necesario obtener la etiqueta localmente para poder utilizarla.
La forma general para los nombres de confirmaciones específicas -que Git llama referencias- es cualquier cadena que empiece por refs/
. Una cadena que empieza por refs/heads/
nombra una rama; una cadena que empieza por refs/remotes/
nombra una rama de seguimiento remoto; y una cadena que empieza por refs/tags/
nombra una etiqueta. El nombre refs/stash
es la referencia al almacén (tal y como la utiliza git stash
; nótese la falta de una barra al final).
Hay algunos nombres inusuales en casos especiales que no comienzan con refs/
: HEAD
, ORIG_HEAD
, MERGE_HEAD
, y CHERRY_PICK_HEAD
en particular son también nombres que pueden referirse a confirmaciones específicas (aunque HEAD
normalmente contiene el nombre de una rama, es decir, contiene ref: refs/heads/branch
). Pero en general, las referencias comienzan con refs/
.
Una cosa que hace Git para hacer esto confuso es que te permite omitir las refs/
, y a menudo la palabra después de refs/
. Por ejemplo, puedes omitir refs/heads/
o refs/tags/
cuando te refieras a una rama local o a una etiqueta -¡y de hecho debes omitir refs/heads/
cuando revises una rama local! Puedes hacer esto siempre que el resultado no sea ambiguo, o -como acabamos de señalar- cuando debas hacerlo (para git checkout branch
).
Es cierto que las referencias existen no sólo en tu propio repositorio, sino también en repositorios remotos. Sin embargo, Git te da acceso a las referencias de un repositorio remoto sólo en momentos muy concretos: durante las operaciones fetch
y push
. También puedes usar git ls-remote
o git remote show
para verlas, pero fetch
y push
son los puntos de contacto más interesantes.
Durante fetch
y push
, Git utiliza cadenas que llama refspecs para transferir referencias entre el repositorio local y el remoto. Así, es en estos momentos, y a través de refspecs, cuando dos repositorios Git pueden sincronizarse entre sí. Una vez que sus nombres están sincronizados, puedes usar el mismo nombre que usa alguien en el remoto. Sin embargo, hay algo de magia especial en fetch
, y afecta tanto a los nombres de las ramas como a los de las etiquetas.
Deberías pensar en git fetch
como si dirigieras tu Git para llamar (o quizás enviar un mensaje de texto) a otro Git -el "remoto" - y tener una conversación con él. Al principio de esta conversación, el remoto lista todas sus referencias: todo lo que está en refs/heads/
y todo lo que está en refs/tags/
, junto con cualquier otra referencia que tenga. Tu Git escanea a través de ellas y (basándose en el fetch refspec habitual) renombra sus ramas.
Echemos un vistazo a la refspec normal para la remota llamada origin
:
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$
Esta refspec ordena a tu Git que tome todos los nombres que coincidan con refs/heads/*
-es decir, todas las ramas del remoto- y cambie su nombre a refs/remotes/origin/*
, es decir, que mantenga la parte coincidente igual, cambiando el nombre de la rama (refs/heads/
) por un nombre de rama de seguimiento del remoto (refs/remotes/
, concretamente, refs/remotes/origin/
).
Es a través de esta refspec que las ramas de origin
se convierten en sus ramas de seguimiento remoto para origin
remoto. El nombre de la rama se convierte en el nombre de la rama de seguimiento remoto, con el nombre del remoto, en este caso origin
, incluido. El signo "+" al principio de la especificación de referencia establece la bandera "forzar", es decir, su rama de seguimiento remoto se actualizará para que coincida con el nombre de la rama remota, independientemente de lo que haga falta para que coincida. (Sin el +
, las actualizaciones de la rama se limitan a los cambios "fast forward", y las actualizaciones de las etiquetas simplemente se ignoran desde la versión 1.8.2 de Git, más o menos-antes se aplicaban las mismas reglas de fast-forward).
¿Pero qué pasa con las etiquetas? No hay refspec para ellas, al menos no por defecto. Puedes establecer una, en cuyo caso la forma de la refspec depende de ti; o puedes ejecutar git fetch --tags
. Usar --tags
tiene el efecto de añadir refs/tags/*:refs/tags/*
a la refspec, es decir trae todas las etiquetas (pero no actualiza su etiqueta si ya tiene una etiqueta con ese nombre, independientemente de lo que diga la etiqueta remota Edición, enero de 2017: a partir de Git 2.10, las pruebas muestran que --tags
actualiza forzosamente tus etiquetas a partir de las etiquetas remotas, como si la especificación de referencia dijera +refs/tags/*:refs/tags/*
; esto puede ser una diferencia de comportamiento respecto a una versión anterior de Git).
Tenga en cuenta que aquí no hay renombramiento: si el origen
remoto tiene la etiqueta xyzzy
, y usted no, y usted git fetch origin "refs/tags/*:refs/tags/*"
, obtendrá refs/tags/xyzzy
añadido a su repositorio (apuntando al mismo commit que en el remoto). Si utiliza +refs/tags/*:refs/tags/*
entonces su etiqueta xyzzy
, si tiene una, es reemplazada por la del origen
. Es decir, la bandera de fuerza +
en una refspec significa "reemplazar el valor de mi referencia' con el que mi Git obtiene de su Git'.
Por razones históricas,3 si no usas ni la opción --tags
ni la opción --no-tags
, git fetch
toma una acción especial. Recuerda que dijimos arriba que el remoto comienza mostrando a tu Git local todas sus referencias, tanto si tu Git local quiere verlas como si no.4 Tu Git toma nota de todas las etiquetas que ve en este punto. Luego, cuando empieza a descargar los objetos de confirmación que necesita para manejar lo que sea que está recuperando, si uno de esos commits tiene el mismo ID que cualquiera de esas etiquetas, git añadirá esa etiqueta -o esas etiquetas, si varias etiquetas tienen ese ID- a tu repositorio.
Edit, Jan 2017: las pruebas muestran que el comportamiento en Git 2.10 es ahora: Si su Git proporciona una etiqueta llamada T, y tú no tienes una etiqueta llamada T, y el ID de confirmación asociado a T es un ancestro de una de sus ramas que tu git fetch
está examinando, tu Git añade T a tus etiquetas con o sin --tags
. Añadir --tags
hace que tu Git obtenga todas sus etiquetas, y también forzar la actualización.
Puede que tengas que usar git fetch --tags
para obtener sus etiquetas. Si sus nombres de etiqueta entran en conflicto con los nombres de etiqueta existentes, puedes (dependiendo de la versión de Git) incluso tener que borrar (o renombrar) algunas de tus etiquetas, y luego ejecutar git fetch --tags
, para obtener sus etiquetas. Dado que las etiquetas -a diferencia de las ramas remotas- no tienen un renombramiento automático, tus nombres de etiquetas deben coincidir con los nombres de sus etiquetas, por lo que puedes tener problemas de conflictos.
En la mayoría de los casos normales, sin embargo, un simple git fetch
hará el trabajo, trayendo sus commits y sus etiquetas coincidentes, y como ellos -quienesquiera que sean- etiquetarán los commits en el momento en que los publiquen, te mantendrás al día con sus etiquetas. Si no haces tus propias etiquetas, ni mezclas su repositorio con otros repositorios (a través de múltiples remotas), tampoco tendrás colisiones de nombres de etiquetas, por lo que no tendrás que complicarte borrando o renombrando etiquetas para obtener las suyas.
Ya he mencionado que puedes omitir refs/
casi siempre, y refs/heads/
y refs/tags/
y así la mayoría de las veces. Pero, ¿cuándo se puede omitir?
La respuesta completa (o casi completa) está en la documentación de gitrevisions
. Git resolverá un nombre a un ID de confirmación utilizando la secuencia de seis pasos que se indica en el enlace. Curiosamente, las etiquetas anulan las ramas: si hay una etiqueta xyzzy
y una rama xyzzy
, y apuntan a diferentes confirmaciones, entonces:
git rev-parse xyzzy
gitrevisions
- git checkout
prefiere los nombres de las ramas, así que git checkout xyzzy
te pondrá en la rama, sin tener en cuenta la etiqueta.
En caso de ambigüedad, casi siempre puedes deletrear el nombre de la referencia usando su nombre completo, refs/heads/xyzzy
o refs/tags/xyzzy
. (Ten en cuenta que esto funciona con git checkout
, pero de una manera quizás inesperada: git checkout refs/heads/xyzzy
provoca una comprobación detached-HEAD en lugar de una comprobación de rama. Por eso sólo tienes que tener en cuenta que git checkout
utilizará primero el nombre corto como nombre de rama: así es como se hace el checkout de la rama xyzzy
aunque la etiqueta xyzzy
exista. Si quieres comprobar la etiqueta, puedes usar refs/tags/xyzzy
).
Dado que (como señala gitrevisions
) Git intentará refs/name
, también puedes simplemente escribir tags/xyzzy
para identificar el commit etiquetado xyzzy
. (Sin embargo, si alguien ha conseguido escribir una referencia válida llamada xyzzy
en $GIT_DIR
, esto se resolverá como $GIT_DIR/xyzzy
. Pero normalmente sólo los distintos nombres *HEAD
deberían estar en $GIT_DIR
).1Vale, vale, "no sólo para ser pedante". :-)
2Algunos dirían "muy poco útil", y yo tendería a estar de acuerdo, en realidad.
Básicamente, git fetch
, y todo el concepto de remotas y refspecs, fue una adición un poco tardía a Git, que ocurrió alrededor de la época de Git 1.5. Antes de eso sólo había algunos casos especiales ad-hoc, y la obtención de etiquetas era uno de ellos, por lo que se incluyó mediante un código especial.
Si ayuda, piensa en el Git remoto como un flasher, en el sentido del argot.