如何使用 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 templategit 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 Jsgit 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 功能,這次的介紹就到這邊。

參考 :