如何使用 git commit template 與 git hooks 管理團隊的 git log

為什麼需要規範團隊的 git log

在團隊開發中,我們常常會希望團隊遵循一個 git commit log 的規範,原因是我們希望在未來要查找之前的 log 時,可以透過這樣的方式可以很快的搜尋到想要的結果,也可以在 CI/CD 的流程中,透過規範的 git log 藉而產出一個有意義且能給 QA/PM/其他團隊成員觀看的 CHNAGELOG (版本更新內容)

如何管理與規範團隊的 git log

通常我們會規範一些 commit role 的文件 ,希望團隊成員能夠去遵守,但是在每次 commit 時,開發成員都需要去確保自己的 commit log 是否符合規範,是一件稍嫌困擾的事情,而且我們也不能確保每位成員都真的『 完全 』遵守我們的 commit 規範,這時候我們就可以利用 commit template 跟 git hooks 去達到讓成員 commit 時可以完全按照團隊的 commit role 跟確保這個 commit 是否完全符合規範。

關於 git commit template

在 git 中,我們可以設置模板文件,那麼當你每次 commit 的時候, git 會默認使用該文件的內容,例如:你創建了一個 template 文件 $HOME/.gitmessage.txt :

1
2
3
4
5
subject line

what happened

[ticket: X]

接著我們設置 commit.template :

1
2
$ git config --global commit.template $HOME/.gitmessage.txt
$ git commit

這樣子每次提交的時候,默認都會出現你設置的模板文件,在這邊可以透過這個文件,讓每個成員都能很快的遵守團隊的 commit role 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
subject line

what happened

[ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C

關於 git hooks

git hooks 就像名字敘述一樣,當某些重要事件發生時,Git 有方法可以觸發自訂腳本, 在每個 Git repository 中都有一個 .git/hooks 目錄,裡面的內容大概像這樣:

1
2
3
applypatch-msg.sample  pre-applypatch.sample      pre-push.sample
commit-msg.sample pre-commit.sample pre-rebase.sample
post-update.sample prepare-commit-msg.sample update.sample
  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • post-checkout
  • pre-rebase

上述為幾個較為有用的參考對應事件。完整的事件對應。

所以我們可以在每次commit之前,去檢查這次的 commit msg 是否符合我們的 commit role,透過 git hooks script 的用法,可以讓不符合規範的 commit msg 報錯,這樣在團隊中可以很有效的去規範團隊成員的 git msg。

這邊提供一個對應 Aangular Js 的 git hook script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/env python
"""
Git commit hook:
.git/hooks/commit-msg
Check commit message according to angularjs guidelines:
* https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
"""

import sys
import re

valid_commit_types = ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', ]
commit_file = sys.argv[1]
help_address = 'https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#'

with open(commit_file) as commit:
lines = commit.readlines()
if len(lines) == 0:
sys.stderr.write("\nEmpty commit message\n")
sys.stderr.write("\n - Refer commit guide: %s\n\n" % help_address)
sys.exit(1)

# first line
line = lines[0]
m = re.search('^(.*)\((.*)\): (.*)$', line)

if not m or len(m.groups()) != 3:
sys.stderr.write("\nFirst commit message line (header) does not follow format: type(scope): message\n")
sys.stderr.write("\n - Refer commit guide: %s\n\n" % help_address)
sys.exit(1)
commit_type, commit_scope, commit_message = m.groups()
if commit_type not in valid_commit_types:
sys.stderr.write("\nCommit type not in valid ones: %s\n" % ", ".join(valid_commit_types))
sys.stderr.write("\n - Refer commit guide: %s\n\n" % help_address)
sys.exit(1)

if len(lines) > 1 and lines[1].strip():
sys.stderr.write("\nSecond commit message line must be empty\n")
sys.stderr.write("\n - Refer commit guide: %s\n\n" % help_address)
sys.exit(1)

if len(lines) > 2 and not lines[2].strip():
sys.stderr.write("\nThird commit message line (body) must not be empty\n")
sys.stderr.write("\n - Refer commit guide: %s\n\n" % help_address)
sys.exit(1)

sys.exit(0)

當然, git hooks 還可以做到許多強大的功能,像是 lint 檢查,在 commit 前就運行單元測試,他本身就是一個非常強大的 git plugin ,在 CI/CD 的流程中,是非常有用的一個 git 功能,這次的介紹就到這邊。

參考 :