☰
Git分支与标签管理:从随手命令到可回溯版本规范
2026/10/26 14:05:44 网站建设 项目流程

仓库里的分支和标签,大概是每个写代码的人每天都要碰、却又最容易含糊带过的两个东西。git branch和git tag看起来只是两条简单的命令,一个切来切去,一个打上标记,但真正在多人协作、版本发布、线上回滚这些场景里出问题的时候,八成都能追到这两块没管清楚。我自己就经历过把热修分支误删、把发布标签删掉又重打、在 detached HEAD 上提交完切走导致提交"消失"这些事,踩一次记一辈子。

这篇内容围绕git branch与git tag的操作展开,把这两个东西的底层定位、常用命令的参数取舍、合并与变基的边界、标签的创建推送与校验、以及误操作之后的补救路径,全部拆开讲一遍。核心解决的问题是:让分支和标签从"随手用的命令"变成一套有规则、可回溯、能放心交给团队用的版本管理习惯。适合刚上手 Git 不久、只会add/commit/push三件套的同学,也适合带团队、需要制定分支规范的人对照着看。下面所有命令都基于 Git 2.23 以上版本,switch和restore这两个新命令可以直接用。

1. 先弄清分支和标签到底在做什么

1.1 两者本质都是指针,区别在于会不会跟着提交往前走

Git 的整个数据结构里,提交对象是一张有向无环图,每个提交记录着父提交的哈希。而分支和标签,干的其实是同一件事——给某个提交起一个好记的名字。翻一下.git目录你就明白了:.git/refs/heads/下面放的是分支,.git/refs/tags/下面放的是标签,里面的内容就是一行四十位的提交哈希。仓库跑久了,这些散文件会被打包进.git/packed-refs,但逻辑不变。

真正的差别在于可变性。分支是一个会移动的指针,你在分支上提交一次,这个指针就自动前移到新提交;标签一旦创建,就死死钉在那个提交上,除非你手动删掉重打。用生活里的东西类比:分支像书签夹在书里,你继续往后读,书签就跟着往后挪;标签像在某一页盖了个骑缝章,那一页写死了,后面怎么翻都不影响它。

这个差异直接决定了它们的用途。分支是"工作线",承载的是"接下来要做什么";标签是"里程碑",承载的是"曾经做过什么"。把这两件事混在一起,用分支去标记版本,最后仓库里会堆出几十条release-1.0、release-1.1的长命分支,谁也不敢删;反过来用标签做并行开发,那就更离谱了,标签根本没法承载后续提交。

1.2 什么时候必须用分支,什么时候必须用标签

判断标准其实很简单,问自己一句:这个东西后面还会不会继续往前走?

会往前走的,用分支。功能开发、bug 修复、实验性重构、临时的技术验证,全都属于这一类。分支的价值在于隔离——你在feature/payment上把代码改烂了,main上一行都不受影响;等你改好了,再合回去。它是并行工作的基础设施,没有分支,一个团队只能排队改代码。

不会往前走的,用标签。版本发布、线上事故的锚点、某个重要节点需要长期留存的快照,用标签。标签的价值在于可追溯且不可漂移。三个月后线上出问题,你说"回滚到 2.4.1",运维执行git checkout v2.4.1拿到的代码,和你三个月前发布时打的标签指向的代码,是同一个哈希,一个字符都不差。换成用分支标记版本,谁敢保证那条分支上没人在发布后又推了一次提交。

我在实际项目里见过一种很典型的混用:某个团队每次发版就打一条release/20240315分支,然后在上面继续改小问题,改完再发。结果三条发布分支之间代码不一致,谁也说不清线上跑的到底是哪份。后来改成打附注标签,发布分支发完立刻删掉,仓库立刻清爽了,回滚也有了唯一确定的锚点。

1.3 长命分支越少越好,短命分支越多越好

顺带说一个设计层面的判断。一个健康的仓库,长命分支一般就那么两三条,比如main加一条develop,可能再加一条当前正在维护的旧版本分支。剩下的分支都应该是短命的,活几天、最多一两周,合完就删。

原因在于合并成本是随着分支存活时间指数级上升的。一条分支活一个月,主干上可能已经进了两百个提交,合并的时候冲突能堆满一屏,解决冲突的时间比写功能还长。我也试过让分支活很久,最后发现每次 rebase 都要花半小时处理冲突,纯属自找麻烦。

