Git Hooks 在 IOS開發(fā)的應(yīng)用

1.什么是 Git Hooks

如同其他許多的版本控制系統(tǒng)一樣,Git 也具有在特定事件發(fā)生之前或之后執(zhí)行特定腳本代碼功能(從概念上類比,就與監(jiān)聽事件、觸發(fā)器之類的東西類似)。Git Hooks 就是那些在Git執(zhí)行特定事件(如commit、push、receive等)后觸發(fā)運(yùn)行的腳本。

Git鉤子最常見的使用場景包括推行提交規(guī)范,根據(jù)倉庫狀態(tài)改變項(xiàng)目環(huán)境,和接入持續(xù)集成工作流。但是,因?yàn)槟_本可以完全定制,你可以用Git鉤子來自動化或者優(yōu)化你開發(fā)工作流中任意部分。

2.Git Hooks 能做什么

Git Hooks是定制化的腳本程序,所以它實(shí)現(xiàn)的功能與相應(yīng)的git動作相關(guān),如下幾個簡單例子:

1.多人開發(fā)代碼語法、規(guī)范強(qiáng)制統(tǒng)一

2.commit message 格式化、是否符合某種規(guī)范

3.如果有需要,測試用例的檢測

4.服務(wù)器代碼有新的更新的時候通知所有開發(fā)成員

5.代碼提交后的項(xiàng)目自動打包(git receive之后) 等等...

更多的功能可以按照生產(chǎn)環(huán)境的需求寫出來

3.Git Hooks 是如何工作的

每一個使用了 git 的工程下面都有一個隱藏的 .git 文件夾。

一個工程下面的.git
一個工程下面的.git

掛鉤都被存儲在 .git 目錄下的 hooks 子目錄中,即大部分項(xiàng)目中的 .git/hooks。 如下圖:

一個工程下面的.git
一個工程下面的.git

Git 默認(rèn)會放置一些腳本樣本在這個目錄中,除了可以作為掛鉤使用,這些樣本本身是可以獨(dú)立使用的。所有的樣本都是shell腳本,其中一些還包含了Perl的腳本。不過,任何正確命名的可執(zhí)行腳本都可以正常使用 ,也可以用Ruby或Python,或其他腳本語言。

上圖是git 初始化的時候生成的默認(rèn)鉤子,已包含了大部分可以使用的鉤子,但是 .sample 拓展名防止它們默認(rèn)被執(zhí)行。為了安裝一個鉤子,你只需要去掉 .sample 拓展名。或者你要寫一個新的腳本,你只需添加一個文件名和上述匹配的新文件,去掉.sample拓展名。把一個正確命名且可執(zhí)行的文件放入 Git 目錄下的 hooks子目錄中,可以激活該掛鉤腳本,之后他一直會被 Git 調(diào)用。

一個簡單的 Hooks 例子

使用shell 這里嘗試寫一個簡單的鉤子,安裝一個 prepare-commit-msg 鉤子。去掉腳本的 .sample 拓展名,在文件中加上下面這兩行:

#!/bin/sh

echo "# Please include a useful commit message!" > $1

鉤子需要能被執(zhí)行,所以如果你創(chuàng)建了一個新的腳本文件,你需要修改它的文件權(quán)限。比如說,為了確保prepare-commit-msg可執(zhí)行,運(yùn)行下面這個命令:

chmod + x prepare-commit-msg

接下來你每次運(yùn)行g(shù)it commit時,你會看到默認(rèn)的提交信息都被替換了。

內(nèi)置的樣例腳本是非常有用的參考資料,因?yàn)槊總€鉤子傳入的參數(shù)都有非常詳細(xì)的說明(不同鉤子不一樣)。

腳本語言

git自己生成的默認(rèn)鉤子的腳本大多是shell和Perl語言的,但你可以使用任何腳本語言,只要它們最后能編譯到可執(zhí)行文件。每次腳本中的 #!/bin/sh 定義了你的文件將被如何解析。比如,使用其他語言時你只需要將path改為你的解釋器的路徑。

比如說,你可以在 prepare-commit-msg 中寫一個可執(zhí)行的Python腳本。下面這個鉤子和上一節(jié)的shell腳本做的事完全一樣。

#!/usr/bin/env python

import sys, os

