代碼評審中的代碼協同
大神說:“Show me the code”,于是就有了代碼評審。
“Talk is cheap. Show me the code.”
——Linus Torvalds, founder of Linux and Git.
代碼評審中同樣存在著“Talk is cheap. Show me the code”,語言無力時,直接上代碼吧。這就是我們今天要討論的話題——代碼評審中的代碼協同。
一 基于郵件列表的代碼評審
這是一種和代碼倉庫松耦合的代碼評審模式,100%的代碼都要經由一位或多位“仁慈的獨裁者”(benevolent dictator)代碼評審后才能合并入代碼倉庫。這種開發模式還需要開發者掌握一些命令行操作技巧以便完成代碼在倉庫和郵件列表之間的轉換。采用這個模式的項目不多,不過 Linux、Git 開源社區就是按照這種模式運作的。
1 代碼和郵件的相互轉換
代碼轉換為電子郵件,要使用 git format-patch 命令。例如下面的命令將指定范圍的代碼提交(例如在 origin/master 之后的新提交)轉換為電子郵件:
- git format-patch origin/master..HEAD
生成的補丁文件的格式如下所示:
- From: Author Name <author@email>
- Subject: [PATCH] first line of commit message
- more commit message...
- ---
- diff --git ...
- <content of patch>
- 郵件頭中的 Subject: 字段是郵件標題,使用 [PATCH] 作為標題前綴,以提交說明的第一行作為標題內容。
- 更多的提交說明作為郵件內容,和郵件頭之間用一個空行分隔開。
- 用分隔符 --- 作為提交說明的結束。
- 在分隔符 --- 和 diff --git 開始的補丁內容之間的文字被忽略。通常此處內容是提交的變更統計,開發者也可以在此處寫入不宜列入提交說明中的附加說明。
git format-patch 命令有很多參數,要結合不同場景使用,例如:
- 一個特性由多個提交構成,分散在多個提交中的提交說明難以描述整個特性,可以使用 --cover-letter 參數,生成一封編號為 0000 的郵件,作為后續提交的摘要說明,便于評審者理解代碼。
- 一個特性通常會多次迭代,就需要為每次迭代設置不同的版本。這就要用到 -v {num} 參數指定補丁的版本。版本將體現在郵件標題中,例如第二版本的補丁,郵件標題將使用 [PATCH v2] 作為前綴。
- 回復特定郵件,以便形成可追蹤的郵件線索,使用參數 --in-reply-to="{Message-ID}",為電子郵件生成相關的 In-Reply-To: 和 References: 頭信息。
- 默認提交本身的作者、提交說明的簽名區(trailer)提及的貢獻者會自動添加為郵件的收件人。要添加更多參與者,可以使用 --to={email}、--cc={email} 參數。
將電子郵件轉換為代碼,則使用命令 git am [options...] mail... 。該命令會將郵件正確轉換為 Git 倉庫中的提交。
使用 git send-email 命令,將包含代碼提交的郵件發送到郵件列表。
2 評審中的代碼片段轉換為提交
代碼評審以郵件回復的方式完成。注意郵件回復都要求用純文本格式,否則會被郵件服務器退信。
代碼評審中發現小的文字錯誤,例如將 warning 寫成了 waring,評審者可能做出如下簡潔的回復:
- s/waring/warning/
這種約定俗成的格式大概是源于 sed 命令實現文本替換的語法。
評審者有時候會在回復中貼上大段的代碼補丁,為了使代碼補丁和郵件上下文做出區分,會使用特殊的剪刀分隔符將郵件中的評論和代碼補丁分隔開。
- Subject: Re: whatever thread you're in
- Somebody else said:
- > blah blah blah
- I disagree. You should do it like this instead:
- -- >8 --
- first line of commit message
- more commit message
- ---
- diff --git ...
上面是 Peff(Jeff King)在郵件中給出的一個示范,看到其中的剪刀分隔符了么?剪刀分隔符由多個減號(穿孔的分割線)和一個剪刀符號組成至少8個字符的分隔符??蛇x的分隔符有:-- 8< -- 、-- >8 -- 、-- %< -- 或 --- >% --- 等。
使用 git am --scissors 命令,能夠識別郵件中的剪刀分隔符,將郵件中的代碼轉換為提交。
3 為提交貢獻者署名
Git的提交元信息中只包含兩個署名信息,一個是提交的原始作者(Author),一個是將提交合入倉庫或者對提交做了修補的提交者(Committer),而在提交評審過程中有過貢獻的人往往不只兩人,如何致敬貢獻者呢?Git 社區的實踐是在提交尾部(trailer)添加貢獻者簽名。貢獻者簽名由一個被動語態的關鍵字和貢獻者ID組成,例如:
- Signed-off-by: User
:通常由代碼的貢獻者(Author)和代碼合入時的提交者(Committer)提供的簽名??捎擅? git commit -s 、 git am -s 等命令自動添加。 - Reported-by: User
:問題的報告者。 - Helped-by: User
:對提交有過幫助的人。 - Reviewed-by: User
:評審者。
可以通過 Git 項目倉庫的提交歷史,看到更多的簽名示例。
4 使用 GitHub PR 實現代碼到郵件的轉換
一個名為 GitGitGadget 工具借助 GitHub 強大的擴展能力,通過向 gitgitgadget/git 倉庫發送 pull request,實現提交到郵件的轉換,并發送到 Git 項目的郵件列表中。使用 GitGitGadget 參與 Git 社區代碼貢獻詳見。
二 GitHub 代碼評審中的協同
GitHub 使用 pull request 進行代碼評審,評論中的代碼塊兒也可以轉換為提交。
1 代碼評論中嵌入代碼塊
下圖中,點擊評論工具欄第一個按鈕,可以在評論中嵌入代碼塊:
2 評論中代碼塊轉換為提交
對 pull request 的源倉庫具有寫權限的用戶,可以將評審中的代碼庫轉換為提交,如下圖所示:
于是代碼評審中會增加一個新的修正提交。
GitHub 的這個功能對于代碼評審中發現的一些小問題,還是非常方便的。但是大的修改就無能為力了。
3 線下評審
對于功能復雜的 pull request,在線上瀏覽代碼不方便,也不能線上調試代碼,這時線下獲取并瀏覽代碼,就非常有必要了。
GitHub 的代碼倉庫中為每一個代碼評審設置了特殊的關聯引用:
- refs/pull/{ID}/head :關聯 pull request 的源提交。
- refs/pull/{ID}/merge :對于沒有沖突的 pull request,這個引用指向一個成功的合并提交。
代碼評審者使用如下命令可以獲取 pull request (例如編號為 123 的 PR)指向的提交:
- git fetch origin refs/pull/123/head
- git switch -d FETCH_HEAD
評審者可以線下調試 pull request 指向的代碼,但是對代碼做出的本地修改,沒有辦法直接更新到線上的代碼評審中。
阿里巴巴的云效Codeup,支持線下到線上的代碼協同。
三 云效Codeup代碼評審中的協同
無論是 GitHub 還是 Gitlab,開發者創建代碼評審首先需要將代碼推送到線上獨立的分支中(無論是在線上的派生倉庫,還是目標倉庫),然后再通過網頁選擇來源倉庫、分支及目標倉庫、分支,創建代碼評審。
GitHub 和 Gitlab 這種代碼評審方式,或者要引入冗余的派生倉庫,或者需要為開發者賦予在倉庫中的寫入權限,并容易引發雜亂的分支管理。
1 適合主干開發的無分支創建代碼評審
云效 Codeup 可以通過 git push 命令在客戶端直接創建代碼評審,無需創建派生倉庫或者在倉庫中創建特性分支。例如在客戶端執行如下命令:
- git push origin HEAD:refs/for/master/topic1
該命令會在服務端創建新的代碼評審,或者如果已經存在相同用戶、相同命令創建的代碼評審則會更新評審中的提交。
建議安裝我們開源的 git-repo 工具,則可以用更簡單的命令行,實現從客戶端創建/更新代碼評審。
- git pr
2 線下評審,線上協同
和 GitHub 類似,云效 Codeup 創建的代碼評審都有一個特殊引用相關聯,格式為:refs/merge-requests/{ID}/head。
代碼評審者可以使用 git fetch 命令獲取特定的代碼評審(以編號123為例)指向的代碼,進行線下代碼評審。
- git fetch origin refs/merge-requests/123/head
- git switch -d FETCH_HEAD
如果安裝了 git-repo,可以使用下面更為簡潔的命令:
- git download 123
代碼評審者除了可以在本地倉庫中瀏覽、調試代碼,還可以更新代碼、創建提交,然后將本地新增提交更新到線上的代碼評審中。命令示例如下:
- git pr -c 123
在云效 Codeup,開發者和評審者可以基于代碼評審進行更為流暢的代碼協同。
3 Git proc-receive 掛鉤
上述“線下評審、線上協同”功能的核心是 Git 的 proc-receive 掛鉤和 report-status-v2 新能力。這一功能由阿里巴巴貢獻給 Git 社區,并在 Git 2.29.0 發布。
云效 Codeup 匯集了阿里巴巴最新的代碼托管、代碼協同技術,希望能夠造福更多中國和世界的開發者。