至于标签,数量上没有上限,历史标签越多越好,它们是版本演进的完整档案。仓库里保留十年份的标签都没问题,因为标签几乎不占空间,一个附注标签也就是几百字节。

2. 分支操作的核心细节与实操要点

2.1 创建与切换:switch 和 checkout 该怎么选

老一点的教程里全是git checkout -b,这个命令本身没错,但它是个"万能命令",既能切分支,又能恢复文件,还能检出提交,参数一多就容易搞混。Git 2.23 把职责拆开了:切分支用git switch,恢复工作区文件用git restore。这不是玩花活,而是减少误操作的实招——你想想,git checkout -- .是丢弃所有工作区改动,手一抖打成git checkout .在某些版本里行为还不一样,损失是不可逆的。

日常我用得最多的三条:

# 从当前 HEAD 创建并切到新分支 git switch -c feature/order-export # 从指定的远端分支创建本地跟踪分支 git switch -c hotfix/login-timeout origin/release/2.4 # 从某个标签创建分支,用于基于历史版本修问题 git switch -c hotfix/2.4.1 v2.4.1

这里有个细节值得说一下:git switch -c的-c是 create 的缩写,等价于老写法git checkout -b。但switch有个明确的好处,它只接受分支名,你要是手滑传个文件名进去,它会直接报错而不是默默去切提交,安全不少。

查看分支这件事,很多人只会git branch,其实它的参数能挖出不少信息:

git branch # 本地分支 git branch -r # 远端分支 git branch -a # 全部 git branch -vv # 带上游跟踪信息和 ahead/behind 计数 git branch --merged # 已经合进当前分支的分支 git branch --no-merged # 还没合进来的

git branch -vv是我最推荐养成习惯的一条。输出长这样:

* main a1b2c3d [origin/main: ahead 2, behind 1] 修订单号校验 feature/order-export 9f8e7d6 [origin/feature/order-export] 导出接口初版

方括号里的ahead 2, behind 1直接告诉你本地比远端多两个提交、少一个提交。少了这个信息,你根本不知道自己的分支是不是已经落后于主干,push的时候才发现被拒绝,白耽误时间。--merged和--no-merged则是清理分支时的利器,先看一眼哪些已经合完了,心里有数再动手删。

注意:git branch只是列本地分支,远端已经被别人删掉的分支,你本地仍然会显示为origin/xxx。这些是"过期的远端引用",需要定时清理。

2.2 清理过期远端引用与设置上游跟踪

远端分支被人删了,本地还留着一堆origin/feature/xxx的过期引用,时间长了git branch -a能刷出几十行,看着就烦。解决办法是带 prune 参数拉取:

git fetch --prune # 或者简写 git fetch -p

这条命令会在拉取的同时,把远端已经不存在的分支引用从本地清掉。我习惯把它设成默认行为,省得每次手动加:

git config --global fetch.prune true

再说上游跟踪。新建的本地分支默认没有 upstream,第一次git push会提示你加--set-upstream。这一步别偷懒,宁可多敲一次:

git push -u origin feature/order-export

设好之后,后续git push、git pull、git status全都知道该和哪个远端分支对比。git status会告诉你"你的分支比 origin/xxx 领先 3 个提交",这个提示在日常协作里非常有用。如果分支已经建好了但忘了设,可以补:

git branch --set-upstream-to=origin/feature/order-export

还有一种情况,别人的分支你想在本地跟一下,不用自己建,直接切同名分支 Git 会自动建立跟踪:

git switch feature/order-export

前提是origin/feature/order-export存在且本地没有同名分支。这个"自动猜"的行为很方便,但要注意别在已有本地同名分支的情况下用,会直接切到本地那条,容易搞混。

2.3 合并策略:merge 与 rebase 的边界在哪

这是分歧最大的一块,我先给结论:主干上用 merge,个人分支整理用 rebase,公共分支绝对不 rebase。

git merge会生成一个合并提交,保留完整的分叉历史。默认情况下如果 Git 发现可以快进(目标分支是当前分支的直系后代),它会直接把指针前移,不产生合并提交。这在历史记录上看起来像是一条直线,但丢失了"这里曾经有一个功能分支"的信息。团队协作场景里,我更倾向强制生成合并提交:

git merge --no-ff feature/order-export

--no-ff强制创建一个合并节点,好处是将来用git log --graph看历史,能清楚看到每个功能是从哪里进来、包含了哪几个提交。要回滚整个功能,直接 revert 那个合并提交就行,一次搞定。如果用快进,功能分支上的五个提交混进主干历史,想整体回滚就得 revert 五次,中间还可能被别的提交隔开。

