如何写好Git Commit

什么是好的git commit,有以下几点:
* message清楚反应本次提交内容
* 方便回退到某个版本
* 反应产品演进过程

主要针对团队开发,对于开源和非开源项目要求可能不一样。个人认为,开源项目的master提交尽量反应产品演进,所以,分支合并时,可以把分支的多个commit合并为一条。但团队非开源项目,我觉得没必要这么做,多点“小步提交“的message没什么关系。

当然,对个人的提交来说,可以按照自己的习惯,从msg格式和提交上把commit写好。

message格式

feat: 添加阅读数量

给文章添加阅读数量功能
- 添加xx1
- 添加xx2

Issue #1, #2
Close #1

说明:
第一行: :header

keyword: 简要说说明

keyword:
* feat: 新增feature
* fix:bugfix
* docs:文档修改
* style: 改变编码风格
* refactor:重构
* perf:改善
* test:添加测试
* revert: 回退到前一版本

第二行:body,详细说明
第三行:footer,指向或者关闭issues

所以,在提交是尽量避免如下命令

git commit -am "xxx"

下文还是这样使用,只是为了方便演示。

修改提交

本来开发都会尽快小步提交,如果提交的message写得不好,直接通过--amend选项修改:

git commit --amend

如果是新的修改提交,也可以用相同的命令,把这次提交合并到上次的commit中。

可以使用rebase作各种变基嫁接操作,下面看一个示例

$ ls
README.md file1.txt

$ git lg
* 6ffc8d0 - (HEAD -> master) add file1 (3 minutes ago) <thoreau>
* d12e8cf - refactor(package): 提炼方法 (21 minutes ago) <thoreau>

下面添加file2并简单(方便演示)提交:

$ touch file2.txt
$ ga 
$ gcm "add file2"
$ git lg
* bc004ef - (HEAD -> master) add file2 (8 seconds ago) <thoreau>
* 6ffc8d0 - add file1 (5 minutes ago) <thoreau>
* d12e8cf - refactor(package): 提炼方法 (23 minutes ago) <thoreau>

现在,我们想把第二个提交删除,把最后一个提交的msg修改为»new file2»:

git rebase -i d12e8cf


修改如下:

紧接着编辑最后一个提交的msg。执行git log

做到了我们想要的结果,删一个改一个,再看文件,发现file1.txt不存在了。

使用rebase的好处是想怎么改就怎么改,但最后是针对自己阶段性提交的修改,否则造成commit history对不上,分支合并出现问题。除非是修改历史敏感信息,这个命令需要谨慎使用。

从技术上,还是有补救办法,如果不想删除第二个提交,想回退rebase,怎么办?
git reflog

git reset --hard bc004ef #撤销

分支合并时的commit

在上述三个commit的master上建一个分支:b1,并修改file2,新建file_b1

* 9bd82c9 - (HEAD -> b1) add file_b1 (82 seconds ago) <thoreau>
* 5cab28f - edit file2 (2 minutes ago) <thoreau>
* bc004ef - (master) add file2 (21 minutes ago) <thoreau>
* 6ffc8d0 - add file1 (26 minutes ago) <thoreau>
* d12e8cf - refactor(package): 提炼方法 (44 minutes ago) <thoreau>

现在把分支合并到主干,但我希望把分支的commit都合并成一个,可以使用--squash

git checkout master
git merge --squash b1
git commit -m "feat: new file_b1 and Bugfix"

远程分支合并

如果你在本地新增提交的时候,远程分支已经有新提交,此时由于commit history不一样,是不允许提交的,需要先把分支合并过来,形成一个新的提交,如下图。

可以看到,分支br上的提交6e989ff合并到master时,生成一个新提交ea74b46。我们可以使用嫁接的方式(也叫分支衍合),把6e989ff直接嫁接到master提交1becaca后,还是使用rebase,不会产生新的提交,如下,是git官方说明。


参考列表:
* https://github.com/torvalds/linux/pull/17#issuecomment-5654674
* http://yanhaijing.com/git/2016/02/17/my-commit-message/
* http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html
* https://git-scm.com/book/zh/v1/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E8%A1%8D%E5%90%88

CONTENTS