Remova as tags git locais que não estão mais no repositório remoto


468

Usamos tags no git como parte de nosso processo de implantação. Periodicamente, queremos limpar essas tags removendo-as do nosso repositório remoto.

Isso é bem direto. Um usuário exclui a marca local e a marca remota em um conjunto de comandos. Temos um pequeno script de shell que combina as duas etapas.

O segundo (terceiro, quarto, ...) usuário agora tem tags locais que não são mais refletidas no controle remoto.

Estou procurando um comando semelhante ao git remote prune originqual limpa as ramificações de rastreamento local para as quais a ramificação remota foi excluída.

Como alternativa, um comando simples para listar tags remotas pode ser usado para comparar com as tags locais retornadas por git tag -l.


2
Propus um novo recurso no git para apoiar poda etiquetas obsoletos: thread.gmane.org/gmane.comp.version-control.git/168833
Adam Monsen

1
Nota: com o Git 2.17 (Q2 2018), um simples git config fetch.pruneTags truefará com git fetchque você faça o que deseja! Veja minha resposta a essa outra pergunta .
VonC 10/0318

2
Reposting um comentário de uma das respostas abaixo: Pelo menos com git 2.18.0 pode-se também usar esta sintaxe: git fetch --prune --prune-tags origem
zutnop

Respostas:


71

Boa pergunta. :) Eu não tenho uma resposta completa ...

Dito isto, você pode obter uma lista de tags remotas via git ls-remote. Para listar as tags no repositório referenciado por origin, você deve executar:

git ls-remote --tags origin

Isso retorna uma lista de hashes e nomes de tags amigáveis, como:

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

Você certamente poderia montar um script bash para comparar as tags geradas por esta lista com as que você possui localmente. Dê uma olhada git show-ref --tags, que gera os nomes das tags da mesma forma que git ls-remote).


Como um aparte, git show-reftem uma opção que faz o oposto do que você gostaria. O comando a seguir listaria todas as tags na ramificação remota que você não possui localmente:

git ls-remote --tags origin | git show-ref --tags --exclude-existing

Obrigado Mike. Vou rolar meu próprio script bash usando cada lista para comparação.
KEND

11
A resposta de Richard W faz isso de maneira muito mais elegante, caso você não esteja interessado em um script complicado.
Kyle Heironimus

1
A nota lateral sobre marcas não apresentam localmente pode ser expandida para verificar mais controles remotos:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec

Ver resposta seguinte para uma solução mais simples
sfletche

O git suporta --prune-tags. Incerto que versão foi introduzida. git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian 1/01/18

1054

Esta é uma ótima pergunta, eu estava pensando a mesma coisa.

Como não queria escrever um script, procurei uma solução diferente. A chave é descobrir que você pode excluir uma marca localmente e usar o git fetch para "recuperá-la" do servidor remoto. Se a tag não existir no controle remoto, ela permanecerá excluída.

Portanto, você precisa digitar duas linhas em ordem:

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

Estes:

  1. Exclua todas as tags do repositório local. FWIW, xargs coloca cada tag de saída por "tag -l" na linha de comando para "tag -d". Sem isso, o git não excluirá nada porque não lê stdin (git bobo).

  2. Busque todas as tags ativas no repositório remoto.

Isso funciona mesmo no Windows.


57
Essa deve ser minha resposta favorita do git no StackOverflow. Combina conhecimento, simplicidade e truques e explica tudo. Grande
tymtam

25
como observado em uma resposta em separado, isso exclui todos os tags locais, e aqueles que não estão no repo remoto, obviamente, não vai ser re-criado
segundo

13
FWIW, isso deve ser completamente desnecessário. Deve haver um git tag prune origincomando.
void.pointer

9
Isso pode não funcionar para todos. Você deve fazer git fetch --tags para estar do lado seguro.
Adam Kurkiewicz

5
Eu tive que ir git tag -l | %{git tag -d $_}para fazer isso funcionar no PowerShell. Não tenho certeza sobre mais ninguém.
Alain

244

Do Git v1.7.8 para v1.8.5.6, você pode usar isto:

git fetch <remote> --prune --tags

Atualizar