git rebase则是把当前分支的提交"摘下来",重新接到目标分支的最新提交之后。效果是历史变成一条直线,没有分叉。它的适用场景是:你的个人分支落后主干太多,想在合并前先跟上最新的主干,把冲突在自己这边解决掉。

# 在 feature 分支上,把基线更新到最新 main git switch feature/order-export git rebase main

如果中间有冲突,Git 会停下来让你解决,解决完git add,然后git rebase --continue。想放弃就git rebase --abort,回到 rebase 之前的状态。

注意:rebase 会重写提交哈希。一条已经推送到远端、别人可能基于它工作的分支,绝对不能 rebase。你 rebase 完强推上去,同事本地的历史就对不上了,下次 pull 会拉出一堆重复提交,非常难收拾。

如果确实在自己分支上 rebase 过并且需要推上去,用git push --force-with-lease而不是--force。前者会先检查远端有没有你不知道的新提交,有就拒绝推送;后者是无脑覆盖,能把你同事刚推的东西直接抹掉。我吃过一次--force的亏,虽然最后从 reflog 里捞回来了,但那半小时心跳加速的感觉不想要第二次。

还有一个常被忽略的操作是交互式 rebase,用来整理自己分支上的提交历史:

git rebase -i HEAD~3

它会打开编辑器,列出最近三个提交,你可以把pick改成squash合并、改成reword改提交信息、改成drop删掉。合并前把"修一下"、"再改改"、"改回来了"这种垃圾提交压成一个干净的提交,是对 reviewer 的基本尊重。

2.4 删除分支与误删之后的补救

合完的分支要删,这是纪律。本地删:

git branch -d feature/order-export # 已合并才允许删 git branch -D feature/order-export # 强制删,未合并也删

-d会检查这个分支是否已经合并进当前分支,没合并就拒绝,这是保护机制。-D是大写,强行删,用在"这个分支的实验彻底失败了"的场景。远端删:

git push origin --delete feature/order-export

现在说误删。假设你手滑-D删了一条还有三个提交没合的分支,别慌,git reflog是救命的:

git reflog

输出里会有一行类似a1b2c3d HEAD@{5}: checkout: moving from feature/order-export to main,找到那个提交哈希,直接建回来:

git branch feature/order-export a1b2c3d

reflog 默认保留 90 天的可达记录,30 天的不可达记录,日常误操作基本都能捞回来。远端分支被误删也一样,只要本地还有那个提交,重新推上去就行:

git push origin a1b2c3d:refs/heads/feature/order-export

这条命令的意思是"把哈希 a1b2c3d 推到远端的 feature/order-export 分支"。注意冒号右边要写完整的refs/heads/前缀,否则 Git 可能理解成别的意思。

提示:reflog 只存在于本地,不会随 clone 或 push 传给别人。所以指望别人帮你找回误删的提交是不现实的,出事只能在自己这台机器上捞。

3. 标签操作全流程

3.1 轻量标签和附注标签,务必要选后者

Git 支持两种标签。轻量标签就是git tag v1.0.0,本质上只是在refs/tags/下写一个文件,指向某个提交,别的什么都没有。附注标签是git tag -a v1.0.0 -m "发布说明",它会在 Git 对象库里创建一个完整的 tag 对象,记录打标签的人、邮箱、时间、说明文字,还能做 GPG 签名。

我的建议很明确:发布用的标签一律用附注标签,轻量标签只在临时本地标记时用。

理由有几条。第一,附注标签能回答"这个版本是谁、什么时候发的",这在追责和审计时是硬信息,轻量标签完全给不了。第二,git describe默认只认附注标签,你打一堆轻量标签,它一个都看不见。第三,附注标签可以被签名,git tag -s v1.0.0 -m "..."加-s参数,用 GPG 私钥签一下,别人git tag -v v1.0.0就能验证这个标签确实是你打的,没被篡改。发布到生产环境的版本,这个保障值得花那几秒钟。

一个规范的附注标签长这样:

git tag -a v2.4.1 -m "修复订单导出超时问题 - 导出任务改为异步队列 - 单次导出上限调整为 5 万条 - 修复分页参数越界导致的空结果"

-m支持多行,用换行符分隔就行。这种写法让标签本身就带了一份简版变更日志,git show v2.4.1的时候直接能看到,不用再去翻提交记录。

