一個維護版本日誌整潔的Git提交規範

1 關於提交日誌規範

良好的Commit Message有利於代碼審查,能更快速查找變動記錄,而且能夠直接生成Change log。html

Commit Message的寫法規範:conventional-changelog 爲了規範代碼提交的說明,這裏咱們使用angular的規範寫法:前端

<type>(<scope>): <subject>
<空行>
<body>
<空行>
<footer>
複製代碼

其中 head((): )是必須的,body和footer是可選的。 若是隻須要輸入header,能夠直接使用:java

git commit -m
複製代碼

命令提交。linux

若是須要輸入body、footer這樣的多行日誌,須要輸入:git

git commit
複製代碼

跳出文本編輯器進行編寫。github

1.1 Header

1.1.1 Type

commit的類別,包涵如下七種:shell

feat:新功能(feature)
fix:修補bug
docs:文檔(documentation)
style: 格式(不影響代碼運行的變更)
refactor:重構(即不是新增功能,也不是修改bug的代碼變更)
test:增長測試
chore:構建過程或輔助工具的變更
複製代碼

1.1.2 Scope

commit的影響範圍,好比會影響到哪一個模塊/性能/哪一層(業務層,持久層,緩存,rpc),若是是特性代碼,能夠寫特性名稱express

1.1.3 Subject

commit的簡短描述,不超過50個字符。npm

  • 使用如今式,祈使句
  • 第一個字母無需大寫
  • 結尾不用加句號

1.2 Body

跟subject同樣,使用如今式,祈使句。應該說明提交代碼的動機,以及跟前一個版本的對比。segmentfault

1.3 Footer

Foot包含能夠包含如下信息:

1.3.1 描述重大變動的信息

以 BREAKING CHANGE 開頭,後面是變動的具體描述,如

