【问题标题】:Remove local git tags that are no longer on the remote repository删除不再在远程存储库上的本地 git 标签
【发布时间】:2010-12-22 22:00:47
【问题描述】:

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

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

第二个(第三个、第四个、...)用户现在具有不再反映在远程上的本地标签。

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

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

【问题讨论】:

  • 我在 git 中提出了一个新特性来支持修剪过时的标签:thread.gmane.org/gmane.comp.version-control.git/168833
  • 注意:使用 Git 2.17(2018 年第二季度),一个简单的 git config fetch.pruneTags true 将使您的 git fetch 做您想做的事!见my answer to this other question
  • 从以下答案之一重新发布评论:至少在 git 2.18.0 中也可以使用以下语法:git fetch --prune --prune-tags origin
  • 感谢@zutnop 的评论。对于今天的 git 版本,我几乎会错过正确答案。

标签: git git-tag


【解决方案1】:

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

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

所以你需要运行:

git fetch origin --prune --prune-tags

【讨论】:

    【解决方案2】:

    更新@2021/05

    $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 上的自定义操作。
    通过Sourcetree 设置Custom Actions -> Preferences... -> Custom Actions


    `Script to run` 必须是 `git` 路径。

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

    【讨论】:

    • 谢谢! git tag -l | xargs git tag -d && git fetch -t 工作。
    【解决方案3】:

    Git 原生支持清理本地标签

    git fetch --tags --prune-tags
    

    此命令拉入最新标签并删除所有已删除标签

    【讨论】:

    • 看来应该是“--prune”而不是“--prune-tags”,否则就是我需要的,谢谢。
    • 我在源代码树中遇到问题,无法将一些引用推送到...:它对我有用 :) 非常感谢
    • @AnyDev: --prune-tags 是正确的。手册页中提到了 --prune: Tags are not subject to pruning if they are fetched only because of the default tag auto-following or due to a --tags option.
    • 这将删除“任何不再存在于远程如果启用--prune的本地标签。所以应该是git fetch --tags --prune --prune-tags。这也会修剪其他参考,但 AFAIK 没有办法只修剪标签。无论如何,这个答案中的命令对我不起作用。 (git 版本 2.32.0)
    【解决方案4】:

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

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

    是的,现在可以选择获取。

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

    git remote prune origin
    

    【讨论】:

      【解决方案5】:

      看起来最近版本的 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
      

      【讨论】:

      • 伟大的。我已将其改编为在 SOes 上发布 -> ¿Cómo puedo eliminar las etiquetas de Git que solo tengo en local?.
      • 太棒了!我遇到了 git push 失败,“git-shell 死于信号 13”。即使增加了 http.postbuffer 也没有效果。启用 GIT_TRACE_PACKET 和 GIT_TRACE 后,我看到推送到无效的引用/标签,因此使用“--prune-tags”解决它。非常感谢!
      • 可以写成git fetch -pP
      • 这正是最方便的方式。
      【解决方案6】:

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

      $ git tag -d $(git tag)
      

      然后获取所有远程标签:

      $ git fetch --tags
      

      【讨论】:

      • @ocroquette,我不确定它比xargs 好多少。如果您有比ARG_MAX 更多的标签或类似的限制,这将不起作用。不太可能,但可能,这就是 xargs 很棒的原因。
      • “nice”是主观的东西,每个人都会有自己的看法。关于 ARG_MAX,确实如此。但是,在我使用的系统上,ARG_MAX 远高于我在任何存储库中拥有的标签数量,所以我不介意限制,就像我在写“ls *.jpg”时不介意一样.
      • git config --global alias.prune-tags '!git tag -d $(git tag) && git fetch --tags' 强制别名命令。享受。 :-)
      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

        这是个好方法:

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

        来源:demisx.GitHub.io

        【讨论】:

          【解决方案9】:

          自 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
          

          如需进一步了解 Git v1.9.0 中“--tags”和“--prune”行为的变化,请参阅:https://github.com/git/git/commit/e66ef7ae6f31f246dead62f574cc2acb75fd001c

          【讨论】:

          • upstream替换了origin,git根据上游更正了我的本地标签;下一个 git push origin :<deleted-tag-name> 更新了我的 GitHub 分支,删除了已删除的标签。
          • 至少 git 2.18.0 也可以使用这种语法:git fetch --prune --prune-tags origin
          • 从 git 2.17.0 开始 - --prune-tags 选项已包含在 PRUNING 部分中,并在以下文档中使用等效命令进行了详细描述:git-scm.com/docs/git-fetch/2.17.0 git fetch origin --prune --prune-tagsgit 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/*'
          【解决方案10】:

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

          【讨论】:

          • 我指的是随 Git for Windows 1.9.4-preview20140611 打包的文档(我怀疑所有以前的版本)。我使用“git fetch --help”访问所述文档 [quote]如果仅因为默认标签自动跟踪或由于 --tags 选项而获取标签,则不会对其进行修剪。[/quote]
          • git fetch --prune &lt;remote&gt; +refs/tags/*:refs/tags/* 在 ZSH 中不起作用,但在 BASH 中起作用
          • @Alex 这只是因为 zsh 扩展了 * 但如果你单引号应该没问题。
          • @v01pe - 现在有一个 git 快捷方式 --prune-tags 自 git 2.17.0 起可用,在 PRUNING 部分下的文档中描述:git-scm.com/docs/git-fetch/2.17.0 来自文档:--prune-tags选项等效于在遥控器的 refspecs 中声明 refs/tags/*:refs/tags/*。等效项:git fetch origin --prune --prune-tagsgit fetch origin --prune 'refs/tags/*:refs/tags/*'git fetch &lt;url of origin&gt; --prune --prune-tagsgit fetch &lt;url of origin&gt; --prune 'refs/tags/*:refs/tags/*'
          • git fetch origin --prune --prune-tags 修剪远程跟踪分支和标签。签入 git 2.18 版本。
          【解决方案11】:

          TortoiseGit 现在可以比较标签了。

          左日志在远程,右日志在本地。

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

          另见TortoiseGit issue 2973

          【讨论】:

            【解决方案12】:

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

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

            因此您需要按顺序键入两行:

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

            这些:

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

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

            这甚至适用于 Windows。

            【讨论】:

            • 如单独答案中所述,这会删除所有本地标签,并且显然不会重新创建不在远程仓库中的标签
            • 第一个命令是否需要xargs 扩展名或其他什么?我在 windows cmd 中执行该命令时得到这个:'xargs' is not recognized as an internal or external command, operable program or batch file.
            • FWIW 这应该是完全没有必要的。应该有一个git tag prune origin 命令。
            • 这可能并不适合所有人。为了安全起见,您应该执行 git fetch --tags。
            • 我必须去 git tag -l | %{git tag -d $_} 才能在 PowerShell 中使用它。不知道其他人。
            【解决方案13】:

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

            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/##' 仅从远程标签路径列表中解析出标签名称
            • 最后我们对两个列表中的每一个进行排序并区分它们

            以“

            【讨论】:

            • 请考虑为您的代码添加一些解释。这绝对会提高您的回答质量。
            • 删除所有本地不存在的远程标签的完整命令是:diff &lt;(git tag | sort) &lt;( git ls-remote --tags origin | cut -f2 | grep -v '\^' | sed 's#refs/tags/##' | sort) | grep "&gt;" | cut -c3- | xargs -I{} git push origin :refs/tags/{}
            • 如果你需要做这样的 diff 并同时显示提交哈希:diff &lt;(git show-ref --tags | grep -v '{}' | awk '{print $1 " " $2}') &lt;(git ls-remote --tags origin | grep -v '{}' | awk '{print $1 " " $2}')
            • 这个比较正是我想要的,谢谢。我唯一感到困惑的是,它还输出了几行不以箭头&lt; 开头的行,而是一个数字后跟一个逗号,然后看起来像提交哈希的前三个字符( ?),例如7,8d4...
            【解决方案14】:

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

            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
            

            【讨论】:

              【解决方案15】:

              刚刚在 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)
              

              【讨论】:

                【解决方案16】:

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

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

                【讨论】:

                • Richard W 的回答更加优雅,以防您对复杂的脚本不感兴趣。
                • 关于本地不存在的标签的旁注可以扩展以检查更多遥控器:git remote | xargs -L 1 git ls-remote --tags | git show-ref --tags --exclude-existing
                • git 支持 --prune-tags。不确定这是引入了什么版本。 git-scm.com/docs/git-fetch#git-fetch---prune-tags
                猜你喜欢
                • 2012-11-28
                • 2018-10-21
                • 1970-01-01
                • 2016-04-24
                • 2013-11-17
                • 1970-01-01
                • 2011-09-03
                • 2013-05-11
                • 1970-01-01
                相关资源
                最近更新 更多