Git 使用规范及操作流程

Git 使用规范

一、user.name 配置

Git 的 user.name 配置一定要使用自己的中文名称。命令行操作方式如下:

git config --global user.name "自己的中文名字"

二、Commit message 的作用

Git 每次提交代码,都要写 commit message(提交说明),否则就不允许提交。

$ git commit -m "hello world"

上面代码的 -m 参数,就是用来指定 commit mesage 的。

如果一行不够,可以只执行 git commit,就会跳出文本编译器,让你写多行。

$ git commit

但是,一般来说,commit message 应该清晰明了,说明本次提交的目的。


image

目前,社区有多种 Commit message 的写法规范。本文介绍 Angular 规范(见上图),这是目前使用最广的写法,比较合理和系统化,并且有配套的工具。

格式化的 Commit message,有几个好处。

(1)提供更多的历史信息,方便快速浏览。

比如,下面的命令显示上次发布后的变动,每个 commit 占据一行。你只看行首,就知道某次 commit 的目的。

$ git log  HEAD --pretty=format:%s
image

(2)可以过滤某些 commit(比如文档改动),便于快速查找信息。

比如,下面的命令仅仅显示本次发布新增加的功能。

$ git log  HEAD --grep feature

(3)可以直接从 commit 生成 Change log。

Change Log 是发布新版本时,用来说明与上一个版本差异的文档,详见后文。

image

三、Commit message 的格式

每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。

(): 
// 空一行

// 空一行

其中,Header 是必需的,Body 和 Footer 可以省略。

不管是哪一个部分,任何一行都不得超过 72 个字符(或 100 个字符)。这是为了避免自动换行影响美观。

3.1 Header

Header 部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。

(1)type

type 用于说明 commit 的类别,只允许使用下面 7 个标识。

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改 bug 的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

如果 typefeatfix,则该 commit 将肯定出现在 Change log 之中。其他情况(docschorestylerefactortest)由你决定,要不要放入 Change log,建议是不要。

(2)scope

scope 用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。

(3)subject

