删除不再在远程存储库中的本地git标签


468

在部署过程中,我们在git中使用标签。我们不时希望通过从远程存储库中删除它们来清理这些标记。

这很简单。一个用户在一组命令中删除本地标签和远程标签。我们有一个结合了两个步骤的小shell脚本。

现在,第二(第三,第四,...)用户具有不再反映在遥控器上的本地标签。

我正在寻找与git remote prune origin清除本地跟踪分支(已删除远程分支)的命令类似的命令。

或者,可以使用列出远程标签的简单命令与通过传回的本地标签进行比较git tag -l


2
我在git中提出了一项新功能,以支持修剪陈旧标签:thread.gmane.org/gmane.comp.version-control.git/168833
Adam Monsen

1
注意:使用Git 2.17(2018年第二季度),简单的操作git config fetch.pruneTags true就能使您git fetch做自己想做的事情!请参阅我对另一个问题的回答
VonC

2
从以下答案之一重新发布评论:至少使用git 2.18.0时,也可以使用以下语法:git fetch --prune --prune-tags origin
zutnop

Answers:


71

好问题。:)我没有完整的答案...

也就是说,您可以通过获得远程标签列表git ls-remote。要列出所引用的存储库中的标签origin,请运行:

git ls-remote --tags origin

这将返回哈希和友好标记名称的列表,例如:

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

当然,您可以将bash脚本放在一起,以比较此列表生成的标签与本地标签。看一下git show-ref --tags,它会生成与相同格式的标记名称git ls-remote


顺便说一句,git show-ref有一个选项与您想要的相反。以下命令将列出您在本地没有的远程分支上的所有标签:

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

谢谢迈克。我将使用每个列表滚动我自己的bash脚本进行比较。
kEND

11
如果您对复杂的脚本不感兴趣,Richard W的答案会做得更加优雅。
凯尔·赫罗尼穆斯

1
可以扩展有关本地不存在的标签的附带说明,以检查更多的遥控器:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
Palec 2014年

查看下一个更简单的解决方案的答案
sfletche '18

git支持--prune-tags。不确定引入的版本。 git-scm.com/docs/git-fetch#git-fetch---prune-tags
John Kloian

1052

这是一个很好的问题,我一直想知道同样的事情。

我不想编写脚本,因此寻求其他解决方案。关键是发现您可以在本地删除标签,然后使用git fetch从远程服务器“取回”它。如果该标签在遥控器上不存在,则它将保持删除状态。

因此,您需要依次键入两行:

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

这些:

  1. 从本地存储库中删除所有标签。FWIW,xargs将“ tag -l”输出的每个标签放置到“ tag -d”的命令行上。没有这个,git不会删除任何东西,因为它不会读取stdin(愚蠢的git)。

  2. 从远程仓库中获取所有活动标签。

这甚至可以在Windows上使用。


57
这必须是我在StackOverflow上最喜欢的git答案。它结合了知识,简单性和欺骗性,可以解释所有内容。大
tymtam

25
如在单独的答案中所述,这将删除所有本地标记,并且显然不会重新创建不在远程存储库中的那些标记
第二天

13
FWIW这应该完全没有必要。应该有一个git tag prune origin命令。
void.pointer 2014年

9
这可能并不适合所有人。为了安全起见,您应该执行git fetch --tags。
亚当·库基维奇

5
我必须去git tag -l | %{git tag -d $_}使它在PowerShell中工作。不确定其他人。
Alain

244

从Git v1.7.8到v1.8.5.6,您可以使用以下命令:

git fetch <remote> --prune --tags

更新资料

由于提交e66ef7ae6f31f2,这在较新版本的git(从v1.9.0开始)上不起作用。我真的不想删除它,因为它确实对某些人有用。

正如“ Chad Juliano”建议的那样,从v1.7.8开始,所有Git版本都可以使用以下命令:

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

您可能需要在标签部分加上引号(例如在Windows上),以避免通配符扩展:

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

2
我指的是Git Windows 1.9.4-preview20140611随附的文档(我怀疑所有以前的版本)。我访问表示,与“混帐提取--help”的文件[报价]标签不受如果他们是牵强只有默认的标签,因为自动以下或因--tags选项修剪了[/ quote]
费利克斯Cantournet

