Supprimer les balises git locales qui ne se trouvent plus sur le référentiel distant

469

Nous utilisons des balises dans git dans le cadre de notre processus de déploiement. De temps en temps, nous voulons nettoyer ces balises en les supprimant de notre référentiel distant.

C'est assez simple. Un utilisateur supprime la balise locale et la balise distante dans un ensemble de commandes. Nous avons un petit script shell qui combine les deux étapes.

Le 2e (3e, 4e, ...) utilisateur dispose désormais de balises locales qui ne sont plus reflétées sur la télécommande.

Je recherche une commande similaire à celle git remote prune originqui nettoie localement les branches de suivi pour lesquelles la branche distante a été supprimée.

Alternativement, une simple commande pour lister les balises distantes pourrait être utilisée pour comparer aux balises locales retournées via git tag -l.

kEND
la source
2
J'ai proposé une nouvelle fonctionnalité dans git pour prendre en charge l'élagage des balises périmées
Adam Monsen
1
Remarque: avec Git 2.17 (Q2 2018), un simple vous git config fetch.pruneTags truefera faire git fetchce que vous voulez! Voir ma réponse à cette autre question .
VonC
2
Republier un commentaire d'une des réponses ci-dessous: Au moins avec git 2.18.0 on peut aussi utiliser cette syntaxe: git fetch --prune --prune-tags origin
zutnop

Réponses:

71

Bonne question. :) Je n'ai pas de réponse complète ...

Cela dit, vous pouvez obtenir une liste de balises distantes via git ls-remote. Pour répertorier les balises dans le référentiel référencé par origin, vous devez exécuter:

git ls-remote --tags origin

Cela renvoie une liste de hachages et de noms de balises conviviales, comme:

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

Vous pouvez certainement créer un script bash pour comparer les balises générées par cette liste avec les balises que vous avez localement. Jetez un œil à git show-ref --tags, qui génère les noms de balises sous la même forme que git ls-remote).


En aparté, git show-refa une option qui fait le contraire de ce que vous aimeriez. La commande suivante répertorierait toutes les balises de la branche distante que vous n'avez pas localement:

git ls-remote --tags origin | git show-ref --tags --exclude-existing
Mike West
la source
Merci Mike. Je vais rouler mon propre script bash en utilisant chaque liste pour comparaison.
kEND
11
La réponse de Richard W le fait de manière beaucoup plus élégante, au cas où vous ne seriez pas intéressé par un script compliqué.
Kyle Heironimus
1
La note latérale sur les balises non présentes localement peut être développée pour vérifier plus de télécommandes:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec
Voir la réponse suivante pour une solution plus simple
sfletche
git prend en charge --prune-tags. Je ne sais pas quelle version cela a été introduit. git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian
1056

C'est une grande question, je me demandais la même chose.

Je ne voulais pas écrire de script alors j'ai cherché une solution différente. La clé est de découvrir que vous pouvez supprimer une balise localement, puis utiliser git fetch pour la "récupérer" à partir du serveur distant. Si la balise n'existe pas sur la télécommande, elle restera supprimée.

Vous devez donc taper deux lignes dans l'ordre:

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

Celles-ci:

  1. Supprimez toutes les balises du référentiel local. FWIW, xargs place chaque balise sortie par "tag -l" sur la ligne de commande pour "tag -d". Sans cela, git ne supprimera rien car il ne lit pas stdin (idiot git).

  2. Récupérez toutes les balises actives du référentiel distant.

Cela fonctionne même un régal sur Windows.

Richard W
la source
57
Ce doit être ma réponse préférée sur StackOverflow. Il allie savoir, simplicité et ruse et explique tout. Super
tymtam
25
comme indiqué dans une réponse séparée, cela supprime TOUTES les balises locales, et celles qui ne figurent pas dans le référentiel distant ne seront évidemment pas recréées
deuxième
13
FWIW cela devrait être complètement inutile. Il devrait y avoir une git tag prune origincommande.
void.pointer
9
Cela pourrait ne pas fonctionner pour tout le monde. Vous devriez faire git fetch --tags pour être du bon côté.
Adam Kurkiewicz
5
J'ai dû aller git tag -l | %{git tag -d $_}pour que cela fonctionne dans PowerShell. Je ne suis sûr de personne d'autre.
Alain
244

De Git v1.7.8 à v1.8.5.6, vous pouvez utiliser ceci:

git fetch <remote> --prune --tags

Mise à jour

Cela ne fonctionne pas sur les versions plus récentes de git (à partir de v1.9.0) en raison de la validation e66ef7ae6f31f2 . Je ne veux pas vraiment le supprimer car cela a fonctionné pour certaines personnes.