命名上我推荐语义化版本v主版本.次版本.修订号,前缀加不加v团队内部统一就行,但要一致。见过一个仓库里同时有1.0.0、v1.1、release-1.2、V1.3.0四种风格,纯属给脚本添堵。

3.2 打标签、推送、删除与校验的完整动作

标签有一个极其容易踩的坑:git push默认不推标签。

很多人打完标签本地git tag看着有,以为完事了,结果 CI 拉代码时找不到标签,构建号对不上。正确的推送方式有两种:

# 推单个标签 git push origin v2.4.1 # 推所有本地标签(包括轻量的) git push origin --tags # 只推附注标签(推荐) git push origin --follow-tags

--follow-tags是我最推荐的,它只推送附注标签,而且是在推送分支的同时顺带推,不会把本地那些乱七八糟的轻量标签一股脑甩到远端。如果团队里有人习惯打轻量标签,用--tags会把它们全推上去,远端标签列表很快就乱了。

把默认行为改掉也行:

git config --global push.followTags true

删除标签要分本地和远端两步,很多人只做了第一步:

# 删本地 git tag -d v2.4.1 # 删远端 git push origin --delete v2.4.1 # 等价的旧写法 git push origin :refs/tags/v2.4.1

只删本地不删远端,下次fetch一拉,远端那个标签又回来了,白忙一场。

校验这块有几个实用命令:

git tag # 列出全部标签 git tag -l "v2.*" # 通配符筛选,注意引号不能省 git show v2.4.1 # 查看标签详情和指向的提交 git show-ref --tags # 列出标签及其哈希 git ls-remote --tags origin # 直接查远端有哪些标签 git tag --contains a1b2c3d # 哪些标签包含这个提交 git describe --tags --long # 找到最近的标签并给出距离

git tag -l "v2.*"这条命令里的引号千万别省。不写引号的话,shell 会先做文件名通配,当前目录下有v2.txt之类的文件时,命令就变成了git tag -l v2.txt,结果自然是空的,你会以为标签不存在。

git describe --tags --long的输出格式是v2.4.1-12-ga1b2c3d,意思是"距离 v2.4.1 这个标签还有 12 个提交,当前提交是 a1b2c3d"。这个字符串非常适合拿来做构建版本号,比单纯的2.4.1信息量大得多,能精确定位到某次构建对应的代码状态。CI 脚本里常见这种用法:

VERSION=$(git describe --tags --long --dirty)

末尾的--dirty表示如果工作区有未提交改动,就在版本号后面加个-dirty后缀,能有效防止"从带脏改动的工作区构建出来的产物被当成正式版发布"这种情况。

3.3 检出标签与 detached HEAD 的处理

git checkout v2.4.1之后,Git 会提示你处于 "detached HEAD" 状态。这个提示吓过不少人,其实它没那么可怕,只是需要理解发生了什么。

正常情况下 HEAD 指向一个分支,分支指向一个提交。检出标签时,HEAD 绕过分支直接指向那个提交,所以叫"游离"。在这个状态下你当然可以看代码、编译、跑测试,但如果你在这里做了提交,这些提交不属于任何分支,一旦切走,它们就成了"孤儿提交",只能靠 reflog 找回来。

正确的处理方式分两种。

只读不改,看完就走:

git switch v2.4.1 # 看看代码,跑跑测试 git switch main

需要在这个版本上改东西,就基于标签开一条新分支:

git switch -c hotfix/2.4.2 v2.4.1

这样 HEAD 就挂到新分支上了,后续提交都有归属,不存在丢失风险。这是我认为最应该养成的习惯:看到 detached HEAD 的提示,第一反应就是开分支,而不是直接在上面改。

万一手快已经在游离状态下提交了才发现,也别急,直接原地建分支就能把提交接住:

git switch -c rescue/20240315

此时新分支会指向你刚才的提交,一切正常。要是已经切走了,用git reflog找到那个提交哈希,再git branch rescue/xxx <hash>建回来。

还有一个细节:如果标签名和分支名重名,git checkout xxx会有歧义。Git 默认优先当分支处理,找不到才当标签。想明确指定标签,写全路径:

git switch --detach refs/tags/v2.4.1

4. 几个真实场景的完整演练

4.1 线上紧急修复:从标签拉分支再合回去

这是最典型的组合用法。假设线上跑的是v2.4.1,主干main已经推进到了v2.5.0的开发中期,现在线上爆出一个严重问题,必须基于 2.4.1 修。