BREAKING CHANGE: isolate scope bindings definition has changed and
    the inject option for the directive controller injection was removed.

    To migrate the code follow the example below:

    Before:

    scope: {
      myAttr: 'attribute',
      myBind: 'bind',
      myExpression: 'expression',
      myEval: 'evaluate',
      myAccessor: 'accessor'
    }

    After:

    scope: {
      myAttr: '@',
      myBind: '@',
      myExpression: '&',
      // myEval - usually not useful, but in cases where the expression is assignable, you can use '='
      myAccessor: '=' // in directive's template change myAccessor() to myAccessor } The removed `inject` wasn't generaly useful for directives so there should be no code using it.
複製代碼

1.3.2 關閉JIRA

如:

Closes DB-1001, DB1002
複製代碼

1.4 一些 Commit Message 例子:

feat($browser): onUrlChange event (popstate/hashchange/polling)

Added new event to $browser:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available

Breaks $browser.onHashChange, which was removed (use onUrlChange instead)

---------

fix($compile): couple of unit tests for IE9

Older IEs serialize html uppercased, but IE9 does not...
Would be better to expect case insensitive, unfortunately jasmine does
not allow to user regexps for throw expectations.

Closes #392
Breaks foo.bar api, foo.baz should be used instead

---------

eat(directive): ng:disabled, ng:checked, ng:multiple, ng:readonly, ng:selected

New directives for proper binding these attributes in older browsers (IE).
Added coresponding description, live examples and e2e tests.

Closes #351

---------

feat($compile): simplify isolate scope bindings

Changed the isolate scope binding options to:
  - @attr - attribute binding (including interpolation)
  - =model - by-directional model binding
  - &expr - expression execution binding

This change simplifies the terminology as well as
number of choices available to the developer. It
also supports local name aliasing from the parent.

BREAKING CHANGE: isolate scope bindings definition has changed and
the inject option for the directive controller injection was removed.

To migrate the code follow the example below:

Before:

scope: {
  myAttr: 'attribute',
  myBind: 'bind',
  myExpression: 'expression',
  myEval: 'evaluate',
  myAccessor: 'accessor'
}

After:

scope: {
  myAttr: '@',
  myBind: '@',
  myExpression: '&',
  // myEval - usually not useful, but in cases where the expression is assignable, you can use '='
  myAccessor: '=' // in directive's template change myAccessor() to myAccessor } The removed `inject` wasn't generaly useful for directives so there should be no code using it.

複製代碼

若是是特性開發,則能夠這樣:

feat(短視頻播放優化): 全屏播放動畫效果優化
複製代碼

2 提交日誌自動校驗

在NodeJS項目中,咱們能夠經過使用 ghooks + validate-commit-msg進行提交日誌校驗,校驗不經過的將被拒絕提交。原理是經過NodeJs項目編譯,把NodeJS的校驗腳本寫到.git/hooks/目錄下的勾子文件中,這樣每次執行git commit命令都會執行這個校驗,不過這種方式依賴於Node環境,而且每一個Git項目都須要引入對應的npm模塊進行編譯,對於比較多微服務項目的狀況來講使用不太方便。

爲此,編寫了git-hook-maven-plugin插件, 該插件有以下特色:

  • 很方便的在項目中自定義團隊的工做流, 把自定義鉤子鉤子腳本歸入git管理類, 方便團隊共享;
  • 把鉤子腳本的安裝集成到Maven的生命週期中的某個階段, 方便的經過項目編譯自動安裝或者升級腳本;
  • 提供通用的內置腳本, 方便鉤子的配置, 目前只提供了validate-commit-message鉤子腳本, 用於提交日誌的規範, 遵循AngularJS Git Commit Message Conventions的格式。

具體安裝參考說明文檔

配置完這個,當咱們經過maven編譯完項目以後,下一次提交代碼,若是提交日誌不符合規範,則會報錯:

➜  project-1 git:(master) ✗ git commit -m "test"

Commit log error: First commit message line (commit header) does not follow format: type(scope): subject
 - Refer commit guide: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
複製代碼

3 特性開發提交壓縮合並

對於獨自完成的特性,可能在開發過程當中會產生多個提交,爲了讓提交整潔,須要對這個特性的全部提交進行壓縮合並。咱們先看看壓縮合並以前的代碼:

* be6e32d (HEAD->master)feat(測試提交): 修改第二個文件
* 4a7615e feat(測試提交): 修改第一個文件
* 721064e feat(測試提交): 提交第四個文件
* e20968e feat(測試提交): 提交第三個文件
* b7160b3 feat(測試提交): 提交第二個文件
* 0c90fcl feat(測試提交): 提交第一個文件
* e618321 fix(頁面展現): 展現錯誤修復
複製代碼

如圖,能夠發現壓縮合並測試特性有多個提交,能夠進行合併,如今準備把e618321前面的提交都進行合併,執行git rebase -i命令進行壓縮合並:

git rebase -i e618321

其中命令後面的hash值是壓縮合並開始的那個提交的hash值:

pick 0c90fcl feat (測試提交): 提交第一個文件
pick b7160b3 feat(測試提交): 提交第二個文件
pick e20968e feat(測試提交): 提交第三個文件
pick 721064e feat(測試提交): 提交第四個文件
pick 4a7615e feat(測試提交): 修改第一個文件
pick be6e32d feat(測試提交): 修改第二個文件

# Rebase e618321..be6e32d onto e618321 (6 command(s))
#
# 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
# d, drop = remove commit
#
# 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
複製代碼

注意:這個界面裏面的提交是按照提交時間順序往下排的,最新提交的在最後面,跟git lg的相反,平時查看日誌是最新提交的排在最前面。

咱們把低2行到6行改成 s(squash),第一個行改成 r(reword),把第2到6行合併到第一個提交裏面,調整下提交信息:

r 0c90fcl feat (測試提交): 提交第一個文件
s b7160b3 feat(測試提交): 提交第二個文件
s e20968e feat(測試提交): 提交第三個文件
s 721064e feat(測試提交): 提交第四個文件
s 4a7615e feat(測試提交): 修改第一個文件
s be6e32d feat(測試提交): 修改第二個文件
複製代碼

而後輸 :wq 保存並退出編輯模式繼續處理。

若是遇到有衝突,須要解決完衝突以後,修改衝突的提交日誌。

最後是一個壓縮合並以後的提交日誌確認界面,看看第一行的日誌是否符合咱們的需求,沒有問題則輸入 :wq 保存並退出編輯模式。

# This is acombination of 7commits.
# The first commit'smessage is:
feat(測試提交): 測試代碼

# This is the 2nd commit message:

feat(測試提交): 提交第二個文件

# This is the 3rd commit message:

feat(測試提交): 提交第三個文件
複製代碼

這樣咱們就合併完成了,再次查看提交日誌,發現已經合併程了一個提交:

* eb0121a (HEAD->master) feat(測試提交): 測試代碼
* e618321 fix(頁面展現): 展現錯誤修復
複製代碼

注:git lg中 lg = log --graph --oneline --decorate,特別注意,本次演示代碼直接在master上面進行,實際上須要在 feature-xxx 分支上面進行。

提交代碼和壓縮合並的原則:

開發過程當中的提交代碼原則: 儘可能減小commit的次數; 在push以前,須要把本次特性全部的代碼都壓縮成一個提交; 在提交代碼審查以前,最好把本次特產壓縮成一個提交

4 合併master代碼使用 rebase

假設咱們開發一個新的特性,而且已經把代碼進行了壓縮合並,提交日誌以下:

* 69b4ffb (HEAD -> feature-test) feat(測試特性): 測試特性代碼
* eb0121a (HEAD->master) feat(測試提交): 測試代碼
* e618321 fix(頁面展現): 展現錯誤修復
複製代碼

而此時,master代碼也有了新的修復代碼提交:

* 69b4ffb (HEAD -> master) fix(緩存): 修復產品接口緩存bug
* eb0121a (HEAD->master) feat(測試提交): 測試代碼
* e618321 fix(頁面展現): 展現錯誤修復
複製代碼

爲了保持合併以後,咱們當前特性點仍然在提交日誌的最新位置,達成效果以下:

咱們使用rebase進行合併代碼:

git rebase master

合併以後效果以下,咱們當前特性分支的提交仍然在最前面:

* 69b4ffb (HEAD -> feature-test) feat(測試特性): 測試特性代碼
* 69b4ffb (HEAD -> master) fix(緩存): 修復產品接口緩存bug
* eb0121a (HEAD->master) feat(測試提交): 測試代碼
* e618321 fix(頁面展現): 展現錯誤修復
複製代碼

rebase代碼原則:

特性分支合併master代碼使用 rebase,總讓當前特性處於最近提交; 若是一個特性有多個同事開發,rebase以前記得讓其餘同事提交全部代碼,rebase以後記得讓其餘同事強制更新本地代碼;

References

Git 提交的正確姿式:Commit message 編寫指南 你可能會忽略的 Git 提交規範 Git鉤子:自定義你的工做流 用 Node.js 寫前端本身的 Git-hooks gist.github.com/jasonrobert…

Bash in Linux v.s Mac OS

GitUntrackedFilesMojo

首次發佈於:一個維護版本日誌整潔的Git提交規範

相關文章
相關標籤/搜索