Comme suggéré par "Chad Juliano", avec toutes les versions de Git depuis la v1.7.8, vous pouvez utiliser la commande suivante:

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

Vous devrez peut-être entourer la partie balises de guillemets (sous Windows par exemple) pour éviter l'expansion des caractères génériques:

git fetch --prune <remote> "+refs/tags/*:refs/tags/*"
loganfsmyth
la source
2
Je me réfère à la documentation fournie avec Git pour Windows 1.9.4-preview20140611 (et je soupçonne toutes les versions précédentes). J'accède à ladite documentation avec "git fetch --help" [quote] Les tags ne sont pas soumis à l'élagage s'ils sont récupérés uniquement en raison du suivi automatique des tags par défaut ou en raison d'une option --tags. [/ Quote]
Félix Cantournet
2
git fetch --prune <remote> +refs/tags/*:refs/tags/*n'a pas fonctionné en ZSH mais cela fonctionne en BASH
Alex
3
@Alex C'est juste parce que zsh se développe, *mais si vous citez simplement que cela devrait aller.
NSF
3
@ v01pe - il y a maintenant un raccourci git --prune-tags disponible depuis git 2.17.0 décrit dans la documentation sous la section PRUNING : git-scm.com/docs/git-fetch/2.17.0 Du document: Le - L'option -prune-tags équivaut à avoir refs / tags / *: refs / tags / * déclarés dans les refspecs de la télécommande. Équivalents: git fetch origin --prune --prune-tagsOU git fetch origin --prune 'refs/tags/*:refs/tags/*'OU git fetch <url of origin> --prune --prune-tagsOUgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs
3
git fetch origin --prune --prune-tagstailler les branches et les balises de suivi à distance. vérifié dans la version git 2.18.
Number945
158

Si vous souhaitez uniquement les balises qui existent sur la télécommande, supprimez simplement toutes vos balises locales:

$ git tag -d $(git tag)

Et puis récupérez toutes les balises distantes:

$ git fetch --tags
newmangt
la source
1
impeccable, j'avais un problème avec le xargs il ne trouve pas de tags
Marcio Toshio
3
@ocroquette, je ne sais pas comment c'est plus agréable que xargs. Si vous avez plus de balises ARG_MAXou des limitations similaires, cela ne fonctionnera pas. Peu probable, mais possible, et c'est pourquoi xargsc'est génial.
Paul Draper
2
"gentil" est une chose subjective, chacun se fera sa propre opinion. À propos d'ARG_MAX, c'est vrai. Cependant, sur les systèmes que j'utilise, ARG_MAX est beaucoup plus élevé que le nombre de balises que j'ai dans n'importe quel référentiel, donc cela ne me dérange pas la limitation, tout comme cela ne me dérange pas lorsque j'écris "ls * .jpg" .
ocroquette
2
solution la plus propre
mitsest
2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'Commande d'alias obligatoire. Prendre plaisir. :-)
Karl Wilbur
87

On dirait que les versions récentes de Git (je suis sur git v2.20) permettent de dire simplement

git fetch --prune --prune-tags

Beaucoup plus propre!

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

Vous pouvez également configurer git pour toujours tailler les balises lors de la récupération:

git config fetch.pruneTags true

Si vous souhaitez uniquement élaguer les balises lors de la récupération à partir d'une télécommande spécifique, vous pouvez utiliser l' remote.<remote>.pruneTagsoption. Par exemple, pour toujours tailler les balises lors de la récupération à partir de l'origine mais pas d'autres télécommandes,

git config remote.origin.pruneTags true
Nicholas Carey
la source
Elle est bonne. Je l'ai adapté pour poster sur SOes -> ¿Cómo puedo éliminar las etiquetas de Git que solo tengo en local? .
fedorqui 'SO arrête de nuire'
Excellent! J'ai rencontré un échec de git push avec "git-shell est mort du signal 13". Aucun effet même avec l'augmentation de http.postbuffer. Après avoir activé GIT_TRACE_PACKET et GIT_TRACE, j'ai vu pousser vers des références / balises invalides, donc l'utilisation de "--prune-tags" le résout. Merci beaucoup!
Ivellios
78

Toutes les versions de Git depuis la v1.7.8 comprennent git fetchavec une refspec, alors que depuis la v1.9.0, l' --tagsoption remplace l' --pruneoption. Pour une solution à usage général, essayez ceci:

$ git --version
git version 2.1.3

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

Pour plus d'informations sur la façon dont le comportement "--tags" avec "--prune" a changé dans Git v1.9.0, voir: https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c

Chad Juliano
la source
7
Cela devrait être la meilleure réponse. C'est une seule commande git, sans bash, sans pipe et sans xargs.
G. Sylvie Davies
1
Remplacé originpar upstreamet git corrigé mes balises locales basées sur l'amont; ensuite git push origin :<deleted-tag-name>mis à jour mon fork GitHub, en supprimant la balise supprimée.
leanne
3
Au moins avec git 2.18.0 on peut aussi utiliser cette syntaxe:git fetch --prune --prune-tags origin
Martin
3
À partir de git 2.17.0 - l'option --prune-tags a été incluse et décrite en détail dans la section ÉLAGAGE avec des commandes équivalentes dans le document suivant: git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tags OU git fetch origin --prune 'refs/tags/*:refs/tags/*' OU git fetch <url of origin> --prune --prune-tags OUgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs
8

Git prend en charge nativement le nettoyage des balises locales:

git fetch --tags --prune

Cette commande extrait les dernières balises et supprime toutes les balises supprimées.

Nirav Shah
la source
Il semble que ce devrait être "--prune" au lieu de "--prune-tags", sinon c'est ce dont j'avais besoin, merci.
AnyDev
J'ai un problème dans l'arborescence source qui n'a pas réussi à pousser certaines références vers ...: Cela fonctionne pour moi :) Merci beaucoup
Abhishek Thapliyal
6

c'est une bonne méthode:

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

Source: demisx.GitHub.io

imjoseangel
la source
4

Affichez la différence entre les balises locales et distantes:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag donne la liste des balises locales
  • git ls-remote --tags donne la liste des chemins complets vers les balises distantes
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' analyse uniquement le nom de la balise de la liste des chemins de balises distants
  • Enfin, nous trions chacune des deux listes et les diff

Les lignes commençant par "<" sont vos balises locales qui ne sont plus dans le référentiel distant. S'ils sont peu nombreux, vous pouvez les supprimer manuellement un par un, s'ils sont nombreux, vous faites plus de greping et de piping pour l'automatiser.

dotstaraj
la source
2
Veuillez envisager d'ajouter des explications à votre code. Cela améliorerait définitivement la qualité de votre réponse.
klaxonner
La commande complète pour supprimer toutes les balises distantes non présentes localement serait alors: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 vous devez faire un tel diff et afficher le hachage de validation en même temps: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
piroux
Cette comparaison était exactement ce que je cherchais, merci. La seule chose qui me dérange, c'est qu'il génère également quelques lignes qui ne commencent pas par une flèche <, mais un nombre suivi d'une virgule, puis à quoi ressemblent les trois premiers caractères d'un hachage de validation (?), par exemple 7,8d4...
Kay
3

Nous venons d'ajouter une commande git sync-local-tags à fork fork pivotal_git_scripts Gem sur GitHub:

https://github.com/kigster/git_scripts

Installez la gemme, puis exécutez "git sync-local-tags" dans votre référentiel pour supprimer les balises locales qui n'existent pas sur la télécommande.

Alternativement, vous pouvez simplement installer ce script ci-dessous et l'appeler "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
la source
3

Je sais que je suis en retard à la fête, mais maintenant il y a une réponse rapide à cela:

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

Oui, c'est maintenant une option à récupérer.

Si vous ne voulez pas aller chercher et juste tailler:

git remote prune origin
joker
la source
1

Que diriez-vous de cela - supprimez toutes les balises locales, puis récupérez à nouveau? Considérant que votre dépôt peut contenir des sous-modules:

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
la source
1

TortoiseGit peut comparer les balises maintenant.

Le journal de gauche est sur la télécommande, la droite est au niveau local.

entrez la description de l'image ici

Utilisation de la fonction Comparer les balises de la boîte de dialogue Synchroniser:

entrez la description de l'image ici

Voir également le numéro 2973 de TortoiseGit

Yue Lin Ho
la source
1

La même réponse que @Richard W mais pour Windows (PowerShell)

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

J'ajoute la commande en SourceTreetant qu'action personnalisée sur mon MacOS.


Réglage Custom Actionspar Sourcetree-> Preferences...->Custom Actions


Script to rundoivent être le gitchemin.

J'utilise git fetch --prune --prune-tags originpour synchroniser les balises de distance à locale.

entrez la description de l'image ici entrez la description de l'image ici

AechoLiu
la source
0

Dans la nouvelle version git (comme v2.26.2)

-P, --prune-tags Avant de récupérer, supprimez toutes les balises locales qui n'existent plus sur la télécommande si --prune est activé. Cette option doit être utilisée avec plus de prudence, contrairement à --prune, elle supprimera toutes les références locales (balises locales) qui ont été créées. Cette option est un raccourci pour fournir la balise explicite refspec avec --prune, voir la discussion à ce sujet dans sa documentation.

Il vous faudrait donc exécuter:

git fetch august --prune --prune-tags
Ela Dute
la source