subject 是 commit 目的的简短描述,不超过 50 个字符。

  • 以动词开头,使用第一人称现在时,比如 change,而不是 changedchanges
  • 第一个字母小写
  • 结尾不加句号(.

3.2 Body

Body 部分是对本次 commit 的详细描述,可以分成多行。下面是一个范例。

More detailed explanatory text, if necessary.  Wrap it to 
about 72 characters or so. 

Further paragraphs come after blank lines.

- Bullet points are okay, too
- Use a hanging indent

有两个注意点。

(1)使用第一人称现在时,比如使用 change 而不是 changedchanges

(2)应该说明代码变动的动机,以及与以前行为的对比。

3.3 Footer

Footer 部分只用于两种情况。

(1)不兼容变动

如果当前代码与上一个版本不兼容,则 Footer 部分以 BREAKING CHANGE 开头,后面是对变动的描述、以及变动理由和迁移方法。

BREAKING CHANGE: isolate scope bindings definition has changed.

  To migrate the code follow the example below:

  Before:

  scope: {
    myAttr: 'attribute',
  }

  After:

  scope: {
    myAttr: '@',
  }

  The removed `inject` wasn't generaly useful for directives so there should be no code using it.

(2)关联 Redmine 上的 Issue

如果当前 commit 针对某个 issue,那么应该在 Header 部分关联这个 issue。

git commit -m "commit message (refs: #234)"

也可以一次关联多个 issue。

git commit -m "commit message (refs: #123, #245, #992)"

3.4 Revert

还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以 revert: 开头,后面跟着被撤销 Commit 的 Header。

revert: feat(pencil): add 'graphiteWidth' option

This reverts commit 667ecc1654a317a13331b17617d973392f415f02.

Body 部分的格式是固定的,必须写成 This reverts commit .,其中的 hash 是被撤销 commit 的 SHA 标识符。

如果当前 commit 与被撤销的 commit,在同一个发布(release)里面,那么它们都不会出现在 Change log 里面。如果两者在不同的发布,那么当前 commit,会出现在 Change log 的 Reverts 小标题下面。

四、Commitizen

Commitizen 是一个撰写合格 Commit message 的工具。

安装命令如下。

$ npm install -g commitizen

然后,在项目目录里,运行下面的命令,使其支持 Angular 的 Commit message 格式。

$ commitizen init cz-conventional-changelog --save --save-exact

以后,凡是用到 git commit 命令,一律改为使用 git cz。这时,就会出现选项,用来生成符合格式的 Commit message。

image

五、validate-commit-msg

validate-commit-msg 用于检查 Node 项目的 Commit message 是否符合格式。

它的安装是手动的。首先,拷贝下面这个 JS 文件,放入你的代码库。文件名可以取为 validate-commit-msg.js

接着,把这个脚本加入 Git 的 hook。下面是在 package.json 里面使用 ghooks,把这个脚本加为 commit-msg 时运行。

"config": {
  "ghooks": {
     "commit-msg": "./validate-commit-msg.js"
  }
}

然后,每次 git commit 的时候,这个脚本就会自动检查 Commit message 是否合格。如果不合格,就会报错。

$ git add -A 
$ git commit -m "edit markdown" 
INVALID COMMIT MSG: does not match "(): " ! was: edit markdown

六、生成 Change log

如果你的所有 Commit 都符合 Angular 格式,那么发布新版本时, Change log 就可以用脚本自动生成。

生成的文档包括以下三个部分。

  • New features
  • Bug fixes
  • Breaking changes.

每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。

conventional-changelog 就是生成 Change log 的工具,运行下面的命令即可。

$ npm install -g conventional-changelog-cli
$ cd my-project
$ conventional-changelog -p angular -i CHANGELOG.md -w

上面命令不会覆盖以前的 Change log,只会在 CHANGELOG.md 的头部加上自从上次发布以来的变动。

如果你想生成所有发布的 Change log,要改为运行下面的命令。

$ conventional-changelog -p angular -i CHANGELOG.md -w -r 0

为了方便使用,可以将其写入 package.jsonscripts 字段。

{
  "scripts": {
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0"
  }
}

以后,直接运行下面的命令即可。

$ npm run changelog

七、commit 提交规范

每个提交要保证适当的颗粒度相关性独立性

  • 以一个小功能、小改进或一个 bug fix 为单位
  • 对应的 unit test 程序在同一个 commit
  • 无相关的修改不在同一个 commit
  • 语法错误的半成品程序不能 commit

八、Git 操作流程

团队开发中,遵循一个合理、清晰的 Git 使用流程,是非常重要的。否则,每个人都提交一堆杂乱无章的 commit,项目很快就会变得难以协调和维护。下面是推荐的 Git 使用规范流程。

[图片上传失败...(image-267134-1556241991938)]

第 1 步:新建分支

首先,每次开发新功能或修复 Bug,都应该新建一个单独的分支。

# 获取主干最新代码
$ git checkout develop
$ git pull --rebase

# 新建一个开发分支 branch-name
$ git checkout -b branch-name develop

注意:
branch-name 的命名规如下:

  • 功能开发,branch-name 应为 feat-n。feat 是 feature(功能)的前四个字母,n 是一个数值对应于 Redmine 上功能编号,中间用横线连接。例如:feat-30,如下图所示:
  • Bug 修复,branch-name 应为 fix-n。fix 是修复的意思,n 是一个数值对应于 Redmine 上 Bug 编号,中间用横线连接。例如:fix-31.

第 2 步:提交分支 commit

分支修改后,就可以提交 commit 了。

$ git add .
$ git status
$ git commit --verbose

git add 命令的 all 参数,表示保存所有变化(包括新建、修改和删除)。从 Git 2.0 开始,all 是 git add 的默认参数,所以也可以用 git add . 代替。

git status 命令,用来查看发生变动的文件。

git commit 命令的 verbose 参数,会列出 diff 的结果。

第 3 步:撰写提交信息

Git commit message 的撰写规范,请参考:[[kmc:Commit message 和 Change log 编写规范]]

第 4 步:与主干同步

分支的开发过程中,要经常与主干保持同步。

$ git checkout develop
$ git pull --rebase

第 5 步:合并 commit

分支开发完成后,很可能有一堆 commit,但是合并到主干的时候,往往希望只有一个(或最多两三个)commit,这样不仅清晰,也容易管理。

那么,怎样才能将多个 commit 合并呢?这就要用到 git rebase 命令。

$ git checkout branch-name
$ git rebase -i HEAD~n

git rebase 命令的 i 参数表示互动(interactive),这时 git 会打开一个互动界面,进行下一步操作。n 代表变基操作的提交数量。

下面采用 Tute Costa 的例子,来解释怎么合并 commit。

pick 07c5abd Introduce OpenPGP and teach basic usage
pick de9b1eb Fix PostChecker::Post#urls
pick 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

# Rebase 8db7e8b..fa20af3 onto 8db7e8b
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

上面的互动界面,先列出当前分支最新的 4 个 commit(越下面越新)。每个 commit 前面有一个操作命令,默认是pick,表示该行 commit 被选中,要进行 rebase 操作。

4 个 commit 的下面是一大堆注释,列出可以使用的命令。

  • pick:正常选中
  • reword:选中,并且修改提交信息;
  • edit:选中,rebase 时会暂停,允许你修改这个 commit
  • squash:选中,会将当前 commit 与上一个 commit 合并
  • fixup:与 squash 相同,但不会保存当前 commit 的提交信息
  • exec:执行其他 shell 命令

上面这 6 个命令当中,squash 和 fixup 可以用来合并 commit。先把需要合并的 commit 前面的动词,改成squash(或者s)。

pick 07c5abd Introduce OpenPGP and teach basic usage
s de9b1eb Fix PostChecker::Post#urls
s 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

这样一改,执行后,当前分支只会剩下两个 commit。第二行和第三行的 commit,都会合并到第一行的 commit。提交信息会同时包含,这三个 commit 的提交信息。

# This is a combination of 3 commits.
# The first commit's message is:
Introduce OpenPGP and teach basic usage

# This is the 2nd commit message:
Fix PostChecker::Post#urls

# This is the 3rd commit message:
Hey kids, stop all the highlighting

如果将第三行的 squash 命令改成 fixup 命令。

pick 07c5abd Introduce OpenPGP and teach basic usage
s de9b1eb Fix PostChecker::Post#urls
f 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

运行结果相同,还是会生成两个 commit,第二行和第三行的 commit,都合并到第一行的 commit。但是,新的提交信息里面,第三行 commit 的提交信息,会被注释掉。

# This is a combination of 3 commits.
# The first commit's message is:
Introduce OpenPGP and teach basic usage

# This is the 2nd commit message:
Fix PostChecker::Post#urls

# This is the 3rd commit message:
# Hey kids, stop all the highlighting

第 6 步:推送到远程仓库

合并 commit 后,就可以推送当前分支到远程仓库了。

$ git push --force origin branch-name

git push 命令要加上 force 参数,因为 rebase 以后,分支历史改变了,跟远程分支不一定兼容,有可能要强行推送。

第 7 步:发出 Pull Request

提交到远程仓库以后,就可以发出 Pull Request 将分支合并到 develop 分支,发起 Pull Ruquest 之后,可以做两件事情:Bug 回归测试和 Code Review。

  • Bug 回归测试。这是可选的,当分支是 Bug 修复分支(fix-m)时,需要做回归测试,回归测试通过,才能 Merge

  • 但是,当分支是功能开发分支(feat-n)时,不需要做 Bug 回归测试,但是开发人员需要自己保证代码是经过测试的

  • Code Review。不管分支是 Bug 修复分支还是功能开发分支,都需要利用开发规范对提交的代码进行静态检查。

  • 在 Pull Request 页面,项目组的其他开发人员对程序代码Git commit 注释,进行检查和审核.

  • 如果有问题,需要在相应分支上做修改代码或者 Git 变基操作

  • 注意,在合并代码之前,开发人员如果收到 develop 分支上其他分支的 Merge 事件,应该主动在本地仓库的分支上执行如下命令:

git rebase develop
git push -f branch-name

第 8 步:合并 Pull Request

一旦检查完毕,没有问题,则进行合并操作。注意,合并操作,不应该由提交代码的开发人员本人进行合并,而是应该由其他人进行合并。而且,在合并之前,应该在 Pull Request 备注文字,例如:本次提交的代码,经检查没有问题,可以合并。

九、如何提高 PR 流程的效率

PR(Pull Request)的意义重大,因为有了 PR 这个缓冲,代码在合并到主干之前可以进行 Code Review,有了 Code Review,开发人员的技术能力就有了提升的空间。否则,不管代码是否规范,直接提交到版本仓库中,没有任何回旋的余地。有了 PR,也可以有效的减少冲突代码的互相覆盖。虽然 PR 有诸多好处,但是很多开发人员的了解 PR 的第一反应就是降低了开发流程的效率。其实 PR 没有真正降低效率,想象一下,如果没有 PR,开发人员提交代码导致了代码的覆盖和丢失,寻找丢失和覆盖的代码是不是效率更低呢?至于如何开展 PR,见上面的 Git 流程介绍。下面谈几点提高 PR 流程效率的技巧:

  1. 尽早解决冲突
    当发出 PR 后,GitHub 会立刻检查当前分支和长期分支是否有代码冲突(如下图所示)。一旦有冲突发生,是无法完成代码合并的。这个冲突状态是 GitHub 很快能够提示出来的,所以,开发人员在发起 PR 之后,应该在 PR 的页面上等待页面提示是否有冲突的信息出现,如果发现有代码冲突,应该第一时间去解决代码冲突。在确保 PR 中没有冲突的情况下,再继续 PR 的后续流程。

  2. 主动要求 Code Review
    当发出 PR 后,一般情况下,项目所有参与者都会收到邮件提醒,但是邮件提醒是有时间间隔的。所以,如果发出 PR 后,可以主动把 PR 页面的 URL 地址,通过企业微信或者 QQ 发送给项目组成员。或者直接发送给高杨、王树贤或者王顶,要求 Code Review。当然,如果 PR 是 bug 修复,应该同时把 PR 页面的 URL 链接发送给测试人员,要求测试人员进行测试,测试通过后,测试人员应该在 PR 页面上备注测试是否通过的信息。测试和 Code Review 可以同时开展,这样可以提高流程的效率。
    总结一下:在企业的任何工作流程中,提高效率的关键要点无非三个:一是减少流程中间的等待时间,二是尽量提高任务并行的程度,减少任务串行的程度,三是尽量减少不必要的重复或者任务。

你可能感兴趣的:(Git 使用规范及操作流程)