分類: 版權(quán)聲明:歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處 本系列是為公司寫的 Git & gerrit 場景使用手冊的一篇. 套路部分為解決問題的步驟,心法部分為所用到的知識點的梳理. 場景:你用 git push 向 gerrit 提交了待審核代碼,一切都很順利,你腦袋里冒出了"代碼頭上加了'佛祖保佑'果然有效"的想法. 此時 git 打印出如下提示,你的內(nèi)心OS同步打印 "心情 -5" :
套路:大前提: commit-msg 文件必須已經(jīng)在該項目中存在.使用ls命令檢查該文件是否存在:
如果該文件不存在,則按照 git push 時產(chǎn)生的提示信息,獲取該文件:
上面的命令可以直接從 git push 產(chǎn)生的錯誤信息中復(fù)制出來. 如果要手敲該命令,別忘了把用戶名換成自己的. 方法一: 使用 amend 選項生成 Change-Id:如果缺失 Change-Id 的是最后一個 (head) commit, 使用以下命令即可解決問題:
該命令會打開默認的 commit message 編輯器,一般是 vi. 這時什么都不用修改,直接保存退出即可 (:wq). 再次查看 git log,就會發(fā)現(xiàn)缺失的 Change-Id 已經(jīng)被補上了. 再次 git push 即可. 方法二: 如果缺失 Change-Id 的不是最后一個 commit, 可用 reset 方法:比如,如果缺失 Change-Id 的 commit 是 git log 中的第二個 commit, 則可以用 git reset 命令將本地分支回退到該 commit. (但其實用 git reset 找回 Change-Id 是普通青年才干的事情,文藝青年有更優(yōu)雅的辦法.見方法三) 首先執(zhí)行 git log, 找出缺失了 Change-Id 的 commit,并復(fù)制其 commit-id:
發(fā)現(xiàn)是第二個 commit 缺失 Change-Id. 將代碼 reset 到這個 commit, 并執(zhí)行 amend:
注: 上面的 git reset 用法不會毀滅你寫的代碼,放心執(zhí)行即可. 這時 git log 可以發(fā)現(xiàn)該 commit 已經(jīng)補全了 change-Id. 下一步是把 git reset 撤消掉的代碼重新 commit, 然后 push 即可:
方法三: 使用交互式 rebase 找回任意提交位置的 Change-Id:前面方法二中給出的例子是第二個提交缺失 Change-Id,這時用 git reset 還可以解決問題. 但如果你在一個方案上已經(jīng)工作了一個月,生成了100個本地 commit,提交時才發(fā)現(xiàn) git log 中第99個 commit 缺失 Change-Id. 如果這時還用 git reset 來找回 Change-Id ...... 不要香菇,不要藍瘦.文藝青年表示有辦法優(yōu)雅的解決問題: 交互式 rebase. 第一步,找到缺失 Change-Id 的那個 commit:
發(fā)現(xiàn)是 "I am commit message 1" 這個提交沒有 Change-Id. 第二步,編輯交互式 rebase 的命令文件: 執(zhí)行 git rebase -i, 參數(shù)為 該提交的上一個提交的 commit-id (本例中為 "表單" 那個提交):
這個命令會打開默認的編輯器,一般為 vi. 內(nèi)容如下:
可以將這個文件理解為 git rebase 的內(nèi)嵌腳本.其命令寫法已經(jīng)在下面的注釋里給出了. 這里不贅述,僅給出最終要將該文件編輯成什么樣子:
即: 將缺失了 Change-Id 的 commit 前面的 "pick" 改為 "reword" 即可. 保存退出 (:wq) 注1: 上述文件中 commit 的順序是和 git log 顯示的順序相反的: git log 為最新的在最前; 上述文件為 最新的在最后. 注2: 如果進入該模式后,卻不確定該怎么改,這時不要擔(dān)心,直接退出編輯則什么都不會發(fā)生 (:q!) 注3: 如果沒有搞清楚運作機制,就要注意,除了按需把 pick 改為 reword 外,不要做其他改動.尤其注意不要刪除任何行 (被刪除的那行對應(yīng)的提交將丟失). 注4: 你應(yīng)該已經(jīng)發(fā)現(xiàn),有多個 commit 缺失 Change-Id 的情況也可以用該方法一次性處理. 第三步,逐個編輯 commit-msg: 上一步打開的文件保存退出后,git會逐個打開被你標(biāo)注了 reword 的提交日志頁面. 不需要修改任何東西,逐個保存退出即可 (一路 :wq). 第四步,再次提交: 用 git log 查看提交日志,會發(fā)現(xiàn)缺失的 Change-Id 都生成了. 愉快的提交代碼吧!
心法:gerrit 的 Change-Id 機制:首先要明確, Change-Id 是 gerrit (代碼審核平臺)的概念, 與 git (版本管理) 是沒有關(guān)系的. 簡單來說, Change-Id 是 gerrit 用以追蹤具體提交的機制. 這里不貼網(wǎng)上已有的解釋,舉兩個栗子大家體會下: 1. 你已經(jīng)用 git push 將代碼提交 gerrit 審核了,這時你發(fā)現(xiàn)代碼中有疏漏,修改了一下,執(zhí)行 git commit --amend, 再次推送還可以成功. 這就是因為 gerrit 檢查到兩次 push 的 commit 有同一個 change-id, 就認為是同一個提交,因此可以 amend. 2. git push 將代碼提交到 gerrit 審核,到 gerrit 網(wǎng)站一看,大紅字標(biāo)著 Can Not Merge 字樣. 我想常用 gerrit 的同學(xué)肯定都遇到過這問題. 之前我的做法是, git reset 后,更新代碼,再重新提交. 現(xiàn)在的做法是,不用 git reset 了,直接 git commit --amend, 刪掉 commit log 中的 change-id 那行,然后wq保存退出.這時 gerrit 的那個鉤子腳本會再生成一個不同的 change-id ,這時再更新代碼,重新提交即可成功. 這里只簡要介紹該方法,具體步驟將在 代碼沖突 場景中詳解. Change-Id 的生成機制請繼續(xù)向下看. git 的 hook 機制:鉤子(hooks)是一些在 hook機制可以理解為回調(diào).各個鉤子其實就是一段 bash 腳本,各鉤子腳本的名字都是固定的.可以查看git項目根目錄下的 .git/hooks 這個文件夾,看看都有哪些可用的鉤子.
如果有自己感興趣的 git 事件要處理,修改相應(yīng)的鉤子腳本羅輯即可.然后把 .sample 后綴去掉,鉤子就生效了. 在 gerrit 的 Change-Id 生成機制中,其實 gerrit 就是利用了 commit-msg 的鉤子,在我們提交代碼后,按一定規(guī)則去修改了我們的提交日志,在其末尾添加了這么一行: Change-Id: ....... 這個鉤子腳本是什么時候被加入我們的項目中的呢? 其實就是你在 git push 出錯時 gerrit 網(wǎng)站給你的提示中的那句命令:
執(zhí)行該命令即可得到生成 Change-Id 的鉤子腳本. 這條命令做了以下事情:
查看該腳本,會發(fā)現(xiàn)它是用 awk 命令處理了 .git/COMMIT_EDITMSG 這個文件. 所以如果想手動生成 Change-Id ,只要執(zhí)行下面命令,就可以生成一個可用的 Change-Id:
利用 git commit --amend 重新生成 Change-Id 的原理:git commit --amend , 看名字就知道,是對某個 commit 做出修改的.這種修改既可以包含文件修改,也可以僅包含提交日志修改. 我們用 --amend 對 commit 做出修改后, commit-msg 的鉤子會被重新觸發(fā), Change-Id 就會被生成出來. 用交互式 git rebase 來生成 Change-Id 也是同一個道理. 另: 通過總結(jié)歷次缺失 Change-Id 的例子,發(fā)現(xiàn)基本我們自己通過 git commit 生成的提交都會很順利的生成 Change-Id. 通過 git merge, git revert 等命令由 git 自己生成的 commit 則有較高概率會缺失 Change-Id. 嗯,我們發(fā)現(xiàn)了一個偉大的定律! 然并卵... 并不知道怎么解決這個問題. 因此提倡盡量用 git rebase 代替 git merge 來更新代碼. 事實上, git rebase 更新代碼 相較 git merge 更新代碼,有諸多優(yōu)勢,只是略復(fù)雜些.強烈建議用 git rebase 方式更新代碼. git rebase -i:// TODO: 待續(xù)... |
|
來自: ala咪s > 《SCM_gerrit》