第一步,从标签拉热修分支:

git fetch --tags git switch -c hotfix/2.4.2 v2.4.1

注意先fetch --tags,确保本地标签是最新的。我遇到过同事本地标签停留在半年前,从旧标签拉分支,改完发现改的地方在新版本里早就重构过了,白干一天。

第二步,改代码、提交、打新标签:

git add . git commit -m "修复导出任务并发数超限" git tag -a v2.4.2 -m "紧急修复:导出任务并发控制" git push origin hotfix/2.4.2 git push origin v2.4.2

第三步,把修复同步回主干。这一步很多人会漏,导致下次发版问题重现:

git switch main git cherry-pick <修复提交的哈希>

用cherry-pick而不是merge,原因是hotfix/2.4.2这条分支是从旧版本拉出来的,直接合进main会把大量旧代码一起带回来,等于把主干退回了 2.4.1 的状态。cherry-pick只挑那一个提交,干净利落。

如果中间有冲突,解决完git add,再git cherry-pick --continue。整个链路走完,记得把热修分支删掉:

git branch -d hotfix/2.4.2 git push origin --delete hotfix/2.4.2

4.2 发布流水线里的标签动作

在自动构建里,标签往往是版本的唯一来源。一个典型的发布流程是这样:开发合完代码到main,打一个附注标签推上去,CI 监听到标签推送事件,自动构建、自动打包、自动上传,产物名里带上标签名。

这种设计的好处是版本号和代码状态严格绑定。你看到产物叫app-v2.5.0.tar.gz,就能确定它对应的是v2.5.0这个标签指向的那份代码,出问题回滚也简单——重新构建v2.4.1的产物即可。

CI 里的版本号提取一般这么写:

# 拿最近的标签 + 提交数 + 短哈希,保证唯一 VERSION=$(git describe --tags --always --long) # v2.5.0-7-ga1b2c3d # 如果只想要干净的版本号,且必须打在标签上才发布 if git describe --exact-match --tags HEAD > /dev/null 2>&1; then VERSION=$(git describe --exact-match --tags HEAD) else echo "当前提交没有标签,跳过发布" exit 0 fi

--exact-match的意思是"HEAD 必须正好在一个标签上",不满足就退出来。这条判断能挡住"随手推个分支就触发发布"的情况。我在一个项目里就吃过这个亏,某次误把 feature 分支推到了远端,触发了发布流程,虽然产物没上线,但把版本号占掉了。

再补一个标签顺序的细节。发布时是先推代码还是先推标签?顺序上没强制要求,但实践上我建议先推标签,再推分支。因为标签指向的提交必须先在远端存在(其实不是必须,推送标签会连带把提交传上去),但如果分支先推了、标签推送失败,就会出现"代码已经在那了但没有版本标记"的空窗。先推标签,失败了还能重试,不会留下不一致。

4.3 分支治理:命名规范和合并前的检查清单

分支一多,命名混乱带来的沟通成本会非常大。我现在用的规范是带前缀的三段式:

前缀用途示例生命周期
feature/新功能开发feature/order-export数天到两周
fix/普通缺陷修复fix/login-timeout数小时到数天
hotfix/线上紧急修复hotfix/2.4.2-export数小时
release/发布准备(可选)release/2.5.0一两天
chore/构建、依赖、配置chore/upgrade-node数小时

这个规范的价值不在于好看,而在于可以用脚本批量处理。比如月底清理一遍长期不动的手工分支:

# 列出三个月没动过的分支(按提交日期) git for-each-ref --sort=committerdate \ --format='%(committerdate:short) %(refname:short) %(authorname)' \ refs/heads/ | head -20

合并前的检查清单,我一般跑这三条:

# 1. 我的分支是不是落后主干太多 git fetch origin git branch -vv # 2. 我的分支包含哪些提交,有没有垃圾提交要压 git log --oneline main..HEAD # 3. 有没有把不该提交的文件带上去 git diff --stat main...HEAD

第一条看 ahead/behind,如果落后太多,先 rebase 跟上;第二条看提交信息,把"改一下""测试"这种压掉;第三条看改动文件,防止误提交node_modules、.env、本地配置这类东西。

关于分支保护,如果用的是托管平台,主干分支应该开保护:禁止直接推送、必须走 Pull Request、必须通过 CI、必须至少一个人 approve。这些不是流程负担,而是把"误推到主干"这种低级事故从物理上杜绝。我自己有次半夜改代码忘了切分支,直接在main上提交并推了上去,幸好有保护规则拦住了。

