如何保持自己的应用和关联的第三方框架同步更新?

在当今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兼容了!!!

posted @ 2016-04-01 12:08  世有因果知因求果  阅读(1554)  评论(0编辑  收藏  举报