web-dev-qa-db-fra.com

Supprimer les balises git locales qui ne figurent plus dans le référentiel distant

Nous utilisons des tags dans git dans le cadre de notre processus de déploiement. De temps en temps, nous souhaitons 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 en un seul jeu de commandes. Nous avons un petit script Shell qui combine les deux étapes.

Le 2ème (3ème, 4ème, ...) utilisateur a maintenant des balises locales qui ne sont plus reflétées sur la télécommande.

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

Alternativement, une simple commande de liste des balises distantes pourrait être utilisée pour comparer les balises locales renvoyées via git tag -l.

414
kEND

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, tels que:

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 tags générés par cette liste avec ceux que vous avez localement. Jetez un coup d'œil à git show-ref --tags, qui génère les noms de balises sous la même forme que git ls-remote).


En passant, git show-ref a une option qui fait le contraire de ce que vous souhaitez. La commande suivante listerait toutes les balises de la branche distante que vous avez ne pas localement:

git ls-remote --tags Origin | git show-ref --tags --exclude-existing
64
Mike West

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

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

Ainsi, vous devez taper deux lignes dans l'ordre:

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

Celles-ci:

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

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

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

950
Richard W

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) à cause du commit 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 version 1.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 une expansion par caractère générique:

git fetch --Prune <remote> "+refs/tags/*:refs/tags/*"
228
loganfsmyth

Si vous ne voulez que les tags qui existent sur la télécommande, supprimez simplement tous vos tags locaux:

$ git tag -d $(git tag)

Et puis récupérez tous les tags distants:

$ git fetch --tags
145
newmangt

Toutes les versions de Git depuis la v1.7.8 comprennent git fetch avec un refspec, alors que depuis la v1.9.0, l'option --tags annule l'option --Prune. Pour une solution générale, 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

74
Chad Juliano

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 supprimer les tags lors de la récupération:

git config fetch.pruneTags true

Si vous souhaitez uniquement supprimer les balises lors de la récupération d'une télécommande spécifique, vous pouvez utiliser l'option remote.<remote>.pruneTags. Par exemple, pour toujours supprimer les balises lors de l'extraction de Origin mais pas d'autres télécommandes,

git config remote.Origin.pruneTags true
41
Nicholas Carey

Git supporte nativement le nettoyage des tags locaux:

git fetch --tags --Prune

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

7
Nirav Shah

c'est une bonne méthode:

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

Source: demisx.GitHub.io

7
imjoseangel

Montrer 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 tags locaux
  • git ls-remote --tags donne la liste des chemins complets vers les tags distants
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' analyse uniquement le nom de la liste dans la liste des chemins de balise distants
  • Enfin, nous trions chacune des deux listes et les diff

Les lignes commençant par "<" sont vos balises locales qui ne figurent 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 effectuez plus de recherches et de canalisations pour l'automatiser.

5
dotstaraj

Vient d'ajouter une commande git sync-local-tags à pivotal_git_scripts Gem fork 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.

Sinon, 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)
4

TortoiseGit peut comparer les tags maintenant.

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

enter image description here

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

enter image description here

Voir aussi TortoiseGit numéro 297

2
Yue Lin Ho

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

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

Que diriez-vous de cela: supprimez toutes les balises locales et effectuez une nouvelle extraction? Considérant que votre repo 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
tetzu0