删除不再在远程存储库上的本地git标记

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

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

第二个(第3个,第4个,……)用户现在拥有不再反映在远程上的本地标记。

我正在寻找一个类似于git remote prune origin的命令,用于清理已删除远程分支的本地跟踪分支。

或者,可以使用一个列出远程标记的简单命令来与通过git tag -l返回的本地标记进行比较。

226453 次浏览

好问题。我没有一个完整的答案…

也就是说,您可以通过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

刚刚在GitHub上的pivotal_git_scripts Gem fork中添加了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)

这是个好问题,我也一直在想同样的问题。

我不想写一个脚本,所以寻求一个不同的解决方案。关键是发现可以在本地删除标记,然后使用git fetch从远程服务器“取回”它。如果标签在远程上不存在,那么它将保持删除状态。

因此你需要按顺序输入两行:

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

这些:

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

  2. 从远程回收中获取所有活动标记。

这甚至在Windows上也很有效。

从Git v1.7.8到v1.8.5.6,你可以这样使用:

git fetch <remote> --prune --tags

更新

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

根据“Chad Juliano”的建议,对于v1.7.8以来的所有Git版本,您可以使用以下命令:

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

你可能需要用引号将标签部分括起来(例如在Windows上),以避免通配符展开:

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

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

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

如果你只想要那些存在于远程的标签,只需删除所有本地标签:

$ git tag -d $(git tag)

然后获取所有远程标签:

$ git fetch --tags

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

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和管道来自动化。

自v1.7.8以来的所有版本的Git都通过refspec理解git fetch,而自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

有关“——tags”和“——prune”行为在Git v1.9.0中如何改变的进一步阅读,请参阅:https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c

TortoiseGit现在可以比较标签了。

左边是远程日志,右边是本地日志。

enter image description here

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

enter image description here

参见TortoiseGit第2973期

这是一个很好的方法:

# EYZ0

来源:# EYZ0

Git本身支持清除本地标记

git fetch --tags --prune-tags

该命令提取最新的标记并删除所有已删除的标记

看起来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

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

git tag | ForEach-Object -Process { git tag -d $_ }
git fetch -t

更新@2021/05

enter image description here

$REPO参数传递给自定义脚本。

sync_git_tags.sh的内容

#!/bin/sh


# cd to $REPO directory
cd $1
pwd


# sync remote tags
git tag -l | xargs git tag -d && git fetch -t

ps:更新@2021/05,git fetch --prune --prune-tags origin在我的MacOS中无法工作。

我将命令添加到SourceTree作为我的MacOS上的自定义操作。
设置Custom Actions by Sourcetree -># EYZ2→# EYZ0 < / p >
' Script to run '必须是' git '路径。< br >

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

enter image description here # EYZ0 < / p >

我知道我迟到了,但现在有一个快速的答案:

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

是的,它现在是一个获取的选项。

如果你不想获取,只需修剪:

git remote prune origin

在新的git版本(如v2.26.2或更高版本)中,您可以使用--prune-tags

< p > # EYZ0 < br > # EYZ0 < br > 在获取之前,如果启用了--prune,则删除远程上不再存在的任何本地标记。这个选项应该更谨慎地使用,与--prune不同,它将删除已经创建的任何本地引用(本地标记)。该选项是提供显式标记refspec和--prune的简写,请参阅其文档中关于该选项的讨论

所以你需要运行:

git fetch origin --prune --prune-tags