Githook 也稱 Git 鉤子,是在 Git 倉庫中特定事件發(fā)生時自動運行的腳本艇抠。它可以讓你自定義 Git 內(nèi)部的行為家淤,在開發(fā)周期中的關(guān)鍵點出發(fā)自定義行為瑟由。
Git Hook 最常見的使用場景包括推行提交信息規(guī)范歹苦,根據(jù)倉庫狀態(tài)來改變項目環(huán)境,和接入持續(xù)集成工作流。但是因為腳本可以完全定制痴施,你可以用 Git Hook 來自動化或者優(yōu)化你開發(fā)工作流中任意部分。
Git Hook 是倉庫中特定事件發(fā)生時 Git 自動運行的普通腳本动遭。因此 Git Hook 安裝和配置也非常容易神得。Hook 在本地或服務(wù)端倉庫都可以部署,且只會在倉庫中事件發(fā)生時被執(zhí)行宵蕉。
背景:想在每一次代碼commit的時候發(fā)送一封郵件到相關(guān)人員的郵箱
前提:閱讀以下文字需要有一定Git基礎(chǔ)的朋友羡玛,請參見之前的文章:五步法掌握Git基本操作
實驗環(huán)境:
Python3.5
Pycharm(最順手的IDE而已)
Windows系統(tǒng) Win7
- Hook 存在于每個 Git 倉庫的 .git/hooks 目錄中宗苍。當你初始化倉庫時讳窟,Git 自動生成這個目錄和一些示例腳本。你可以在某個 .git/hooks 中谋右,查看這些文件碌上,如下圖:
注:本地沒有g(shù)it倉庫的可以隨意git clone一個馏予,但是需要有權(quán)限可以做git commit天梧,好做之后的練習。
- 編寫腳本語言
內(nèi)置的腳本大多是 shell 和 perl 語言實現(xiàn)的霞丧,但你也可以使用任何腳本語言呢岗,只要它們最后能編譯到可執(zhí)行文件。每次腳本中 #!/bin/sh 定義了你的文件將如何被解釋蛹尝。
這次我們采用Python語言來實現(xiàn)GitHook后豫,在Linux系統(tǒng)下可以直接編寫Python腳本,但是在Windows系統(tǒng)下需要做一個小小的轉(zhuǎn)換突那。
1)新建一個shell腳本挫酿,取名為post-commit,內(nèi)容如下:
#!/bin/sh
python3 .git/hooks/post-commit.py
2)新建一個post-commit.py,里面編寫Hook中需要發(fā)送郵件的功能
注:上面一個文件中寫的python3是因為CC先生的Windows環(huán)境中同時有python2和python3(Python2和Python3共存)愕难,此處特意表明用python3來處理惫霸,否則就直接寫python即可。
內(nèi)容如下:
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from subprocess import check_output
#使用QQ郵箱做測試葱弟,填寫QQ的smtp服務(wù)器名稱
mail_host = "smtp.qq.com"
#替換成自己使用的QQ郵箱
mail_user = "***@qq.com"
#替換成自己使用的授權(quán)碼(非自己的QQ密碼)授權(quán)碼詳見壹店;http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
mail_pass = "*****"
#使用Python中的subprocess的check_output函數(shù)來捕獲運行了git命令后的標準輸出
log = check_output(['git', 'log', '-1', '-p']).decode()
m = log.split('\n',5)[4]
#分割字符串得到最后的一個參數(shù) email
arg = m.split(' ')[-1]
if arg[:6] == 'email:':
receiver = arg[6:]
print(receiver)
sender = mail_user
receivers = [receiver]
message = MIMEText(log)
message['From'] = Header(mail_user, 'utf-8')
message['To'] = Header(str(receivers), 'utf-8')
subject = 'This is a commit log for you!'
message['Subject'] = Header(subject, 'utf-8')
try:
smtpObj = smtplib.SMTP_SSL(mail_host, 465)
smtpObj.login(mail_user,mail_pass)
smtpObj.sendmail(sender, receivers, message.as_string())
smtpObj.quit()
print ("Send the diff email to:", receiver)
except smtplib.SMTPException as e:
print (e)
3.可以在git命令中嘗試GitHook
- 隨意改寫一個倉庫中的文件,比如README.md
$git add README.md
2)提交修改
$ git commit -m 'Update readme. email:xgengshax@msn.com'芝加,如下圖:
gitcommit.png
4.查看QQ郵箱已發(fā)送郵件(此處因為QQ郵箱的安全設(shè)置會收到發(fā)送失敗的提示郵件硅卢,不過這個表示Hook已經(jīng)成功,只是QQ的安全設(shè)置而已)
至此藏杖,我們已經(jīng)完成了只要git commit一次将塑,就會發(fā)送郵件的簡單功能。
回顧一下使用到的知識點:
- Git基礎(chǔ)知識
- Python對SMTP的使用
- Python中subprocess子進程的使用
拓展:
鉤子的作用域
對于任何 Git 倉庫來說 Hook 都是本地的制市,而且它不會隨著 git clone 一起復制到新的倉庫抬旺。而且因為鉤子是本地的,任何能接觸到倉庫的人都可以修改祥楣。對于開發(fā)團隊來說开财,這有很大的影響。所以在開發(fā)團隊中維護鉤子是比較復雜的误褪,因為 .git/hooks 目錄不隨你的項目一起拷貝责鳍,也不受版本控制影響。一個簡單的解決辦法是把你的 Hook 存在項目的實際目錄中(在 .git 外)兽间。這樣你就可以像其他文件一樣進行版本控制历葛。為了安裝 Hook ,你可以在 .git/hooks 中創(chuàng)建一個符號鏈接嘀略,或者簡單地在更新后把它們復制到 .git/hooks 目錄下恤溶。
本地 Hook 只影響它們所在的倉庫。以下是最常用的 6 個本地 >Hook:
pre-commit
prepare-commit-msg
commit-msg
post-commit
post-checkout
pre-rebase
前四個 Hook 介入到版本提交的生命周期帜羊,后兩個允許執(zhí)行一些額外的操作咒程,分別為 git checkout 和 git rebase 的安全檢查。所有與帶 pre- 的 Hook 代表即將發(fā)生的某個階段讼育,帶 post- 只用于通知帐姻。