5. 常见问题与排查速查

5.1 高频问题速查表

现象大概率原因解决方式
推标签报already exists远端已有同名标签先删远端再推,或用新版本号
删了本地标签,fetch 后又出现只删了本地没删远端git push origin --delete vX
git tag -l "v2.*"返回空少了引号被 shell 展开加上引号重试
切分支后文件没变化工作区有未提交改动被带过去先stash或提交再切
分支误删,提交找不到分支指针没了git reflog找到哈希重建
detached HEAD 上的提交消失了提交不属于任何分支git reflog+git branch恢复
git describe看不到标签用的是轻量标签改用-a打附注标签
分支名大小写和远端不一致大小写不敏感的文件系统用git branch -m重命名后重推
rebase 后同事拉取出现重复提交公共分支被改写了历史让同事git reset --hard origin/xxx

5.2 几个容易翻车的点,逐个拆开说

同名标签重复打。这是最常见的。假设v2.4.1已经推到远端,你本地删了重打,然后git push origin v2.4.1,会收到! [rejected] v2.4.1 (already exists)的报错。Git 默认拒绝覆盖已存在的标签,这个保护是对的——如果允许随便覆盖,标签的可追溯性就没了。确实需要重打,先删远端:

git push origin --delete v2.4.1 git push origin v2.4.1

但我更建议的做法是换个版本号。已经发出去的标签就是公开承诺,覆盖它等于告诉所有人"昨天那个 2.4.1 不算数",配合方会疯掉。宁可发v2.4.2。

切分支时工作区改动被带走。这是新手最容易懵的。你在feature/a上改了一堆文件没提交,直接git switch main,Git 会把能带的改动一起带过去。如果改的文件在两个分支之间没有差异,切换是成功的,但改动跑到main上了;如果有差异,Git 会拒绝切换并报错。

正确做法是切换前先处理掉:

# 存起来,切过去处理完事再回来 git stash push -m "调试到一半" # 或者干脆提交一个临时提交(WIP 提交) git commit -am "WIP: 导出接口临时调试"

stash更干净,但要注意stash是不分分支的,列表是全局的。多个分支同时 stash 的时候,用-m加说明,不然过两天你自己都分不清哪个是哪个。查看用git stash list,恢复用git stash pop(弹出并删除)或git stash apply(保留)。

rebase 之后上游分支对不上。你在自己分支上 rebase 了主干,然后git push,被拒绝。这时候用--force-with-lease:

git push --force-with-lease origin feature/order-export

如果还是被拒绝,说明远端有你没拉下来的提交,先git fetch看看是什么,别硬来。--force-with-lease的检查逻辑是比较远端的当前值和你的本地记录值,如果你fetch过,本地记录就更新了,保护就失效了。所以要在 rebase 之后、fetch 之前推,顺序很重要。

大文件误入历史,标签和分支都受影响。这是最麻烦的一类。有人提交了一个几百兆的二进制文件,推上去之后仓库体积爆炸,所有人都要拉这份历史。删掉文件再提交是没用的,历史里还在。这时候要改写历史,用git filter-repo之类的工具(旧版的filter-branch已经废弃了)。改写之后所有提交哈希全变,所有分支和标签都要重新推。这种操作我建议直接开个新仓库重建,或者找有经验的人来做,风险太高。

5.3 三条我踩过坑之后固化的习惯

第一条,推送前必跑git branch -vv。这一步能看出两件事:当前分支有没有设置上游,以及本地和远端差了多少。大部分"推不上去"和"拉不下来"的问题,在这一步就能发现。

第二条,打标签前必跑git status和git fetch --tags。前者确认工作区干净(避免从一个带改动的工作区打标签),后者确认标签列表是最新的。这两条加起来不到十秒钟,能挡掉一大半发布事故。

第三条,任何要删除的东西,先确认它是不是已经在远端存在,以及本地是否有备份。删分支、删标签、--force推送之前,我现在的固定动作是先git branch -a和git tag -l看一遍,心里确认"这个东西远端有,删了能找回来"。找不到的就先建个备份分支backup/xxx放着,确认没问题了再删。

这三条听起来像是废话,但真到了手忙脚乱的时候,能想起这三条的人不多。我现在把前两条直接写进了 shell 的git push别名里,每次推送自动先跑一遍检查,用了几次就回不去了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询