原創(chuàng)文章,轉(zhuǎn)載請保留出處
最近剛剛忙完Spark 2.2.0的性能測試及Bug修復(fù),社區(qū)又要發(fā)布2.1.2了,國慶期間剛好有空,過了一遍2.1.2的相關(guān)JIRA,發(fā)現(xiàn)有不少重要修復(fù)2.2.0也能用上,接下來需要將有用的PR合到我們內(nèi)部維護(hù)的2.2.0分支上了。
經(jīng)常有朋友問我是怎么把社區(qū)的PR合到自己分支上的,我之前跟他們介紹的做法是基于PR拉分支,在IDEA中單個(gè)文件diff合并。如果是偶爾合下社區(qū)代碼,這種方式也不算太費(fèi)事。但是如果PR中改動的文件較多,或者要合并多個(gè)PR過來,這種方式也挺麻煩。
廢話到此,這篇文章是介紹,如何高效地合并Spark社區(qū)PR到自己維護(hù)的分支(常說的打Patch),當(dāng)然,針對其他開源項(xiàng)目,該方法同樣適用。
PR:Pull Request是GitHub上的一個(gè)功能,開源代碼的貢獻(xiàn)者,通過發(fā)起一個(gè)Pull Request向社區(qū)貢獻(xiàn)代碼。
準(zhǔn)備Spark代碼
一般來說,自己維護(hù)一套Spark代碼,需要Fork下社區(qū)項(xiàng)目,在clone自己Fork的代碼,進(jìn)行開發(fā)。我這里以Spark 2.2.0為例。
-
clone自己Fork的倉庫到本地
# stanzhai是我的GitHub賬號,大家需要換成自己的倉庫地址 git clone https://github.com/stanzhai/spark.git cd spark -
添加一個(gè)名為upstream的遠(yuǎn)程倉庫指向社區(qū)的版本庫
git remote add upstream https://github.com/apache/spark.git -
設(shè)置PR引用,編輯git配置
vi .git/config,找到upstream,添加最后一行fetch[remote "upstream"] url = https://github.com/apache/spark.git fetch = +refs/heads/*:refs/remotes/upstream/* fetch = +refs/pull/*/head:refs/remotes/upstream/pr/* # 注意添加這行 -
同步遠(yuǎn)端庫,更新分支引用(每次合并前都需要執(zhí)行)
git remote update -
checkout一個(gè)2.2.0的維護(hù)分支
git checkout -b my-2.2.0 v2.2.0
我們創(chuàng)建了一個(gè)基于2.2.0的my-2.2.0分支,下面的示例是將社區(qū)PR合并到my-2.2.0分支中。
提交給社區(qū)的PR大致分為2類:
- PR被接受,且被合并到社區(qū)的倉庫
- PR沒有合并到社區(qū)倉庫,(代碼沒問題,有可能commiter還沒來得及處理)
整合已被社區(qū)合并的PR
被合并到社區(qū)的PR已經(jīng)做了rebase處理,對于這種PR,合并到自己的分支中是非常簡單的事情,直接使用git的cherry-pick就可以搞定。
我們以這個(gè)卡片為例:https://issues.apache.org/jira/browse/SPARK-22083
這個(gè)卡片被標(biāo)記為resolved,而且PR也被合到社區(qū)倉庫了:https://github.com/apache/spark/pull/19311,我們打開這個(gè)鏈接,到頁面下方,找到這個(gè)位置:

打開后,會跳轉(zhuǎn)到這個(gè)地址:https://github.com/apache/spark/commit/2c5b9b1173c23f6ca8890817a9a35dc7557b0776,地址中后面的一長串就是我們需要的commit-id,得到這個(gè)就可以直接合并代碼了:
git remote update
git cherry-pick 2c5b9b1173c23f6ca8890817a9a35dc7557b0776
執(zhí)行完,提示以下信息就表示合并成功了:
? spark git:(my-2.2.0) ? git cherry-pick 2c5b9b1173c23f6ca8890817a9a35dc7557b0776
[my-2.2.0 529f5ea55ff] [SPARK-22083][CORE] Release locks in MemoryStore.evictBlocksToFreeSpace
Author: Imran Rashid <irashid@cloudera.com>
Date: Mon Sep 25 12:02:30 2017 -0700
2 files changed, 153 insertions(+), 13 deletions(-)
如果合并的代碼恰好也被你改過了,那么有可能會出現(xiàn)沖突,這種情況正常解決沖突,然后git commit就可以了。
整合尚未合并到社區(qū)的PR
由于一個(gè)PR可能包含多次提交,整合未合并到社區(qū)的PR就比較麻煩了。Spark的主干代碼每天都有變動,直接對比兩個(gè)不同的分支變動通常會比較大,我們需要將PR中n次提交的代碼的所有變更梳理出來,然后在做整合。
我們以這個(gè)PR為例:https://github.com/apache/spark/pull/19301,這個(gè)PR實(shí)現(xiàn)上還有待改進(jìn),但可以正常工作,因此還沒合入社區(qū),我們將這個(gè)PR合并到my-2.2.0分支,需要進(jìn)行以下操作:
# 更新遠(yuǎn)程倉庫及版本引用信息
git remote update
# 基于某個(gè)PR創(chuàng)建一個(gè)分支,這里的19301是這個(gè)PR在GitHub上的id
git checkout -b pr-19301 upstream/pr/19301
git checkout pr-19301
# PR分支大都基于master開發(fā),以upstream/master分支為基準(zhǔn),重新apply PR分支上的修改
git rebase upstream/master
# 通過diff提取這次PR的patch文件
git diff upstream/master > pr-19301.patch
# 到目標(biāo)分支打patch
git checkout my-2.2.0
git apply --reject pr-19301.patch
# 查看上一步apply的狀態(tài)
git status
# apply有可能會不成功,尚未apply的patch被存放到*.rej文件中,需要手動處理,最后提交即可
git commit -a
# 清理
rm pr-19301.patch
rm *.rej
git branch -D pr-19301
參考
最后
上述方法不能保證合PR 100%成功,原則上你的分支和社區(qū)代碼約近,沖突越少,越容易處理。Spark 2.x的代碼有很大的變動,把針對2.x的PR打到1.6的分支上,往往是個(gè)麻煩事。
據(jù)說看完這篇文章給個(gè)贊的同學(xué),打Patch都不會遇到?jīng)_突 (≧▽≦)/