1、Gerrit的基本介紹
Gerrit 是一個Git服務器,它基於 git 版本控制系統,使用網頁界面來進行審閱工作。Gerrit 旨在提供一個輕量級框架,用於在代碼入庫之前對每個提交進行審閱,更改將上載到 Gerrit,但實際上並不成為項目的一部分,直到它們被審閱和接受 。代碼審查是Gerrit的核心功能,但仍是可選的,團隊可以決定不進行代碼審查而工作。
Gerrit 是一個臨時區域, 在提交的代碼成為代碼庫的一部分之前, 可以對其修改進行檢查。代碼修改的作者將提交作為對 Gerrit 的更改。在Gerrit中,每個更改都存儲在暫存區域中,可以在其中進行檢查和查看。僅當它被批准並提交時,它才被應用到代碼庫中。
其實,Gerrit 就相當於是在開發員將本地修改提交到代碼倉庫之前的一個審核工具。在這個審核工具中,你可以查看該提交者在本次的的提交中的修改,然后再決定是否可以將該修改提交給倉庫。
2、Gerrit的頁面介紹
2.1、CHANGES菜單
點擊 changes 可以查看所在項目的所有審批記錄,共有三種狀態:open、merged、abandoned。
open:還未審核、審核不通過、審核通過還未提交到遠程倉庫的提交
merged:審核已通過並已提交到遠程倉庫的提交
abandoned:已取消審核的提交
2.2、YOUR -> CHANGES 菜單
點擊 your -> changes 可以查看當前登錄用戶的名下的所有審核記錄,包括本人提交和本人需審核的。
outgoing reviews:本人待被審核的提交
incoming reviews:別人提交,本人需要審核的提交
recently closed:已關閉的提交,包括已經推送到遠程倉庫和已經取消審核的
2.3、Repositories
點擊 repositories 可以看到自己有權限看到的所有項目。
點擊進入某個項目,可以查看該項目的下載鏈接,共有三種下載方式:
anonymous http:鏈接里面無用戶名,下載時需輸入用戶名和密碼
http:鏈接里待用戶名,下載時無需輸入用戶名,但需要輸入密碼
ssh:免密方式,無需輸入用戶名和密碼,但需將本地生成的公鑰保存在 Gerrit 網頁中
3、在Gerrit上的代碼克隆方式
在Gerrit上有三種克隆方式,如上面的 2.3 所示,跟在 github 上克隆代碼沒什么區別。
在 Gerrit 中,你可以選擇 clone with commit-msg hook 選項來進行克隆,該選項在上面的三種克隆方式中都有,該方式會將 Gerrit 上的 commit-msg 腳本拷貝在你的本地倉庫中,由此你就可以將代碼提交到 Gerrit 中(未驗證)。 commit-msg 腳本是使用 Gerrit 的一個非常重要的步驟,不可或缺,后面會介紹。
4、Gerrit 上的鈎子 commit-msg
commit-msg 是一個腳本文件,該腳本對於 Gerrit 的使用非常重要,使用 Gerrit 必須要有此腳本,否則在本地的修改版本無法提交至 Gerrit 中,會報錯:missing change-id in commmit message footer,表示該版本提交沒有 change-id。
commit-msg 腳本文件應該放在代碼根目錄的 .git/hooks 文件夾下,該文件夾下有許多的腳本文件,這些腳本文件也被稱之為鈎子,在被特定的事件觸發后這些文件將會被調用。當一個 git 倉庫被初始化生成時,一些非常有用的鈎子腳本將會生成在倉庫的 .git/hooks 目錄中,但是在默認情況下它們是不生效的,把這些鈎子文件的 ”.sample”文件后綴名去掉就可以使它們生效。
Git 提供了4個提交工作流鈎子:pre-commit、prepare-commit-msg、commit-msg、post-commit。其中 commit-msg 鈎子,會在我們執行 git commit
時被執行。
在 gerrit 的 Change-Id 生成機制中,gerrit 會利用 commit-msg 的鈎子,在我們提交代碼后,按照一定規則修改提交日志,在其末尾添加了一行Change-Id。
4.1、如何給本地倉庫添加鈎子 commit-msg
4.1.1、在克隆倉庫時選擇帶 commit-msg 的方式進行克隆
在 Gerrit 中克隆倉庫有三種方式,anonymous http、http、ssh,這三種方式當中都有一個 clone with commit-msg hook 選項可供選擇,選擇該選項的鏈接來克隆項目,將會自動在你本地的倉庫中生成 commit-msg 鈎子,這樣在你今后的本地提交當中 commit-msg 都會起作用,將會給每個提交自動生成一個 chang-id,保證了你的本地提交可以推送到 Gerrit 中。
4.1.2、在本地倉庫直接使用 git 命令來拷貝Gerrit的commit-msg
如果在克隆時選擇的不是 clone with commit-msg hook 鏈接,那么本地的倉庫當中的 commit-msg 將不會起作用,你的本地提交不會生成 change-id,也就無法將提交推送至 Gerrit 中。
此時你可以在本地倉庫中的根目錄下使用下面的 git 命令來拷貝 Gerrit 的 commit-msg:
scp -p -P 29418 yourName@Gerrit服務器地址:hooks/commit-msg "hooks文件夾路徑" //實例: scp -p -P 29418 wenxuehai@21.96.221.111:hooks/commit-msg ".git/hooks"
上面命令表示將 gerrit 的 commit-msg 腳本下載到本地倉庫的 t/.git/hooks/ 目錄中。執行上面的命令,你的本地倉庫的 .git/hooks 文件夾下的 commit-msg 文件將會被 Gerrit 的 commit-msg 文件覆蓋掉,由此你今后的提交當中也會自動生成一個 change-id。
5、Gerrit 中的 change-id
待完善。
6、如何將本地提交推送至Gerrit中
在 Gerrit 上工作和在 github 上工作的差別不大,兩者都是基於 git 版本控制系統的。當我們在本地工作時,除了需要有一個 commit-msg 鈎子文件外,其他的並沒有區別。
當我們在本地進行了修改,並且進行了 commit 生成了版本后,就可以將本地提交推送至 Gerrit 中,不過推送命令和平常的不太一樣:
git push origin HEAD:refs/for/遠程分支名 //實例: git push origin HEAD:refs/for/2020_branch
一旦你在本地完成commit,就需要把他 push 到Gerrit,這樣才能被審核者 review,這就需要git push到Gerrit server。
可以看到 HEAD 被推送到 refs/for/2020_branch,這是 2020_branch 的的魔幻分支,用於創建 review。對於每一個分支,Gerrit都會追蹤一個魔幻分支refs/for/branchName。
7、提交報錯
7.1、提示:commit xxx:missing change-id in commmit message footer
在將本地修改推送到 Gerrit 上時(請注意往Gerrit上推送必須使用git push origin HEAD:refs/for/branchName命令),有可能會報以上的錯誤,表示沒有 change-id,提示信息還標出了是哪次提交缺少 change-id。
注意:在將修改推送到 Gerrit 上時,本地每次提交的修改都必須有 change-id,可以使用 git log 命令來查看哪次提交是沒有 change-id 的,但凡有一個提交沒有chang-id,本地代碼都無法推送至 Gerrit 上。
面對這種情況有以下解決方法:
請注意,下面的解決方法的前提是本地的commit-msg腳本文件已經替換成了Gerrit上的,使用 Gerrit 必須先拷貝commit-msg腳本文件,如果還沒有的話請參考4.1.2 先拷貝腳本文件,否則下面的解決方法仍然無法解決問題
7.1.1、標出的缺少 chang-id 的提交就是最近的一次提交
此時一般來說,git 就會提示你需要進行的操作:gitdir=$(git rev-parse .... ${gitdir}/hooks/ ,然后需要: git commit --amend --no-edit,我們只需將 git 提示的命令復制下來操作即可:
//先執行下面命令,其實下面的命令就是拷貝Gerrit中的commit-msg腳本文件,如果你已經拷貝了的話可以不用執行下面的命令也行 gitdir=$(git rev-parse --git-dir); scp -p -P 29418 yourName@gerrit服務器地址:hooks/commit-msg ${gitdir}/hooks/ //實例: gitdir=$(git rev-parse --git-dir); scp -p -P 29418 wenxuehai@gerrit21.96.221.111:hooks/commit-msg ${gitdir}/hooks/ //再執行 git commit --amend --no-edit
7.1.2、缺少 change-id 的提交並不是最近的一次提交
如果缺少 change-id 的提交並不是最近的一次提交的話,上面的解決方法就無法解決問題,因為將修改推送至 Gerrit,必須要求每次提交都有 change-id。
此時我們可以使用 git log 命令來查看是哪次提交沒有 change-id,或者 git 提示信息也會標出是哪次提交沒有 change-id,然后記下該次提交的下面那個提交的 commit id,即前一次提交的 commit id。
比如下圖:
假設上圖中,提交2缺少了 change-id,那么我們就需要記下提交1的commit id:8ca4e3c3d9133f33fa36f063bfc2767b56c5cd3a。
然后執行下面的命令:
git reset --soft 8ca4e3c3d9133f33fa36f063bfc2767b56c5cd3a //執行完上面的命令后咱們可以查看狀態,此時可以看到本地的修改並沒有丟失 git status //然后再照常提交一個版本 git add . //此時提交過后就可以看到本次提交的版本就會有 change-id 了 git commit -m '提交修改' //然后推送即可 git push origin HEAD:refs/for/branchName
可參考:https://www.cnblogs.com/zndxall/p/9603834.html
如果缺少 change-id 的不止一個提交,這時就需要從最近的一個缺少 change-id 的提交照着上面的操作進行修改,或者直接從最晚的那個缺少 change-id 的提交進行操作?(未嘗試過)
8、提交成功但在Gerrit上查看顯示在merge conflict狀態
8.1、出現merge conflict的原因
由於有 code review 的存在,有可能出現這種情況:同時有多個人的代碼被 review,如果有一個人改了與你相同地方的代碼,並且他的代碼先通過 review 並被合進了遠程代碼庫。當你的代碼通過 review 並進行合並,此時會產生沖突,你的提交也就會顯示為 merge conflict 狀態。在 Gerrit 網頁上的 CHANGES -> open 上就可以看到該沖突提交,該提交無法 submit 到遠程倉庫上。如果你不解決掉該沖突提交的話,你在本地的之后的提交也無法合並到遠程倉庫上,因為你本地的提交都是基於前面的那次有沖突的提交的。
8.2、解決方法
1)先在 Gerrit 的 CHANGES -> open 上找到該提交,然后點擊 ‘ABANDON' 按鈕將該提交取消掉。
2)在本地找到該提交的上一個提交版本的 commit id,注意,是比這個出現沖突的版本更早提交的版本,一般來說,這個版本已經提交到了Gerrit上的
3)使用 git reset 的混合模式(git reset --mixed commitId)或者是軟模式(git reset --soft commitId)回退至上面記錄的 commit id 的版本,使用這兩種模式不會丟失你本地的修改,所以大可以放心。
4)使用 git stash 命令將本地修改儲存起來,然后再拉取最新代碼,拉取完畢后應用儲存 git stash pop,如果有沖突就解決沖突即可。然后就可以將版本提交至Gerrit上了。
綜上所述,其實出現這種狀態主要就是因為你的代碼和別人的代碼產生了沖突,並且別人的代碼先一步通過了 review 而且合並到了倉庫當中,而你的代碼通過 review 但是無法合並到倉庫中,因為兩人的修改產生了沖突,此時就要解決沖突。
你只需回退一下版本,然后拉取遠程代碼,在本地解決沖突,然后就可以將本地版本提交至 Gerrit 上了。