如何保持自己的應用和關聯的第三方框架同步更新?

世有因果知因求果發表於2016-04-01

在當今web開發中,有越來越多,越來越成熟的開源應用框架來支援我們快速開發web應用。但是有很多情況下這些應用框架本身也在不斷地新增重要功能,解決部分bug,

那麼我們如何能夠在保持自己工作向前走的情況下,又能擇機將我們的應用框架本身做無縫升級?git的工程實踐有什麼可以應用的呢?本文希望能夠有所探討。

我做了以下實驗,暫時看是可行的:

1. 首先假設第三方庫為l.git;

2. 一般首先clone l.git, 做基本的配置後生成我們的應用app.git 注意:l.git和app.git一般都是裸庫;

3.john(碼農) clone一個app.git,形成自己的開發庫,比如叫做dev;

4.john持續遞交程式碼在dev上,並且最終push到app.git中央庫中;

5.假設l.git的開發人員不斷迭代他們的框架程式碼,到現在l.git和app.git中的基礎框架程式碼已經開始分叉了,現在我們希望做一下框架本身的更新;

6.專案經理tom clone一個app.git ,我們叫做sync, 注意這時sync庫已經包含了最新的應用程式碼和比較老的框架程式碼;

7.tom 建立一個upstream remote: git remote add upsteam l.git;

8.tom 拉取最新的庫程式碼: git fetch upstream master

9.tom 執行rebase命令: git checkout master;git rebase upstream/master;到這裡我們的master分支就已經是在最新的框架程式碼之上了,但是問題來了:這時master分支和app.git的master有了分叉,這時git push origin master的話,git會拒絕並且提示我們git pull,我們到底怎麼辦呢?

9.1要麼再次git pull(隱含會rebase),要麼直接merge,但是這兩個工作好像都會把以前在第9步中衝突解決的痛苦過程再演一遍,我感覺不是好辦法;

9.2直接git push -f origin master,貌似這個辦法簡單粗暴有用,但是我的問題是:由於歷史被覆蓋,如果這個master分支上還有其他的分支,是否會產生問題呢?有待繼續驗證更新。對這個問題的繼續探索:如果master分支上在做第三方框架庫同步時已經長出了其他的分支,比如develop,release分支的話,那麼除了master需要第9步的操作外,develop分支則需要執行git rebase master, release分支則要執行git rebase develop,這樣在sync這個repo中的所有分支就都包含了這次的第三方框架變更。隨後直接git push origin master -f /develop和release做同樣的操作。

但是這個步驟實際上已經冒犯了rebase黃金定律,從這個效果來看,我們確實不應該對公共庫中的master做rebase操作,因為一旦rebase了,master上面的歷史將完全重寫,而其他開發人員pull時將會由於歷史完全不同必須merge,而這個merge帶來了多次完全相同的change set放在歷史中,更可怕的是mastr上面還有很多其他的分支也都須做同樣的操作。因此比較合理的方式是tom執行一個merge操作, git merge upstream/master;git push origin master;其他人員則git fetch origin master; git merge origin/master

10.到了其他的開發人員那裡,他們需要做的是git pull和git rebase,如果從sync clone那個時間點到現在他們沒有任何本地工作,則只管git rebase,中間出現的任何問題或者衝突直接git rebase --skip,目的就是讓master和origin/master, develop和origin/develop, release和origin/release保持同步;如果本地有一些commit沒有變更,則在rebase過程中只選擇自己的本地commit重新run一遍,其他的全部丟棄(因為已經完全包含在對應的origin/xxx分支上了)

問題:在master reabase了upstream/master之後,在master上面的其他分支,比如develop,release分支並未直接獲取到這次rebase動作所做的工作!可以參考以下思路:

參考: http://stackoverflow.com/questions/22770504/rebasing-a-branch-with-sub-branches-all-at-once

a )git rev-list --reverse --simplify-by-decoration master..hotfix | git name-rev --stdin --name-only列出所有從master到hotfix的所有分支

$ git lg
* df79a78 (HEAD, develop) devlop.c updated after hotfix branched off在hotfix建立之後
| * 11bddec (master) master branch updated
| | * 4922bbd (hotfix) hotfix added
| |/
|/|
* | 18515e8 dev develop.c line2
* | c8bc641 (origin/develop) dev dev.c line2 before merged with updated l.git
* | 61025fc dev develop.c line1
|/
* f96e3c4 (origin/master, origin/HEAD) dev mod a.c line3
* 6bdb183 dev dev.c line1
* 9e6c445 a.c line3 in l.git and l1.c new added
* 227eb73 l add a.c line2
* af23226 l add a.c line1

zhenghuz@CV0005366N0 /d/devenv/Code/gitplay2/dev2 (develop)
$ git rev-list --reverse --simplify-by-decoration master..hotfix | git name-rev --stdin --name-only
remotes/origin/develop
hotfix

再參考: http://www.cnblogs.com/rickyk/p/3848768.html 把這段搞清楚

http://ju.outofmemory.cn/entry/98593

http://blog.tankywoo.com/git/2014/05/20/git-merge-strategy-ours-and-theirs.html 參考merge策略

我們再看看老外對這種情況的高見(本人拜讀多遍並且親身動手實踐發現確實是解決這類框架本身不斷髮展而自身基於框架的引用也在不斷開發的同步問題)

https://www.viget.com/articles/keeping-the-framework-for-your-application-up-to-date-with-git

他的思路是:

建立一個命名為framework的branch,來跟進laravel官方庫。我們的應用使用master分支(該分支實際上就是laravel歷史上的一個master快照,只不過增加了我們很多自己特有的應用),

隨後fraemwork分支定期和laravel庫同步,master分支merge這個framework分支,最終以一個commit來代表這次框架的更新,如果有衝突則在merge過程中解決。

這樣就能永遠輕鬆地保持和官方庫的同步,同時又不用手工做太多工作來保持自己的應用庫和更新的laravel相容了!!!

相關文章