个人心得:Git使用与开发规范
长时间开发,已经慢慢积累出了自己的一套开发规范,在此做下记录,同时也为读者提供一个参考。此文档可能会持续更新。
前言
强烈建议先通过交互式教程 learn git branching 了解Git对于操纵修改提交历史的各种进阶操作。
提交规范
参考 约定式提交 。
基本工作流
大型项目
请参照 Gitflow 。
小型项目
分支命名同 大型项目 。和大型项目唯一的区别是去掉了develop
分支,即feature
等分支可直接合入到main
分支。
代码审核
多人合作,无论项目大小,禁止直接将其他分支合入到main
分支。必须在仓库对应平台(如Github)上发起分支合并的PR,并指定小组其他剩余成员review,code review通过才可合入。
保持提交历史干净
借助git stash拉取最新更改
你正在a分支上进行工作,做了一些更改并还没有提交。此时你发现a分支上有一个别人上传的新提交,你想把新提交拉下来,基于此继续开发,但同时你本地的工作又还没有做完,你不想直接丢掉本地的更改。
参考以下命令:
git stash
git pull
git stash pop
git stash
可以把你当前的工作区暂存,然后git pull
拉取远程提交,git stash pop
再恢复工作区。通俗点就是用草稿纸记一下你的当前状态,然后再从草稿纸恢复过来。
另一种应用场景是你正在你的分支上做开发,突然你的队友让你去其他分支帮忙看下bug,此时也可以使用git stash
暂存一下,看完bug,回到自己的分支,再git stash pop
。
merge
还是rebase
分支合入的方式选择merge
还是rebase
是一个有争议的话题。一般来说,rebase
能尽量保持提交历史的干净,而merge
能不破坏原有的提交记录。本人更偏向于rebase
,因为干净的提交历史非常易于整理和阅读,而rebase
能实现这一点。
基于此,以下讨论开发中rebase
的使用。
使用rebase
获取main
分支的最新更改
你在
main
分支的M1
提交上创建了一个feature
分支,并在feature
分支上新增了一个提交F1
。此时你发现main
分支上有了别人上传的一个新提交M2
,于是你想把M2
的内容拉到你的feature
分支上,使你可以在最新的main
分支修改上继续做你feature
分支的开发。
习惯使用merge
而不是rebase
的人可能会选择直接把main
分支merge
到你的feature
分支上,但个人不建议这样,因为这可能会让提交历史看起来很怪异(可能导致历史提交记录各种相互交织,看起来异常复杂)。笔者看来,良好的提交历史里面应该只有其他分支向main
分支方向的merge
,而不存在main
分支向其他分支方向的merge
。也就是,merge
应该是单向的。
一种方式是可以使用cherry-pick
,读者可以自行搜索。但这里想要介绍的是rebase
的方式。在以上场景下,请把你的feature
分支在本地rebase
到main
分支上(可能需要处理冲突),然后在本地,你的feature
分支就从基于M1
变成了基于M2
,也就是M1<-M2(main)<-F1(feature)
这种样子,整个提交历史变成了一条线性,看起来美观许多。
本地rebase
以后,需要将你的本地feature
分支force push(--force
参数)到远程仓库,这是因为你本地的feature
分支已经和你远程的feature
分支所在位置不一样了,需要将本地的rebase
也强行推送到远程,这点很重要。
在提交PR/合并前先rebase
请在你提交PR前(也就是想合并分支前)先把你的个人分支rebase
到main
分支之上(记得force push),然后再发起PR。这样做的好处有二:
- 干净的历史记录。这样做以后,你的第一个修改是接在
main
分支的最后一个修改后面的,整个提交历史是线性的,没有分叉和交汇,非常干净,易于阅读(特别是对于reviewer)与日后维护。 - 无需要再处理的冲突。在你
rebase
的过程当中,你已经完成了你与main
分支的实际代码合并(也就是上一节提到的,你已经通过rebase
获取到了main
分支的所有最新修改),同时完成了对于代码冲突的解决。你的reviewer也会知道,你发起的这个PR已经考虑到了所有main
分支最新的修改。之后在合并时,由于提交历史已经是线性的,main
分支会直接fast-forward
到你的feature
分支的最新提交上,非常优雅。
潜在的风险
请确保你要force push的这条分支只有你一个人在开发,没有其他人在上面,否则你的行为可能会让其他人在下次拉取提交时很困扰(直接pull
的话会出现很混乱的提交合并,后果很严重!)。因此如果这条分支还有其他人,请务必先做好协商。
其他习惯/技巧
开始工作/结束工作 的第一件事:git fetch
请不要直接无脑git pull
,否则可能会产生一些比较严重的后果,例如当别人可能已经通过rebase+force push或者其他方式更改了远程的提交历史/分支结构。
良好的习惯是先git fetch
,获取远程的最新更改,检查一下远程状态,检阅一下别人的最新工作,再决定要做什么操作。
例如,当你发现你所在的某条分支竟然已经被某个不守规矩的人rebase并force push了,此时你要做的应该是先把你本地的这条分支删除,然后重新去把远程的这条分支拉下来。
结束工作(commit)前也是如此。请先确认好该分支没有别人上传的新提交再commit。如果有新提交,请参考前面介绍的git stash
,把远程的更新拉过来再进行自己的提交,保证自己的commit在远程的这个新提交之后,而不是出现奇怪的分叉。
如果你已经commit了,问题也不大,你可以通过
git pull --rebase
,把你的commit置于拉取到的远程提交之后。
工具推荐
- 强烈建议使用可视化工具查看本地/远程提交历史以及具体更改,例如vscode插件 git graph 。