commit_msg_filepath = sys.argv[1]
with open(commit_msg_filepath, 'w') as f:
    f.write("# Please include a useful commit message!")

注意第一行改成了python解釋器的路徑。此外,這里用sys.argv[1]而不是$1來獲取第一個參數(shù)。這個特性非常強(qiáng)大,因?yàn)槟憧梢杂萌魏文阆矚g的語言來編寫Git鉤子。

鉤子的作用域

對于任何Git倉庫來說鉤子都是本地的,而且它不會隨著git clone一起復(fù)制到新的倉庫。而且,因?yàn)殂^子是本地的,任何能接觸得到倉庫的人都可以修改。在開發(fā)團(tuán)隊(duì)中維護(hù)鉤子是比較復(fù)雜的,因?yàn)?git/hooks目錄不隨你的項(xiàng)目一起拷貝,也不受版本控制影響。一個簡單的解決辦法是把你的鉤子存在項(xiàng)目的實(shí)際目錄中(在.git外)。這樣你就可以像其他文件一樣進(jìn)行版本控制。

作為備選方案,Git同樣提供了一個模板目錄機(jī)制來更簡單地自動安裝鉤子。每次你使用 git init 或 git clone 時,模板目錄文件夾下的所有文件和目錄都會被復(fù)制到.git文件夾。

4.客戶端 Hooks

客戶端鉤子只影響它們所在的本地倉庫。有許多客戶端掛鉤,以下把他們分為:提交工作流掛鉤、電子郵件工作流掛鉤及其他客戶端掛鉤。

1.提交工作流掛鉤

commit操作有 4個掛鉤被用來處理提交的過程,他們的觸發(fā)時間順序如下:

pre-commit、prepare-commit-msg、commit-msg、post-commit

commit操作最前和最后的兩個鉤子執(zhí)行時間如下圖:

pre-commit

pre-commit 掛鉤在鍵入提交信息前運(yùn)行,最先觸發(fā)運(yùn)行的腳本。被用來檢查即將提交的代碼快照。例如,檢查是否有東西被遺漏、運(yùn)行一些自動化測試、以及檢查代碼規(guī)范。當(dāng)從該掛鉤返回非零值時,Git 放棄此次提交,但可以用 git commit --no-verify 來忽略。該掛鉤可以被用來檢查代碼錯誤,檢查代碼格式規(guī)范,檢查尾部空白(默認(rèn)掛鉤是這么做的),檢查新方法(譯注:程序的函數(shù))的說明。

pre-commit 不需要任何參數(shù),以非零值退出時將放棄整個提交。這里,我們用 “強(qiáng)制代碼格式校驗(yàn)” 來說明 (見第6點(diǎn))。

prepare-commit-msg

prepare-commit-msg 掛鉤在提交信息編輯器顯示之前,默認(rèn)信息被創(chuàng)建之后運(yùn)行,它和 pre-commit 一樣,以非零值退出會放棄提交。因此,可以有機(jī)會在提交作者看到默認(rèn)信息前進(jìn)行編輯。該掛鉤接收一些選項(xiàng):擁有提交信息的文件路徑,提交類型。例如和提交模板配合使用,以編程的方式插入信息。提交信息模板的提示修改在上面已經(jīng)看到了,現(xiàn)在我們來看一個更有用的腳本。在處理需要單獨(dú)開來的bug時,我們通常在單獨(dú)的分支上處理issue。如果你在分支名中包含了issue編號,你可以使用prepare-commit-msg鉤子來自動地將它包括在那個分支的每個提交信息中。

#!/usr/bin/env python

import sys, os, re
from subprocess import check_output

# 收集參數(shù)
commit_msg_filepath = sys.argv[1]
if len(sys.argv) > 2:
    commit_type = sys.argv[2]
else:
    commit_type = ''
if len(sys.argv) > 3:
    commit_hash = sys.argv[3]
else:
    commit_hash = ''

print "prepare-commit-msg: File: %s\nType: %s\nHash: %s" % (commit_msg_filepath, commit_type, commit_hash)

# 檢測我們所在的分支
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
print "prepare-commit-msg: On branch '%s'" % branch

