git - 与分支同名的标签

git - Tags with the same name with a branch

我有点奇怪为什么 git diff branch1 branch2 会显示不相关的东西(就像是在比较 branch1 和旧版本的 branch2)

直到我发现我们有一些带有分支的同名标签!

除了 diff 之外,这会在 pull/push 上产生问题(不明确的引用名称错误...),并且可能会导致结帐...

所以我想找到所有这些标签以便删除它们

首先,我们提取所有标签:

git tag | sort > tags

和分支机构,如果您想与当地分支机构核实:

git branch | sed -e 's/^[ \t]*//' | sort > branches

或特定遥控器的分支,例如 origin

git branch -r | grep origin/  | sed -e 's:^[ \t]*origin/::' | sort > branches

提取标签和分支(按排序顺序)后,我们在这 2 个文件中找到了共同的行:

comm -1 -2 tags branches > bad-tags

并查看文件bad-tags
然后我们就可以全部删除了:

cat bad-tags | xargs git tag -d

saeedgnu's 走在正确的轨道上,但使用了许多额外的 shell 命令。

而不是使用 | sortgit tag and git branch have a --sort=<key> option, with <key> based on git for-each-ref field names and

默认情况下,分支和标签的默认排序顺序已经是 refname

并且自 Git 2.19(2018 年第 3 季度)以来,git branch 支持配置 branch.sort,就像 git tag 已经有一个配置 tag.sort.
参见 commit 560ae1c (16 Aug 2018) by Samuel Maftoul (``)
(由 Junio C Hamano -- gitster -- in commit d89db6f 合并,2018 年 8 月 27 日)

所以:

  • 无需排序 git tag:默认情况下它们已按 refname 排序,除非已设置 tag.sort 配置。
    但为了安全起见,至少使用 git tag --sort="refname"(不需要 | sort
  • 无需 grep originsedsort(除非已设置 branch.sort 配置):使用模式和格式:

    git branch -r --list 'origin/*' --format="%(refname:lstrip=3)"
    

格式将remotes/origin/aBranchName转换为aBranchName
模式“origin/*”确保我们选择了正确的远程仓库的远程分支。

这为您提供了纯粹的 git 命令:

git tag --sort="refname" > tags
git branch -r --list 'origin/*' --format="%(refname:lstrip=3)"
comm -1 -2 tags branches > bad-tags

除了脚本(使用纯 git 命令)错误标签的数量,Git 2.20(2018 年第 4 季度)提供了 避免 的替代方法必须获得与分支同名的标签。

git push”和“git fetch”用于确定一个 ref 是否可以更新的规则不一致;具体来说,即使标签应该是固定的锚点,也允许获取更新现有标签。
git fetch”被教导禁止在没有“--force”选项的情况下更新现有标签。

参见 commit 0bc8d71, commit ae6a470, commit fe802bd, commit 8da6128, commit d931455, commit 6b0b067, commit 253b3d4, commit f08fb8d, commit 8cd4b7c (31 Aug 2018) by Ævar Arnfjörð Bjarmason (avar)
(由 Junio C Hamano -- gitster -- in commit d39cab3 合并,2018 年 9 月 17 日)

fetch: stop clobbering existing tags without --force

Change "fetch" to treat "+" in refspecs (aka --force) to mean we should clobber a local tag of the same name.

This changes the long-standing behavior of "fetch" added in 853a369 ("[PATCH] Multi-head fetch.", 2005-08-20, Git 0.99.5).
Before this change, all tag fetches effectively had --force enabled.
See the git-fetch-script code in fast_forward_local() with the comment:

Tags need not be pointing at commits so there is no way to guarantee "fast-forward" anyway.

该提交和“fetch”的其余历史表明 refpecs 的“+”(--force)部分仅用于分支更新,而标签已无条件接受来自上游的任何更改并破坏了本地标记对象。更改此行为 has been discussed as early as 2011.

目前的行为对我来说没有意义,它很容易导致本地标签被意外破坏。
我们可以为每个远程标签命名空间,而不是在本地填充 refs/tags/*,但与我的 97716d2 一样(fetch:添加 --prune-tags 选项和 fetch.pruneTags 配置", 2018-02-09, Git 2.17) 解决当前实施比修复根本原因更容易。

(参见“In Git, how do I sync my tags against a remote server?”)

So this change implements suggestion #1 from Jeff's 2011 E-Mail, "fetch" now only clobbers the tag if either "+" is provided as part of the refspec, or if "--force" is provided on the command-line.

This also makes it nicely symmetrical with how "tag" itself works when creating tags.
I.e. we refuse to clobber any existing tags unless "--force" is supplied.
Now we can refuse all such clobbering, whether it would happen by clobbering a local tag with "tag", or by fetching it from the remote with "fetch".

Ref updates outside refs/{tags,heads/* are still still not symmetrical with how "git push" works, as discussed in the recently changed pull-fetch-param.txt documentation.
This change brings the two divergent behaviors more into line with one another. I don't think there's any reason "fetch" couldn't fully converge with the behavior used by "push", but that's a topic for another change.