Isso não funciona nas versões mais recentes do git (começando na v1.9.0) devido ao commit e66ef7ae6f31f2 . Eu realmente não quero excluí-lo, já que funcionou para algumas pessoas.

Conforme sugerido por "Chad Juliano", com todas as versões do Git desde a v1.7.8, você pode usar o seguinte comando:

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

Pode ser necessário incluir a parte de tags entre aspas (no Windows, por exemplo) para evitar a expansão de caracteres curinga:

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

2
Refiro-me à documentação que acompanha o Git for Windows 1.9.4-preview20140611 (e suspeito que todas as versões anteriores). Acesso a documentação com "git fetch --help" [quote] As tags não estão sujeitas a remoção se forem buscadas apenas por causa do acompanhamento automático da tag padrão ou devido a uma opção --tags. [/
Quote

2
git fetch --prune <remote> +refs/tags/*:refs/tags/*não funcionou no ZSH no entanto, funciona em bash
Alex

3
@ Alex Isso é apenas porque o zsh se expande, *mas se você citar apenas isso deve ser bom.
NSF

3
@ v01pe - agora existe um atalho do git --prune-tags disponível desde o git 2.17.0 descrito na documentação na seção PRUNING : git-scm.com/docs/git-fetch/2.17.0 No documento: The - A opção -prune-tags é equivalente a ter refs / tags / *: refs / tags / * declarado nos refspecs do controle 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 20/09/18

3
git fetch origin --prune --prune-tagspodar ramificações e tags de rastreamento remoto. fez check-in na versão 2.18 do git.
Number945

158

Se você deseja apenas as tags existentes no controle remoto, basta excluir todas as tags locais:

$ git tag -d $(git tag)

E, em seguida, busque todas as tags remotas:

$ git fetch --tags

1
impecável, eu estava tendo problema com os xargs um não encontrar algumas tags
Marcio Toshio

3
@ocroquette, não tenho certeza de como é melhor xargs. Se você tiver mais tags ARG_MAXou limitações semelhantes, isso não funcionará. Improvável, mas possível, e é por isso que xargsé ótimo.
Paul Draper

2
"legal" é uma coisa subjetiva, todos farão sua própria opinião. Sobre ARG_MAX, isso é verdade. No entanto, nos sistemas que uso, o ARG_MAX é muito maior que o número de tags que tenho em qualquer repositório; portanto, não me importo com a limitação, assim como não me importo com isso quando escrevo "ls * .jpg" .
Ocroquette 26/08/2015

2
solução mais limpa
mitsest

2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'Comando de alias obrigatório. Aproveitar. :-)
Karl Wilbur

87

Parece que as versões recentes do Git (estou no git v2.20) permitem simplesmente dizer

git fetch --prune --prune-tags

Muito mais limpo!

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

Você também pode configurar o git para remover sempre as tags ao buscar:

git config fetch.pruneTags true

Se você desejar remover tags ao buscar em um controle remoto específico, poderá usar a remote.<remote>.pruneTagsopção Por exemplo, para sempre remover tags ao buscar na origem, mas não em outros controles remotos,

git config remote.origin.pruneTags true


Excelente! Eu encontrei a falha do git push com "git-shell morreu do sinal 13". Sem efeito, mesmo com o aumento do http.postbuffer. Depois de ativar GIT_TRACE_PACKET e GIT_TRACE, vi empurrando para refs / tags inválidas, portanto, usando "--prune-tags" resolvê-lo. Muito obrigado!
Ivellios 4/03

78

Todas as versões do Git desde a v1.7.8 são compreendidas git fetchcom um refspec, enquanto que desde a v1.9.0 a --tagsopção substitui a --pruneopção. Para uma solução de uso geral, tente o seguinte:

$ git --version
git version 2.1.3

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

Para ler mais sobre como o comportamento "--tags" com "--prune" mudou no Git v1.9.0, consulte: https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c


7
Essa deve ser a resposta principal. É um único comando git, sem bash, sem pipes e sem xargs.
G. Sylvie Davies

1
Substituído originpor upstreame git corrigi minhas tags locais com base no upstream; Em seguida, git push origin :<deleted-tag-name>atualizei meu fork do GitHub, removendo a tag excluída.
Anat

3
Pelo menos com git 2.18.0 pode-se também usar esta sintaxe:git fetch --prune --prune-tags origin
Martin

3
Começando com git 2.17.0 - a opção --prune-tags foi incluída e descrita na seção PRUNING em detalhes com comandos equivalentes no documento a seguir: git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tags OR git fetch origin --prune 'refs/tags/*:refs/tags/*' OR git fetch <url of origin> --prune --prune-tags ORgit fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
Mkisaacs

8

O Git suporta nativamente a limpeza de tags locais:

git fetch --tags --prune

Este comando extrai as tags mais recentes e remove todas as tags excluídas.


Parece que deveria ser "--une" em vez de "--uneune tags", caso contrário é isso que eu precisava, obrigado.
AnyDev

Estou tendo problema na árvore de origem não conseguiu empurrar alguns árbitros para ...: Funciona para mim :) Obrigado Alot
Abhishek Thapliyal


4

Mostre a diferença entre tags locais e remotas:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag fornece a lista de tags locais
  • git ls-remote --tags fornece a lista de caminhos completos para tags remotas
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' analisa apenas o nome da marca na lista de caminhos de marca remota
  • Finalmente, classificamos cada uma das duas listas e as diferenciamos

As linhas que começam com "<" são suas tags locais que não estão mais no repositório remoto. Se forem poucos, você poderá removê-los manualmente, um por um, se forem muitos, você fará mais grep-ing e tubulação para automatizá-lo.


2
Por favor, considere adicionar algumas explicações ao seu código. Isso melhoraria definitivamente a qualidade da sua resposta.
Honk

O comando completo para excluir todos os tags remotos que não estão presentes localmente seria: #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

Se você precisar fazer essa comparação e exibir o hash de confirmação ao mesmo tempo: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
piroux 15/03/19

Essa comparação foi exatamente o que eu estava procurando, obrigado. A única coisa que me deixa confuso é que ele também gera algumas linhas que não começam com uma seta <, mas um número seguido de uma vírgula e, em seguida, o que parece os três primeiros caracteres de um hash de confirmação (?), por exemplo 7,8d4...
Kay

3

Acabei de adicionar um comando git sync-local-tags ao pivotal_git_scripts fork do Gem no GitHub:

https://github.com/kigster/git_scripts

Instale a gema e execute "git sync-local-tags" em seu repositório para excluir as marcações locais que não existem no controle remoto.

Como alternativa, você pode instalar este script abaixo e chamá-lo de "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

Eu sei que estou atrasado para a festa, mas agora há uma resposta rápida para isso:

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

Sim, agora é uma opção para buscar.

Se você não deseja buscar e apenas poda:

git remote prune origin

1

Que tal isso - largue todas as tags locais e depois busque novamente? Considerando que seu repo pode conter 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

1

O TortoiseGit pode comparar tags agora.

O registro esquerdo está no controle remoto, o direito está no local.

insira a descrição da imagem aqui

Usando o recurso Tags de comparação da caixa de diálogo Sincronizar:

insira a descrição da imagem aqui

Veja também a edição 2973 do TortoiseGit


1

A mesma resposta que @Richard W, mas para Windows (PowerShell)

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

1

Eu adiciono o comando SourceTreecomo uma Ação personalizada no meu MacOS.


Definir Custom Actionspor Sourcetree-> Preferences...->Custom Actions


Script to runtem que ser o gitcaminho.

Eu uso git fetch --prune --prune-tags originpara sincronizar tags de remoto para local.

insira a descrição da imagem aqui insira a descrição da imagem aqui


0

Na nova versão do git (como v2.26.2)

-P, --prune-tags Antes de buscar, remova as tags locais que não existem mais no controle remoto se --prune estiver ativado. Esta opção deve ser usada com mais cuidado, ao contrário do --prune, ele removerá todas as referências locais (tags locais) que foram criadas. Esta opção é um atalho para fornecer a tag explsp refspec junto com --prune, consulte a discussão sobre isso em sua documentação.

Então você precisaria executar:

git fetch august --prune --prune-tags
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.