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.


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

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.


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/*"

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

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


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


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.


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


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.


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)

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

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

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


1

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

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

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


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.