在Git中,我如何将我的标签与远程服务器同步?

91

有没有一种方法可以让本地git标签与远程的标签保持同步? 也就是说,不仅在创建新标签时(通常在fetch/pull)获取新标签,而且还能够清除不再存在于远程的标签,并在其他人使用git push -f推送标签时删除现有标签。 我知道我可以通过git fetch remotenamegit remote prune remotename来实现类似分支的行为。


看起来有点像https://dev59.com/cXI-5IYBdhLWcg3weoFO。 - VonC
2
注意:使用Git 2.17(2018年第二季度),只需简单地运行git config fetch.pruneTags true,就可以使您的git fetch达到您想要的效果!请参见下面的答案 - VonC
8个回答

94

...还可以修剪不再存在于远程的标签

git fetch在Git 2.17(2018年第二季度)中提供了一个方便的简写,用于清除本地保留的陈旧标签。

请参见commit 6317972, commit 97716d2, commit e249ce0, commit 627a129, commit d0e0747, commit 2c72ed7, commit e1790f9, commit 59caf52, commit 82f34e0, commit 6fb23f5, commit ca3065e, commit bf16ab7, commit eca142d, commit 750d0da, commit 0711883, commit ce3ab21, commit aa59e0e (2018年2月9日)由Ævar Arnfjörð Bjarmason (avar)提交。
(由Junio C Hamano -- gitster --commit c1a7902合并,2018年3月6日)

fetch: 添加--prune-tags选项和fetch.pruneTags配置

Add a --prune-tags option to git-fetch, along with fetch.pruneTags config option and a -P shorthand (-p is --prune).
This allows for doing any of:

git fetch -p -P
git fetch --prune --prune-tags
git fetch -p -P origin
git fetch --prune --prune-tags origin

Or simply:

git config fetch.prune true &&
git config fetch.pruneTags true &&
git fetch

Instead of the much more verbose:

git fetch --prune origin 'refs/tags/*:refs/tags/*' '+refs/heads/*:refs/remotes/origin/*'

Before this feature it was painful to support the use-case of pulling from a repo which is having both its branches and tags deleted regularly, and have our local references to reflect upstream.

At work we create deployment tags in the repo for each rollout, and there's lots of those, so they're archived within weeks for performance reasons.

Without this change it's hard to centrally configure such repos in /etc/gitconfig (on servers that are only used for working with them). You need to set fetch.prune=true globally, and then for each repo:

git -C {} config --replace-all remote.origin.fetch "refs/tags/*:refs/tags/*" "^\+*refs/tags/\*:refs/tags/\*$"

Now I can simply set fetch.pruneTags=true in /etc/gitconfig as well, and users running "git pull" will automatically get the pruning semantics I want.


2021年4月更新,Git for Windows 2.30.1和GitHub Desktop 2.8

如果您设置了prune pruneTags选项,则它可以正常工作:

cd C:\path\to\local\repo
git config fetch.prune true
git config fetch.pruneTags true

然后在 GitHub Desktop 中点击 Fetch origin:日志将显示:

2021-04-28T20:25:21.244Z - info: [ui] Executing fetch: 
  git -c credential.helper= -c protocol.version=2 fetch --progress --prune origin (took 2.986s)

...并且任何本地标签在远程不存在的都将被删除!


