git提交规范

65次阅读

共计 4190 个字符,预计需要花费 11 分钟才能阅读完成。

Git Commit (提交) 规范与注意事项

请先阅读:

  • How to Write a Git Commit Message
  • Commit messages – Good practices
  • angular.js 的命名规范

怎么样算是一个好的 commit?

  1. 一个 commit 应该只包含一种变更逻辑,多个变更逻辑应该拆分多个 commit
  2. 容易 code review (多个小 commit 比一个大 commit 容易 review)
  3. 一次变更在 200 行代码内,或是 4 小时内的工作量 (超过则要考虑拆分 commit)
  4. 提交历史容易阅读,可以理解一个分支是如何完成的
  5. 将来容易 revert
  6. 不确定怎么样算是一个合理的 commit?=> 问 code reviewer 的建议
  7. 若是多个 commit 完成同一件任务,则应该考虑合并 (squash/amend)
  8. 宁愿先拆分成多个 commit,之后再合并 (操作简单);也不要提交一个大 commit,之后再拆分 (操作困难)
  9. reviewer 有权力退回并要求重新拆分或是合并 commits。因为大 commit 会非常难以审查。

Commit Message 规范

一个好的 commit message 应该一眼就能理解:

  • 操作的目的 (subject)
  • 改变的范围或模块 (scope)
  • 操作的类型 (type)

而这些讯息应该都放在 commit message 的第一行 (header) 中。commit message 允许输入多行讯息,因此详细的内容应该放在后面的 body 和 footer 中。

本 commit message 规范,主要参考 angular.js 的命名规范。提交一个 commit 时,message 必须符合以下三个部分:

  1. header (或称 title;必要):一行就能理解 commit 的摘要
  2. body (非必要):详细说明内容,给 reviewer 看的讯息。
  3. footer (或称 note;非必要):说明解决了哪个 ticket。

<type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer>

Commit Message 格式注意事项

  • header 的 scope 括号使用英文半型,且与 type 紧连 (看起来像是个函式);冒号使用英文半型,且之后必须要有一个空白。
  • header 尽量控制在 50 字之内,太长则应该考虑精简叙述
  • 每行应该不超过 72 字距,太长则应该自行排版换行
  • header/body/footer 之间,应该空一行。
  • header 有严格的格式规范,必须用一行说明一个 commit 的目的 (见后面说明)。
  • body 内要敘述「做了什麼 (What)」和「為什麼做 (Why)」,而不要寫「如何做 (How)」
  • footer 说明完成了哪些 ticket
  • commit 本身应该就提供足够的资讯给 reviewer,不该在 merge request 内做额外说明。

范例

分支的多个提交历史:

// 分支为 `feat/JIRA-388-new-API-to-update-user-info` // 含有以下的提交 (只显示 header) * test(单元测试): 新增 WebAPI 测试

* update(Pods): 更新第三方套件 AFNetworking

* feat(API): 新增 update user 的 API,并实现

* feat(使用者 UI): 新增编辑使用者资讯的页面

* feat(缓存): 新增 APICache 类,并实现 cache 功能

* feat(默认图片): 无自定图片图片时,内定的头像图片

* chore(编译设定): info.plist 编译设定

* docs(README): 修改 README 文件叙述,完成 API 模组

或是参考 conventional-changelog 的提交历史

<type> 格式说明

跟 branch names 一样,采用以下的分类 (angular.js 的命名规范定义):

  • feat:变更功能、新开发需求、第三方库引入
  • fix:修复 bug (无论是在哪个主分支上修复)
  • add:增加文件 fi
  • refactor:重构、调整架构,不新增功能、不修复 bug (但可能会增加测试代码)
  • perf:增进效能,优化
  • test:增加测试为主 (可能伴随著重构)

以及新增以下允许的 types:

  • update (从原本的 feat 抽出):变更已存在的需求、第三方库更新
  • deprecated (从原本的 feat 抽出):废弃功能、第三方库。通常不直接删除,而是使用条件编译,或是将代码、资源搬至一个废弃资料夹,以备将来需要回复使用。

<scope> 格式说明

这个部分表明了变更范围。但好的 scope 应该要指出此改变会影响的范围,让代码审查者了解,让测试人员知道要测试什么,如动了缓存,则写缓存,改了支付模块,就写支付等,能迅速看到影响范围或者模块。

以下是一些建议:

  • 以简单的一个单字来叙述,越简洁越好
  • 可以用简写或是缩写来定义,只要大家知道就好
  • 同样一个 scope 应该大家都会用一样的 scope 叙述,大小写也应该一致 (不要用多个单字来解释同一个 scope)。
  • scope 的叙述不要含空白,若是英文单字,则使用骆驼式命名法 (Camel-Case)
  • 能够让其他开发者猜出你可能会修改的范围 (某个档案、或是某个资料夹 … 等等)
  • 能够让测试者比较有概念知道你修改代码影响的部份
  • 改了不同范围的东西,或许拆开成不同的 commit 来叙述会比较好。
  • 如果真的想不到一个专有名词,可以使用一个通称,例如 fix(err)、fix(bug)
  • 如果改的东西实在太杂,则可以写 (misc) (miscellaneous)。(不推荐)
  • 如果真的没有什么可以叙述改动范围的,那就不写 scope。(不推荐)