# 用issue編號生成提交信息
if branch.startswith('issue-'):
    print "prepare-commit-msg: Oh hey, it's an issue branch."
    result = re.match('issue-(.*)', branch)
    issue_number = result.group(1)

    with open(commit_msg_filepath, 'r+') as f:
        content = f.read()
        f.seek(0, 0)
        f.write("ISSUE-%s %s" % (issue_number, content))

首先,上面的 prepare-commit-msg 鉤子告訴你如何收集傳入腳本的所有參數(shù)。接下來,它調(diào)用了git symbolic-ref --short HEAD 來獲取對應(yīng)HEAD的分支名。如果分支名以issue-開頭,它會重寫提交信息文件,在第一行加上issue編號。比如你的分支名issue-224,下面的提交信息將會生成:

ISSUE-224 

# Please enter the commit message for your changes. Lines starting 
# with '#' will be ignored, and an empty message aborts the commit. 
# On branch issue-224 
# Changes to be committed: 
# modified:   test.txt

有一點(diǎn)要記住的是即使用戶用-m傳入提交信息,prepare-commit-msg也會運(yùn)行。也就是說,上面這個腳本會自動插入ISSUE-[#]字符串,而用戶無法更改。你可以檢查第二個參數(shù)是否是提交類型來處理這個情況。但是,如果沒有-m選項(xiàng),prepare-commit-msg鉤子允許用戶修改生成后的提交信息。所以這個腳本的目的是為了方便,而不是推行強(qiáng)制的提交信息規(guī)范。如果你要這么做,你需要下面所講的 commit-msg 鉤子。

commit-msg

commit-msg鉤子和prepare-commit-msg鉤子很像,但它會在用戶輸入提交信息之后被調(diào)用。這適合用來提醒開發(fā)者他們的提交信息不符合你團(tuán)隊(duì)的規(guī)范。傳入這個鉤子唯一的參數(shù)是包含提交信息的文件名。如果它不喜歡用戶輸入的提交信息,它可以在原地修改這個文件(和prepare-commit-msg一樣),或者它會以非零值退出,放棄這個提交。比如說,下面這個腳本確認(rèn)用戶沒有刪除prepare-commit-msg腳本自動生成的ISSUE-[#]字符串。

#!/usr/bin/env python

import sys, os, re
from subprocess import check_output

# 收集參數(shù)
commit_msg_filepath = sys.argv[1]

# 檢測所在的分支
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
print "commit-msg: On branch '%s'" % branch

# 檢測提交信息,判斷是否是一個issue提交
if branch.startswith('issue-'):
    print "commit-msg: Oh hey, it's an issue branch."
    result = re.match('issue-(.*)', branch)
    issue_number = result.group(1)
    required_message = "ISSUE-%s" % issue_number

    with open(commit_msg_filepath, 'r') as f:
        content = f.read()
        if not content.startswith(required_message):
            print "commit-msg: ERROR! The commit message must start with '%s'" % required_message
            sys.exit(1)
post-commit

post-commit 掛鉤在整個提交過程完成后運(yùn)行,他不會接收任何參數(shù),但可以運(yùn)行 git log 來獲得最后的提交信息。總之,該掛鉤是作為通知之類使用的。雖然可以用post-commit來觸發(fā)本地的持續(xù)集成系統(tǒng),但大多數(shù)時候你想用的是post-receive這個鉤子。它運(yùn)行在服務(wù)端而不是用戶的本地機(jī)器,它同樣在任何開發(fā)者推送代碼時運(yùn)行。那里更適合進(jìn)行持續(xù)集成。

提交工作流的客戶端掛鉤腳本可以在任何工作流中使用,他們經(jīng)常被用來實(shí)施某些策略,但值得注意的是,這些腳本在clone期間不會被傳送。可以在服務(wù)器端實(shí)施策略來拒絕不符合某些策略的推送,但這完全取決于開發(fā)者在客戶端使用這些腳本的情況。所以,這些腳本對開發(fā)者是有用的,由他們自己設(shè)置和維護(hù),而且在任何時候都可以覆蓋或修改這些腳本,后面講如何把這部分東西也集成到開發(fā)流中。

2.E-mail工作流掛鉤

有3個可用的客戶端掛鉤用于e-mail工作流。當(dāng)運(yùn)行 git am 命令時,會調(diào)用他們,因此,如果你沒有在工作流中用到此命令,可以跳過本節(jié)。如果你通過e-mail接收由 git format-patch 產(chǎn)生的補(bǔ)丁,這些掛鉤也許對你有用。

首先運(yùn)行的是 applypatch-msg 掛鉤,他接收一個參數(shù):包含被建議提交信息的臨時文件名。如果該腳本非零退出,Git 放棄此補(bǔ)丁。可以使用這個腳本確認(rèn)提交信息是否被正確格式化,或讓腳本編輯信息以達(dá)到標(biāo)準(zhǔn)化。

下一個在 git am 運(yùn)行期間調(diào)用是 pre-applypatch 掛鉤。該掛鉤不接收參數(shù),在補(bǔ)丁被運(yùn)用之后運(yùn)行,因此,可以被用來在提交前檢查快照。你能用此腳本運(yùn)行測試,檢查工作樹。如果有些什么遺漏,或測試沒通過,腳本會以非零退出,放棄此次 git am 的運(yùn)行,補(bǔ)丁不會被提交。

最后在 git am 運(yùn)行期間調(diào)用的是 post-applypatch 掛鉤。你可以用他來通知一個小組或獲取的補(bǔ)丁的作者,但無法阻止打補(bǔ)丁的過程。

3.其他客戶端掛鉤

pre-rebase

pre-rebase 掛鉤在衍合前運(yùn)行,腳本以非零退出可以中止衍合的過程。你可以使用這個掛鉤來禁止衍合已經(jīng)推送的提交對象,pre-rebase 掛鉤樣本就是這么做的。該樣本假定next是你定義的分支名,因此,你可能要修改樣本,把next改成你定義過且穩(wěn)定的分支名。

比如說,如果你想徹底禁用rebase操作,你可以使用下面的pre-rebase腳本:

#!/bin/sh

# 禁用所有rebase
echo "pre-rebase: Rebasing is dangerous. Don't do it."
exit 1

每次運(yùn)行g(shù)it rebase,你都會看到下面的信息:

pre-rebase: Rebasing is dangerous. Don't do it.
The pre-rebase hook refused to rebase.

內(nèi)置的pre-rebase.sample腳本是一個更復(fù)雜的例子。它在何時阻止rebase這方面更加智能。它會檢查你當(dāng)前的分支是否已經(jīng)合并到了下一個分支中去(也就是主分支)。如果是的話,rebase可能會遇到問題,腳本會放棄這次rebase。

post-checkout

由git checkout命令調(diào)用,在完成工作區(qū)更新之后執(zhí)行。該腳本由三個參數(shù):之前HEAD指向的引用,新的HEAD指向的引用,一個用于標(biāo)識此次檢出是否是分支檢出的值(0表示文件檢出,1表示分支檢出)。也可以被git clone觸發(fā)調(diào)用,除非在克隆時使用參數(shù)--no-checkout。在由clone調(diào)用執(zhí)行時,三個參數(shù)分別為null, 1, 1。這個腳本可以用于為自己的項(xiàng)目設(shè)置合適的工作區(qū),比如自動生成文檔、移動一些大型二進(jìn)制文件等,也可以用于檢查版本庫的有效性。

最后,在 merge 命令成功執(zhí)行后,post-merge 掛鉤會被調(diào)用。他可以用來在 Git 無法跟蹤的工作樹中恢復(fù)數(shù)據(jù),諸如權(quán)限數(shù)據(jù)。該掛鉤同樣能夠驗(yàn)證在 Git 控制之外的文件是否存在,因此,當(dāng)工作樹改變時,你想這些文件可以被復(fù)制。

5.服務(wù)器端 Hooks

除了客戶端掛鉤,作為系統(tǒng)管理員,你還可以使用兩個服務(wù)器端的掛鉤對項(xiàng)目實(shí)施各種類型的策略。這些掛鉤腳本可以在提交對象推送到服務(wù)器前被調(diào)用,也可以在推送到服務(wù)器后被調(diào)用。推送到服務(wù)器前調(diào)用的掛鉤可以在任何時候以非零退出,拒絕推送,返回錯誤消息給客戶端,還可以如你所愿設(shè)置足夠復(fù)雜的推送策略。

pre-receive

處理來自客戶端的推送(push)操作時最先執(zhí)行的腳本就是 pre-receive 。它從標(biāo)準(zhǔn)輸入(stdin)獲取被推送引用的列表;如果它退出時的返回值不是0,所有推送內(nèi)容都不會被接受。利用此掛鉤腳本可以實(shí)現(xiàn)類似保證最新的索引中不包含非 fast-forward 類型的這類效果;抑或檢查執(zhí)行推送操作的用戶擁有創(chuàng)建,刪除或者推送的權(quán)限或者他是否對將要修改的每一個文件都有訪問權(quán)限。

#!/usr/bin/env python

import sys
import fileinput

# 讀取用戶試圖更新的所有引用
for line in fileinput.input():
    print "pre-receive: Trying to push ref: %s" % line

# 放棄推送
# sys.exit(1)

post-receive

post-receive 掛鉤在整個過程完結(jié)以后運(yùn)行,可以用來更新其他系統(tǒng)服務(wù)或者通知用戶。它接受與 pre-receive 相同的標(biāo)準(zhǔn)輸入數(shù)據(jù)。應(yīng)用實(shí)例包括給某郵件列表發(fā)信,通知實(shí)時整合數(shù)據(jù)的服務(wù)器,或者更新軟件項(xiàng)目的問題追蹤系統(tǒng) —— 甚至可以通過分析提交信息來決定某個問題是否應(yīng)該被開啟,修改或者關(guān)閉。該腳本無法組織推送進(jìn)程,不過客戶端在它完成運(yùn)行之前將保持連接狀態(tài);所以在用它作一些消耗時間的操作之前請三思。

update

update 腳本和 pre-receive 腳本十分類似。不同之處在于它會為推送者更新的每一個分支運(yùn)行一次。假如推送者同時向多個分支推送內(nèi)容,pre-receive 只運(yùn)行一次,相比之下 update 則會為每一個更新的分支運(yùn)行一次。它不會從標(biāo)準(zhǔn)輸入讀取內(nèi)容,而是接受三個參數(shù):索引的名字(分支),推送前索引指向的內(nèi)容的 SHA-1 值,以及用戶試圖推送內(nèi)容的 SHA-1 值。如果 update 腳本以退出時返回非零值,只有相應(yīng)的那一個索引會被拒絕;其余的依然會得到更新。

6.使用Hooks-客戶端代碼規(guī)范(OC)

統(tǒng)一的代碼規(guī)范讓代碼更加清晰易懂。在控制代碼規(guī)范方面可以執(zhí)行的就是 :

1.程序員自己控制(定期code review)

2.自動化檢測 (多人協(xié)作代碼提交的時候強(qiáng)制檢測代碼規(guī)范,不符合不讓提交)

這里就依賴著 spacecommander 和 hooks 的結(jié)合 實(shí)現(xiàn)代碼提交之前的代碼格式規(guī)范檢測。

1.下載 spacecommander

git clone https://github.com/square/spacecommander.git

下圖就是我們clone下來的 spacecommander 的文件夾內(nèi)容,其中包括一些 shell 腳本文件,還有 python 腳本文件,(其中 shell 主要是來調(diào)用 python 腳本的),其中還有一個最重要的隱藏文件 .clang-format (這個文件是用配置代碼規(guī)范的,采用 YMAL 標(biāo)記語言書寫).

2.在項(xiàng)目倉庫中安裝spacecommander

我們進(jìn)入項(xiàng)目目錄 運(yùn)行 spacecommander 倉庫中的 setup-repo.sh 腳本

執(zhí)行過程如下圖:

第一個紅圈處地址為我項(xiàng)目工程所在目錄 執(zhí)行的 setup-repo.sh 需要取 spacecommander 目錄地址。

第二個紅圈處可以看到 setup-repo.sh 命令的執(zhí)行

在 項(xiàng)目目錄下的 .git/hooks 目錄中生成一個 pre-commit 文件(可執(zhí)行鉤子文件)

同時在項(xiàng)目目錄下生成了一個 .clang-format 文件

其中 .clang-format 只是一個文件鏈接,指向了我們的 spacecommander 倉庫中的這個文件,這個文件主要用來配置規(guī)范的選項(xiàng)。最重要的一個文件是 .git 隱藏文件夾下的 hook文件夾中的 pre-commit 腳本,這個腳本會在 git commit 之前執(zhí)行用來檢測代碼是否符合規(guī)范。

#!/usr/bin/env bash
current_repo_path=$(git rev-parse --show-toplevel)
repo_to_format="/Users/young/Desktop/demo/demoWebView"
if [ "$current_repo_path" == "$repo_to_format" ] && 
[ -e "/Users/young/desktop/demo/spacecommander"/format-objc-hook ]; 
then "/Users/young/desktop/demo/spacecommander"/format-objc-hook; fi

上面的 shell 代碼 大致的意思就是 對我們指定的目錄 執(zhí)行 format-objc-hook 腳本文件去校驗(yàn),而這個format-objc-hook 腳本文件主要是用來檢測這個這次提交的變化中是否有不符合代碼規(guī)范的代碼,如果有就 commit 失敗,如果沒有就 commit 成功。

3.提交代碼+代碼檢測+代碼自動fix

?? Format and stage individual files:
"/Users/young/desktop/demo/spacecommander"/format-objc-file.sh 'demoWebView/ViewController.m' && git add 'demoWebView/ViewController.m';

??  Format and stage all affected files:
     "/Users/young/desktop/demo/spacecommander"/format-objc-files.sh -s

??  There were formatting issues with this commit, run the?? above?? command to fix.
??  Commit anyway and skip this check by running git commit --no-verify
yanghuangdeMac-mini:demoWebView young$ 

如上圖結(jié)果 提交命令 git commit -m "mod" 之后 提交并未成功并返回了錯誤,錯誤清楚的告訴我們格式不對的提交文件,我們可以按錯誤提示中得操作命令去 單獨(dú)格式化一個文件 或者整個項(xiàng)目。

4.自定義代碼規(guī)范文件

clang-format 規(guī)范

IndentNestedBlocks: false
AllowNewlineBeforeBlockParameter: false

Language:        Cpp
# BasedOnStyle:  Google # 基礎(chǔ)樣式
AccessModifierOffset: -1 #類的訪問修飾關(guān)鍵字(private,public,protected···)縮進(jìn)
# private:
# int a;
# 1表示不縮進(jìn)
#大于1的值表示訪問修飾關(guān)鍵字的左側(cè)從int a的左側(cè)列開始往右側(cè)移動的距離

ConstructorInitializerIndentWidth: 4
SortIncludes: false

AlignAfterOpenBracket: true #在未封閉(括號的開始和結(jié)束不在同一行)的括號中的代碼是否對齊
# if(a &&
#    b)
# 

AlignEscapedNewlinesLeft: true #如果是true就是左對齊,如果是false就是右對齊 如下:
# void foo() {
#        someFunction();
#  someOtherFunction();
# }//false
# void foo() {
#    someFunction();
#    someOtherFunction();
# }//true

AlignOperands: false #水平對齊二進(jìn)制和三元表達(dá)式

AlignTrailingComments: true  
#是否把注釋右對齊,下面為右對齊的效果
#void someFunction() {
#    doWork();     // Does something
#    doMoreWork(); // Does something else
#}

AlignConsecutiveAssignments: false  #多行賦值語句按=號對齊
AlignConsecutiveDeclarations: false #多行聲明語句按=號對齊

AllowAllParametersOfDeclarationOnNextLine: false #參數(shù)的對齊方式 如果TRUE就讓參數(shù)上下對齊 否則將是默認(rèn)
# someFunction(foo,
#              bar,
#              baz);//true
#
# someFunction(foo, bar, baz);//false
#

AllowShortBlocksOnASingleLine: false #是否允許短代碼塊在一行寫完#如 if (a) { return; }
AllowShortCaseLabelsOnASingleLine: false #是否允許短switch的case 語句在一行寫完
AllowShortFunctionsOnASingleLine: true #是否允許短的函數(shù)在一行寫完
AllowShortIfStatementsOnASingleLine: true #是否允許短的語句在一行寫完
AllowShortFunctionsOnASingleLine: All
AllowShortLoopsOnASingleLine: true #是否允許短的循環(huán)在一行寫完

AlwaysBreakAfterDefinitionReturnType: false
AlwaysBreakTemplateDeclarations: false

AlwaysBreakBeforeMultilineStrings: false #在多行字符串之前總是打破 如下 true
# NSString *string = 
# @"deqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwde"                        # @"qwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeqwdeq"
# @"wdeqwdeqw";

BreakBeforeBinaryOperators: None #在二元運(yùn)算符前斷行
BreakBeforeTernaryOperators: false #在三元運(yùn)算符前斷行
BreakConstructorInitializersBeforeComma: false #在構(gòu)造函數(shù)初始化時按逗號斷行,并以冒號對齊

BinPackArguments: true
BinPackParameters: true
ColumnLimit: 0 #最大寬度,如果代碼超過這個寬度會按語義折行 0意味著沒有限制
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true  #case語句的位置總是在switch語句后縮進(jìn)一級
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 2 #允許最大連續(xù)空行數(shù)
KeepEmptyLinesAtTheStartOfBlocks: false #block從空行開始
NamespaceIndentation: Inner #命名空間縮進(jìn)
ObjCBlockIndentWidth: 4 #block內(nèi)的縮進(jìn)大小
ObjCSpaceAfterProperty: true #是否需要在"@property"后加上空格
ObjCSpaceBeforeProtocolList: true #是否需要在協(xié)議名后加上空格
PenaltyBreakBeforeFirstCallParameter: 10000
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000 #最多能超出ColumnLimit多少個字符
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right #指針在類型那邊還是在變量名那邊還是在中間
SpacesBeforeTrailingComments: 1 #單行注釋前的空格數(shù)
Cpp11BracedListStyle: true
Standard:        Auto
IndentWidth:     4
TabWidth:        8
UseTab:          Never #是否使用tab進(jìn)行縮進(jìn)
BreakBeforeBraces: Custom # 圓括號的換行方式
BraceWrapping: 
    AfterClass: true
    AfterControlStatement: false
    AfterEnum: false
    AfterFunction: true
    AfterNamespace: true
    AfterObjCDeclaration: true
    AfterStruct: false
    AfterUnion: false
    BeforeCatch: false
    BeforeElse: false
    IndentBraces: false

SpacesInParentheses: false #是否在非空的括號中插入空格
SpacesInSquareBrackets: false
SpacesInAngles:  false #是否在<>中間插入空格
SpaceInEmptyParentheses: false  #是否在空括號中加空格
SpacesInCStyleCastParentheses: false
SpaceAfterCStyleCast: false
SpacesInContainerLiterals: true #是否在容器字面量(@[@"1",@"2"])中插入空格
SpaceBeforeAssignmentOperators: true #在=號前加空格

ContinuationIndentWidth: 4 
#在續(xù)行(\  
#     下一行)時的縮進(jìn)長度
CommentPragmas:  '^ IWYU pragma:'
ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements   #是否在括號前加上空格
DisableFormat:   false #禁用當(dāng)前format文件

7.可能出現(xiàn)的問題

1..simple 文件后綴的移除

2.如果自己新建的鉤子文件不生效,執(zhí)行一遍 chmod +x 文件名

3.使用 spacecommander 去自動編譯代碼格式的時候 一定要用他提示的絕對地址的文件路徑

8.參考、栗子

Git Hooks 文檔

spacecommander

clang-format

clang-format-demo

IOS 代碼校驗(yàn)封裝(僅限OC)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內(nèi)容

  • 背景 某某你提交的代碼有問題,怎么把沒有驗(yàn)證的dev代碼合并到master上去了…… 某某你提交的代碼有問題,怎么...
    小黑妞_b8b9閱讀 11,514評論 1 18
  • 什么是Git Hooks? 話說,如同其他許多的版本控制系統(tǒng)一樣,Git也具有在特定事件發(fā)生之前或之后執(zhí)行特定腳本...
    茗涙閱讀 11,437評論 0 7
  • 王富貴一直就是個俗人,別看他長得斯斯文文,說話慢聲細(xì)語,其實(shí)都是假象。王富貴最愛奶大腰細(xì)的美女,低頭看不到腳的那種...
    日暮青遲閱讀 594評論 0 2
  • 最近一周的我 像個泄了氣的皮球 尤其是昨天 只是坐著 什么都不想干 我找菲姐微信了幾句 我不能說出自己的感受 因?yàn)?..
    橙子蛋白閱讀 373評論 0 0
  • 基本的垃圾回收算法 引用計(jì)數(shù)(Reference Counting) 增加一個引用,引用計(jì)數(shù)加1,去掉一個引用,引...
    PennyWong閱讀 411評論 0 3