4
让我印象深刻!自从我最初提出问题以来,这是多年来的一个了不起的跟进。 - mlb
1
@realtebo 嗯... 非冗长形式只在上周发布的2.17中实现了 ;) https://github.com/git-for-windows/git/releases/tag/v2.17.0.windows.1 - VonC
所有的方法都没起作用(2.28,Windows)。没有出现任何错误,但是无法删除远程不存在的标签。只有这个方法有效 - Jason C
@JasonC 好的,奇怪。在我的存储库上它可以正常工作。 - VonC
1
@JasonC 确实如此。我将更新我的GitHub桌面版到最新版本(2.8: https://github.blog/changelog/2021-04-28-github-desktop-2-8-includes-expanding-diffs-hiding-whitespace-and-repository-aliases/)并进行测试。 - VonC
显示剩余7条评论

49
以下方法对我有效:
git fetch --prune --tags

1
这正是我所需要的。在我看来,比被接受的答案更加简单明了。 - Joe
如果你不加上 --tags,分支也是同样的情况。 - Dominik Ehrenberg
13
我不明白为什么这是被接受的答案:git文档(针对V1.9.4版本)明确表示这样做是行不通的。 - Félix Cantournet
2
不,你不能仅通过执行“git fetch -p -t”来删除任何本地标签。 - Christoph
@DominikEhrenberg 我发现它不能删除本地已经在远程删除的标签。最多只能获取新标签。也许这就是原因(来自man git fetch):“如果仅因为默认标签自动跟踪或--tags选项而获取标签,则标签不受修剪影响”。我使用的是git 2.7.4版本。 - R.D.
显示剩余4条评论

21

一些研究表明 git 没有办法区分本地标签和远程标签(所有标签都存储在 .git/refs/tags/ 中)。因此,无法确定本地创建的标签和可修剪的远程标签之间的差异。选项因此减少到:拥有不断增长的标签集合或仅拥有服务器上的标签。

git push --tags origin && \
git tag | xargs -n1 git tag -d && \
git fetch --tags

删除第一行以实现后一种行为,可以将其潜在地用作频繁使用的git别名。

另外一种方法是在标签点创建一个分支(因为它们可以被识别为本地/远程),然后不再对其进行写操作。然后使用remotename/branchname作为标记来检出将保持标记同步(除了 git fetchgit remote prune remotename之外)。

无论哪种方式都是一种黑客行为,“正确”的答案是停止经常更改标签。


还可以将所有标签一起提供给 git tag -d 命令,因此 git tag | xargs git tag -d && git fetch --tags 对我而言是有效的。 - solstice333

16

另一个实际可行的解决方案:

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

1
这个可以运行,但在长时间的标签历史记录上可能会很慢。 - David

13

使用以下命令同步标签(删除所有本地标签,然后获取所有远程标签)

git tag -d $(git tag) # delete all local tags
git fetch --all # fetch all remote to local

这正是我所需的信息。像冠军一样工作。 - Rod Hartzell
1
这个方法能够成功,而其他方法都不行。我一直遇到这个错误 ![rejected] 7.34 -> 7.34 (would clobber existing tag) ,尝试了很多方法都没有用。谢谢! - Intervalia

8

git push --tags会将您本地的标签推送到服务器。默认情况下,git fetch(git pull或git pull --rebase的前半部分)将拉取标签,但您可以指定-t或--tags来拉取所有标签。

我不确定如何修剪远程删除的标签,但fetch应该会拉取任何强制更新的标签。


5

注意事项: 这里使用的是 Git 的内部功能(有些人可能会争论文件系统本身就是一个 Git 接口,但这是另外一天的话题 :D)

# Blow away all local tags, this will remove any that are tagged locally
# but are not on the remote
rm .git/refs/tags/*

# Download all the tags from the remote
git fetch --tags

这并不总是有效的 - 有时标签存储在.git/info/refs而不是.git/refs/tags/*中。我仍在研究这两个位置之间的相互作用,但仅清除.git/refs/tags/*肯定不是清除标签的万无一失的方法。 - Phil Whittington
@PhilWhittington 我还没有遇到过它无法工作的情况,而且好像您也没有遇到过? - anthony sottile

0

这里有一个替代方案:

git fetch -p +refs/tags/*:refs/tags/*

来自git fetch文档:

-p --prune

在获取之前,删除任何在远程不存在的远程跟踪引用。如果标签仅因默认标签自动跟随或由于--tags选项而被获取,则不会对其进行修剪。但是,如果标签由于显式refspec(无论是在命令行上还是在远程配置中,例如如果使用--mirror选项克隆了远程),则它们也会受到修剪的影响


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接