2
git fetch --prune <remote> +refs/tags/*:refs/tags/*在ZSH中不起作用,但在BASH中起作用
Alex

3
@Alex那只是因为zsh会扩展,*但是如果您单引号应该没问题。
NSF

3
@ v01pe-自从在PRUNING部分下的文档中介绍了git 2.17.0之后,现在有了git快捷方式--prune-tags:git-scm.com/docs/git-fetch/2.17.0 来自文档:- -prune-tags选项等效于在遥控器的refspec中声明refs / tags / *:refs / tags / *。等效项: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-tags修剪远程跟踪分支和标签。在git 2.18版本中签入。
Number945

158

如果只希望遥控器上存在的那些标签,只需删除所有本地标签:

$ git tag -d $(git tag)

然后获取所有远程标记:

$ git fetch --tags

1
完美无缺,我在xargs上遇到了麻烦,因为它找不到一些标签
Marcio Toshio

3
@ocroquette,我不确定它的效果如何xargs。如果您的标签数量超过ARG_MAX,或存在类似的限制,则此方法将无效。不太可能,但是可能,这xargs就是很棒的原因。
Paul Draper

2
“好”是一个主观的东西,每个人都会发表自己的看法。关于ARG_MAX,是的。但是,在我使用的系统上,ARG_MAX比我在任何存储库中拥有的标记数高得多,所以我不介意限制,就像我在写“ ls * .jpg”时不介意的那样。
ocroquette

2
最干净的解决方案
敏锐的

2
git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags'强制别名命令。请享用。:-)
Karl Wilbur '18

87

看起来像最新版本的Git(我在git v2.20上)可以简单地说

git fetch --prune --prune-tags

干净得多!

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

您还可以将git配置为在提取时始终修剪标签:

git config fetch.pruneTags true

如果您只想在从特定遥控器中获取标签时修剪标签,则可以使用该remote.<remote>.pruneTags选项。例如,要在从来源而不是其他远程获取时始终修剪标签,

git config remote.origin.pruneTags true


优秀的!我遇到了git push failure和“ git-shell因信号13死亡”的情况。即使增加了http.postbuffer也没有效果。启用GIT_TRACE_PACKET和GIT_TRACE之后,我看到推送到无效的引用/标签,因此使用“ --prune-tags”可以解决该问题。非常感谢!
Ivellios

78

git fetch自v1.7.8 以来的所有版本的Git都具有refspec,而自v1.9.0起,该--tags选项将覆盖该--prune选项。对于通用解决方案,请尝试以下操作:

$ git --version
git version 2.1.3

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

有关Git v1.9.0中具有“ --prune”行为的“ --tags”如何变化的更多信息,请参见:https : //github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c


7
这应该是最佳答案。这是一个git命令,没有bash,没有管道和xargs。
G.西尔维·戴维斯

1
替换originupstreamgit并根据上游纠正了我的本地标签;接下来git push origin :<deleted-tag-name>更新了我的GitHub fork,删除了已删除的标签。
leanne

3
至少使用git 2.18.0时,也可以使用以下语法:git fetch --prune --prune-tags origin
Martin

3
从git 2.17.0开始-在以下文档的PRUNING 部分中使用等效命令详细介绍了--prune-tags选项: git-scm.com/docs/git-fetch/2.17.0git fetch origin --prune --prune-tags OR git fetch origin --prune 'refs/tags/*:refs/tags/*' git fetch <url of origin> --prune --prune-tags 或或git fetch <url of origin> --prune 'refs/tags/*:refs/tags/*'
mkisaacs 18/09/20

8

Git本机支持清除本地标签:

git fetch --tags --prune

该命令提取最新的标签,并删除所有已删除的标签。


似乎应该是“ --prune”而不是“ --prune-tags”,否则,这就是我需要的,谢谢。
AnyDev

我在源代码树中遇到了问题,未能将一些参考推送到...:它对我有用:)谢谢Alot
Abhishek Thapliyal,


4

显示本地和远程标签之间的区别:

diff <(git tag | sort) <( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort)
  • git tag 给出本地标签列表
  • git ls-remote --tags 给出远程标签的完整路径列表
  • cut -f2 | grep -v '\^' | sed 's#refs/tags/##' 从远程标记路径列表中仅解析标记名称
  • 最后,我们对两个列表中的每个列表进行排序并进行比较

以“ <”开头的行是您的本地标签,不再位于远程仓库中。如果数量很少,则可以逐个手动将其删除;如果数量很多,则可以进行更多grep-ing和管道化操作以使其自动化。


2
请考虑在代码中添加一些说明。这将最终改善您的答案的质量。
2014年

删除所有本地不存在的远程标签的完整命令如下: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

如果您需要进行这样的比较并同时显示提交哈希: diff <(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') <(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
piroux

正是我所要的比较,谢谢。我唯一感到困惑的是,它还输出了几行,它们不是以箭头开头<,而是以数字开头,后跟逗号,然后看起来像是提交哈希(?)的前三个字符,例如7,8d4...

3

刚刚在GitHub上的axisal_git_scripts Gem分支中添加了git sync-local-tags命令:

https://github.com/kigster/git_scripts

安装gem,然后在您的存储库中运行“ git sync-local-tags”以删除远程服务器上不存在的本地标签。

或者,您可以仅在下面安装此脚本,并将其称为“ 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

我知道我参加晚会很晚,但是现在有一个快速的答案:

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

是的,现在可以提取。

如果您不想获取,只修剪:

git remote prune origin

1

怎么样-删除所有本地标签,然后重新获取?考虑到您的回购可能包含子模块:

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现在可以比较标签。

左日志位于远程,右日志位于本地。

在此处输入图片说明

使用“同步”对话框的“比较标签”功能:

在此处输入图片说明

另请参阅TortoiseGit问题2973


1

与@Richard W相同的答案,但适用于Windows(PowerShell)

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

1

SourceTree在MacOS上将命令添加为“自定义操作”。


设置Custom Actions通过Sourcetree- > Preferences...- >Custom Actions


Script to run必须成为git道路。

我用来git fetch --prune --prune-tags origin将标签从远程同步到本地。

在此处输入图片说明 在此处输入图片说明


0

在新的git版本中(例如v2.26.2)

-P,--prune-tags在获取之前,如果启用了--prune,请删除远程服务器上不再存在的所有本地标记。与--prune不同,应更谨慎地使用此选项,它将删除已创建的所有本地引用(本地标签)。该选项是提供显式标签refspec和--prune的简写,请参阅其文档中的讨论。

因此,您需要运行:

git fetch august --prune --prune-tags
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.