Elimine las etiquetas git locales que ya no están en el repositorio remoto

468

Usamos etiquetas en git como parte de nuestro proceso de implementación. De vez en cuando, queremos limpiar estas etiquetas eliminándolas de nuestro repositorio remoto.

Esto es bastante sencillo. Un usuario elimina la etiqueta local y la etiqueta remota en un conjunto de comandos. Tenemos un pequeño script de shell que combina ambos pasos.

El segundo usuario (tercero, cuarto, ...) ahora tiene etiquetas locales que ya no se reflejan en el control remoto.

Estoy buscando un comando similar al git remote prune originque limpia localmente las ramas de seguimiento para las que se ha eliminado la rama remota.

Alternativamente, se podría usar un comando simple para enumerar etiquetas remotas para comparar con las etiquetas locales devueltas mediante git tag -l.

kEND
fuente
2
Propuse
Adam Monsen
1
Nota: con Git 2.17 (Q2 2018), ¡un simple git config fetch.pruneTags truehará que git fetchhagas lo que quieras! Vea mi respuesta a esta otra pregunta .
VonC
2
Reposicionando un comentario de una de las respuestas a continuación: Al menos con git 2.18.0 también se puede usar esta sintaxis: git fetch --prune --prune-tags origin
zutnop

Respuestas:

71

Buena pregunta. :) No tengo una respuesta completa ...

Dicho esto, puede obtener una lista de etiquetas remotas a través de git ls-remote. Para enumerar las etiquetas en el repositorio al que hace referencia origin, debe ejecutar:

git ls-remote --tags origin

Eso devuelve una lista de hashes y nombres de etiquetas amigables, como:

94bf6de8315d9a7b22385e86e1f5add9183bcb3c        refs/tags/v0.1.3
cc047da6604bdd9a0e5ecbba3375ba6f09eed09d        refs/tags/v0.1.4
...
2f2e45bedf67dedb8d1dc0d02612345ee5c893f2        refs/tags/v0.5.4

Ciertamente, podría armar un script bash para comparar las etiquetas generadas por esta lista con las etiquetas que tiene localmente. Eche un vistazo a git show-ref --tags, que genera los nombres de etiqueta en la misma forma que git ls-remote).


Como un aparte, git show-reftiene una opción que hace lo contrario de lo que le gustaría. El siguiente comando enumeraría todas las etiquetas en la rama remota que no tiene localmente:

git ls-remote --tags origin | git show-ref --tags --exclude-existing
Mike West
fuente
Gracias Mike Rodaré mi propio script bash usando cada lista para comparar.
kEND
11
La respuesta de Richard W lo hace de manera mucho más elegante, en caso de que no esté interesado en un guión complicado.
Kyle Heironimus
1
La nota al margen sobre las etiquetas que no están presentes localmente se puede ampliar para verificar más controles remotos:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec
Vea la siguiente respuesta para una solución más simple
sfletche
git admite --prune-tags. No estoy seguro de qué versión se introdujo. git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian
1054

Esta es una gran pregunta, me había estado preguntando lo mismo.

No quería escribir un guión, así que busqué una solución diferente. La clave es descubrir que puede eliminar una etiqueta localmente, luego usar git fetch para "recuperarla" desde el servidor remoto. Si la etiqueta no existe en el control remoto, permanecerá eliminada.

Por lo tanto, debe escribir dos líneas en orden:

git tag -l | xargs git tag -d
git fetch --tags

Estas:

  1. Eliminar todas las etiquetas del repositorio local. FWIW, xargs coloca cada salida de etiqueta por "etiqueta -l" en la línea de comando para "etiqueta -d". Sin esto, git no eliminará nada porque no lee stdin (tonto git).

  2. Obtenga todas las etiquetas activas del repositorio remoto.

Esto incluso funciona de maravilla en Windows.

