git fetch 默认不下载远程 tag,需用 git fetch --tags 或配置 remote.origin.tagOpt --follow;本地失效 tag 可通过 git ls-remote --tags origin 对比清理。

git fetch 不会自动下载远程 tag
默认 git fetch 只拉取分支引用(refs/heads/*),远程新建的 tag 完全不会出现在本地。这不是 bug,是 Git 的设计选择:tag 被视为“附注”而非活跃开发线,需显式获取。
- 执行
git fetch后运行git tag,列表不变 - 远程已推送的 tag(如
v1.2.0)在本地查不到,git show v1.2.0报错fatal: ambiguous argument 'v1.2.0': unknown revision - 想让本地 tag 列表和远程完全一致,必须加参数或改配置
同步所有远程 tag 的两种可靠方式
最常用的是带 --tags 的 fetch,但要注意它和 --all 的行为差异;另一个是配置成默认拉取 tag,适合长期协作项目。
-
git fetch --tags:拉取所有远程 tag 到本地(包括已存在同名 tag 的强制覆盖),但不更新远程分支引用 -
git fetch --all --tags:先拉所有远程分支,再拉所有 tag,等价于连续执行git fetch --all和git fetch --tags - 永久生效:运行
git config --global remote.origin.tagOpt --follow,之后每次git fetch都自动包含 tag(Git 2.10+ 支持)
删除本地已失效的 tag
远程 tag 可能被 force-push 覆盖或删除,但本地 tag 不会自动消失,导致 git checkout v1.1.0 拿到旧提交,或 git push origin :refs/tags/v1.1.0 失败(因为本地还存着)。
- 查出哪些 tag 远程已不存在:
git ls-remote --tags origin | cut -d' ' -f2 | grep -v '^{}$' | sed 's/\^{}$//' | sort | comm -23 - 批量删掉这些本地 tag:
git tag -d $(git ls-remote --tags origin | cut -d' ' -f2 | grep -v '^{}$' | sed 's/\^{}$//' | sort | comm -23 - 更稳妥的做法:先
git fetch --prune --tags(Git 2.22+),再手动确认后删
CI/CD 或脚本里别依赖 git tag -l 默认输出
很多自动化流程假设 git tag -l 能反映最新远程状态,结果在干净构建环境里拿到空列表或过期 tag,导致版本号生成错误、发布跳过。
- CI 脚本开头务必加
git fetch --tags --prune-tags(Git 2.22+)或git fetch --tags(兼容旧版) -
--prune-tags会自动清理本地已从远程消失的 tag,比手动git tag -d更安全 - 如果用
git describe --tags打包,确保前一步 fetch 已完成,否则可能 fallback 到最近 commit,版本号失真
tag 同步不是“一次设置永久有效”的事,尤其在多人维护多个远程仓库时,origin 和 upstream 的 tag 状态可能不同步,每次操作前最好先确认当前 fetch 的目标 remote 是谁。


