例如:

  • type 若是 test,scope 可能就是 UnitTest, UITest, BehaviorTest…
  • type 若是 perf,scope 可能就是 LoadingTime, MemoryFootprint…

<subject> 格式说明

  • 以动词和命令语气为开头 (add、delete、update、modify),而不要使用过去式、或动名词 (added、adding)
  • 开头不必大小;除了专有名词,尽量全小写
  • 句尾不必加上句号

注意事项

一个 commit 只会有一种代码集合

一个提交(commit)中应该包含有所有发布需要的代码和资源。

现在很多开发都会使用到第三方套件,并用自动化工具来管理。这些自动化工具可以设定第三方库依赖的最低版本,并提供了自动更新的机制。

若每次从一同个提交签出 (checkout) 时代码都不同 (例如依赖的远端库已经更新版本),那么执行结果可能就会和之前打包的有所不同,这样会增加厘清问题上的困难和额外的成本。

因此,在提交一个 commit 时,当下使用的第三方库的版本应该要固定,以确保任何时间签出编译的结果,永远会一致,得到一样的结果。

不该使用代码注释来控制打包

许多项目都会使用条件编译来控制编译条件 (例如 C macros)。例如在开发、测试以及上线版时,设定不同的访问伺服器的 URL、API keys 等。

但使用「注释 / 反注释 (comment/uncomment)」来决定打包时要采用哪些代码、变数设定,这个行为是不被允许的。因为这会带来一些问题:

  1. 每次发布时,要检查所有的变数是否有正确的注释 / 反注释。这样人为花费时间长,容易出错。
  2. 万一出错的时候,找问题的成本高,因为不确定当初编译时的注释是否正确。
  3. 无法达到自动化打包 (自动化工具不会更改代码)

因此,应该使用 scheme,而不该使用 comment/uncomment,来控制编译 / 打包的条件参数。

另外,若有部分代码需暂时移除,也应该使用条件编译,而非注解的方式移除。

不要任意变更共同开发的分支历史

  • 共同使用的分支 (尤其是主要分支),不应该任意变更历史,这样会发生同步后的开发分歧。
  • 所有主要分支,将变更推送到远端之前,请再三确认没有问题,因为推送之后,就变成了共同开发的远端分支,到时候任意变更容易带来麻烦。我们会强制设定一般开发者不能推送主分支,只能藉由 merge request 来合并进入主分支。
  • 如果要取消过去的某个 commit,使用 revert
  • 若非得修改共同使用的分支,应该在操作前和大家提醒,并先将代码合并。
  • 拉取远端代码时,永远使用 pull –rebase,而不要单纯使用 pull (采用 merge),避免拉取时因与远端分歧而产生意外的合并。

合并分支时采用 always rebase 和 always non-fast-forward merge

关于是否要使用 always rebase,还是单纯的使用 always merge,一直以来有两派的支持者,也各有优缺点。更多的议题讨论,可以参考这篇 “Git team workflows: merge or rebase?” 或是 “Getting solid at Git rebase vs. merge”。

使用 rebase 可以带来清楚的提交历史,并免多人开发时导致的历史混乱。但使用 rebase 有些注意事项,可以参考这篇「The Golden Rule of Rebasing」。

至于 always non-fast-forward merge,可以弥补 rebase 加上 fast-forward merge 形成单一线条的一个缺点:无法追踪一个开发的起始和结束。这也是 Git Flow 的标准。

不要使用 git add .,提交代码之前,应该自行 review

  • 不建议使用命令列使用 add/commit,建议使用图形化工具来执行 (例如 SourceTree)
  • 不要使用 git add . 操作,除非你已经自我 review 完所有需要的提交的内容
  • 尽量不要使用 git commit -m “…” 操作,commit message 应该要符合规范 (可能会有多行)
  • 所有的 add/commit 之前,都必须自我 review,包括:
  • review 档案:是否正确含有不该提交、或是忘记提交的档案 (包括图片等资源)。
  • review 代码:是否有不该提交、或是忘记修改的代码。
  • 绝大多数的错误,都是在自我 review 时就可以发现。

改变 git 提交历史的操作,必须在每步骤操作之后进行确认结果

  • 每次操作会改变提交历史的指令,都应该在操作后立刻检查是否操作成功
  • 尤其是初学者操作 add、commit、rebase、merge、pull,一定要在操作后检查。有问题就立刻排除。
  • 建议使用图形化工具检查,或是 git log –oneline –graph –decorate –all 检查。
正文完
 0