Richard W
fuente
57
Esta debe ser mi respuesta git favorita en StackOverflow. Combina conocimiento, simplicidad y engaño y lo explica todo. Genial
tymtam
25
como se señaló en una respuesta por separado, esto elimina TODAS las etiquetas locales, y las que no están en el repositorio remoto obviamente no se volverán a crear
segundo
13
FWIW esto debería ser completamente innecesario. Debería haber un git tag prune origincomando.
void.pointer
99
Esto podría no funcionar para todos. Debes hacer git fetch --tags para estar seguro.
Adam Kurkiewicz
55
Tuve que ir git tag -l | %{git tag -d $_}para que esto funcionara en PowerShell. No estoy seguro de nadie más.
Alain
244

Desde Git v1.7.8 a v1.8.5.6, puede usar esto:

git fetch <remote> --prune --tags

Actualizar

Esto no funciona en versiones más nuevas de git (comenzando con v1.9.0) debido a commit e66ef7ae6f31f2 . Sin embargo, realmente no quiero eliminarlo ya que funcionó para algunas personas.

Como lo sugiere "Chad Juliano", con todas las versiones de Git desde v1.7.8, puede usar el siguiente comando:

git fetch --prune <remote> +refs/tags/*:refs/tags/*

Es posible que deba encerrar la parte de las etiquetas con comillas (en Windows, por ejemplo) para evitar la expansión de comodines:

git fetch --prune <remote> "+refs/tags/*:refs/tags/*"
loganfsmyth
fuente
2
Me refiero a la documentación que se incluye con Git para Windows 1.9.4-preview20140611 (y sospecho que todas las versiones anteriores). Accedo a dicha documentación con "git fetch --help" [quote] Las etiquetas no están sujetas a poda si se obtienen solo debido al seguimiento automático de etiquetas predeterminado o debido a una opción --tags. [/
Quote
2
git fetch --prune <remote> +refs/tags/*:refs/tags/*no funcionó en ZSH pero funciona en BASH
Alex
3
@Alex Eso es solo porque zsh se expande, *pero si cita entre comillas eso debería estar bien.
NSF
3
@ v01pe - ahora hay un acceso directo de git --prune-tags disponibles desde git 2.17.0 descrito en la documentación bajo la sección PRUNING : git-scm.com/docs/git-fetch/2.17.0 Del documento: El - La opción -prune-tags es equivalente a tener refs / tags / *: refs / tags / * declaradas en las especificaciones del control remoto. Equivalentes: git fetch origin --prune --prune-tagsOR git fetch origin --prune 'refs/tags/*:refs/tags/*'OR git fetch <url of origin> --prune --prune-tagsORgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs
3
git fetch origin --prune --prune-tagspode las ramas y etiquetas de seguimiento remoto. comprobado en la versión git 2.18.
Número945
158

Si solo desea esas etiquetas que existen en el control remoto, simplemente elimine todas sus etiquetas locales:

$ git tag -d $(git tag)

Y luego busque todas las etiquetas remotas:

$ git fetch --tags
newmangt
fuente
1
impecable, estaba teniendo problemas con el xargs que no encuentra algunas etiquetas
Marcio Toshio
3
@ocroquette, no estoy seguro de cómo es mejor que xargs. Si tiene más etiquetas que ARG_MAX, o limitaciones similares, esto no funcionará. Improbable, pero posible, y por eso xargses genial.
Paul Draper
2
"agradable" es algo subjetivo, cada uno hará su propia opinión. Acerca de ARG_MAX, eso es cierto. Sin embargo, en los sistemas que uso, ARG_MAX es mucho mayor que la cantidad de etiquetas que tengo en cualquier repositorio, por lo que no me importa la limitación, al igual que no me importa cuando escribo "ls * .jpg" .
ocroquette
2
solución más limpia
mitsest
2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'Comando de alias obligatorio. Disfrutar. :-)
Karl Wilbur
87

Parece que las versiones más recientes de Git (estoy en git v2.20) permiten simplemente decir

git fetch --prune --prune-tags

Mucho más limpio!

https://git-scm.com/docs/git-fetch#_pruning

También puede configurar git para que siempre pode las etiquetas al buscar:

git config fetch.pruneTags true

Si solo desea podar etiquetas al buscar desde un control remoto específico, puede usar la remote.<remote>.pruneTagsopción. Por ejemplo, para podar siempre las etiquetas al buscar desde el origen pero no otros controles remotos,

git config remote.origin.pruneTags true
Nicholas Carey
fuente
Muy buena. Lo he adaptado para publicar en SOes -> ¿Cómo puedo eliminar las etiquetas de Git que solo tengo en local? .
Fedorqui 'así que deja de dañar'
¡Excelente! Conocí la falla de empuje de git con "git-shell murió de la señal 13". Ningún efecto, incluso con el aumento de http.postbuffer. Después de habilitar GIT_TRACE_PACKET y GIT_TRACE, vi presionar a referencias / etiquetas inválidas, así que usando "--prune-tags" lo resolvió. ¡Muchas gracias!
Ivellios
78

Todas las versiones de Git desde v1.7.8 se entienden git fetchcon una refspec, mientras que desde v1.9.0 la --tagsopción anula la --pruneopción. Para una solución de uso general, intente esto:

$ git --version
git version 2.1.3

$ git fetch --prune origin "+refs/tags/*:refs/tags/*"
From ssh://xxx
 x [deleted]         (none)     -> rel_test

Para obtener más información sobre cómo cambió el comportamiento "--tags" con "--prune" en Git v1.9.0, consulte: https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c

Chad Juliano
fuente
77
Esta debería ser la mejor respuesta. Es un solo comando git, sin bash, sin tuberías y sin xargs.
G. Sylvie Davies
1
Reemplazado origincon upstreamy git corrigió mis etiquetas locales basadas en el flujo ascendente; A continuación, git push origin :<deleted-tag-name>actualicé mi bifurcación de GitHub, eliminando la etiqueta eliminada.
leanne
3
Al menos con git 2.18.0 también se puede usar esta sintaxis:git fetch --prune --prune-tags origin
Martin
3
Comenzando con git 2.17.0 - la opción --prune-tags fue incluida y descrita en la sección PODA en detalle con comandos equivalentes en el siguiente documento: git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tags O git fetch origin --prune 'refs/tags/*:refs/tags/*' O git fetch <url of origin> --prune --prune-tags Ogit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs
8

Git admite de forma nativa la limpieza de etiquetas locales:

git fetch --tags --prune

Este comando extrae las últimas etiquetas y elimina todas las etiquetas eliminadas.

Nirav Shah
fuente
Parece que debería ser "--prune" en lugar de "--prune-tags", de lo contrario, eso es lo que necesitaba, gracias.
AnyDev
Tengo un problema en el árbol de origen que no pudo enviar algunas referencias a ...: Funciona para mí :) Muchas gracias
Abhishek Thapliyal
6

Este es un buen método:

git tag -l | xargs git tag -d && git fetch -t

Fuente: demisx.GitHub.io

imjoseangel
fuente
4

Muestre la diferencia entre etiquetas locales y remotas:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag da la lista de etiquetas locales
  • git ls-remote --tags da la lista de rutas completas a etiquetas remotas
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' analiza solo el nombre de la etiqueta de la lista de rutas de etiquetas remotas
  • Finalmente clasificamos cada una de las dos listas y las diferenciamos

Las líneas que comienzan con "<" son sus etiquetas locales que ya no están en el repositorio remoto. Si son pocos, puede eliminarlos manualmente uno por uno, si son muchos, hace más greping y tuberías para automatizarlo.

dotstaraj
fuente
2
Considere agregar alguna explicación a su código. Esto definitivamente mejoraría la calidad de su respuesta.
tocar la bocina el
El comando completo para eliminar todas las etiquetas remotas no presentes localmente sería:diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort) | grep ">" | cut -c3- | xargs -I{} git push origin :refs/tags/{}
Daniel Gehriger,
Si necesita hacer una diferencia y mostrar el hash de confirmación al mismo tiempo: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
piroux
Esta comparación fue exactamente lo que estaba buscando, gracias. Lo único que me confunde es que también genera un par de líneas que no comienzan con una flecha <, sino un número seguido de una coma y luego lo que parecen los primeros tres caracteres de un hash de confirmación (?), por ejemplo 7,8d4...
Kay
3

Acabo de agregar un comando git sync-local-tags a pivotal_git_scripts Gem fork en GitHub:

https://github.com/kigster/git_scripts

Instale la gema, luego ejecute "git sync-local-tags" en su repositorio para eliminar las etiquetas locales que no existen en el control remoto.

Alternativamente, puede instalar este script a continuación y llamarlo "git-sync-local-tags":


#!/usr/bin/env ruby

# Delete tags from the local Git repository, which are not found on 
# a remote origin
#
# Usage: git sync-local-tags [-n]
#        if -n is passed, just print the tag to be deleted, but do not 
#        actually delete it.
#
# Author: Konstantin Gredeskoul (http://tektastic.com)
#
#######################################################################

class TagSynchronizer
  def self.local_tags
    `git show-ref --tags | awk '{print $2}'`.split(/\n/)
  end

  def self.remote_tags
    `git ls-remote --tags origin | awk '{print $2}'`.split(/\n/)
  end

  def self.orphaned_tags
    self.local_tags - self.remote_tags
  end

  def self.remove_unused_tags(print_only = false)
    self.orphaned_tags.each do |ref|
      tag = ref.gsub /refs\/tags\//, ''
      puts "deleting local tag #{tag}"
      `git tag -d #{tag}` unless print_only
    end
  end
end

unless File.exists?(".git")
  puts "This doesn't look like a git repository."
  exit 1
end

print_only = ARGV.include?("-n")
TagSynchronizer.remove_unused_tags(print_only)
Konstantin Gredeskoul
fuente
3

Sé que llego tarde a la fiesta, pero ahora hay una respuesta rápida a esto:

git fetch --prune --prune-tags # or just git fetch -p -P

Sí, ahora es una opción para buscar.

Si no quieres buscar y simplemente podar:

git remote prune origin
bufón
fuente
1

¿Qué tal esto? ¿Descartar todas las etiquetas locales y luego volver a buscarlas? Teniendo en cuenta que su repositorio puede contener submódulos:

git submodule foreach --recursive  'git tag | xargs git tag -d'
(alternatively, "for i in `find .git  -type d -name '*tags*'`; do rm -f $i/*;  done")
git fetch -t
git submodule foreach --recursive git fetch -t
tetzu0
fuente
1

TortoiseGit puede comparar etiquetas ahora.

El registro izquierdo está en remoto, el derecho está en local.

ingrese la descripción de la imagen aquí

Usando la función Comparar etiquetas del cuadro de diálogo Sincronizar:

ingrese la descripción de la imagen aquí

Ver también el número 2973 de TortoiseGit

Yue Lin Ho
fuente
1

La misma respuesta que @Richard W pero para Windows (PowerShell)

git tag | foreach-object -process { git tag -d $_ }
git fetch -t
Danon
fuente
1

Agrego el comando a SourceTree como Acción personalizada en mi MacOS.


Configuración Custom Actionspor Sourcetree-> Preferences...->Custom Actions


Script to run tiene que ser el git camino.

Yo uso git fetch --prune --prune-tags originpara sincronizar etiquetas de remoto a local.

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

AechoLiu
fuente
0

En la nueva versión de git (como v2.26.2)

-P, --prune-tags Antes de buscar, elimine las etiquetas locales que ya no existan en el control remoto si --prune está habilitado. Esta opción debe usarse con más cuidado, a diferencia de --prune, eliminará las referencias locales (etiquetas locales) que se hayan creado. Esta opción es una abreviatura para proporcionar la etiqueta explícita refspec junto con --prune, vea la discusión sobre eso en su documentación.

Entonces necesitarías correr:

git fetch august --prune --prune-tags
Ela Dute
fuente