记一次Git分支合并引发的问题和修复

背景

Git工做流

在咱们的一个项目中,有3-4我的在同时开发,目前采用的是AoneFlow的变体进行分支管理,简单来讲,分为四种类型的分支:主干分支(master)、特性分支(feature)、发布分支(release)、开发分支(develop/test)。git

每当新功能需求过来后,会从master切出feature分支进行开发,开发完成后合并到test分支中进行测试。多个功能需求测试完成后,将对应的feature分支合并到release分支,再合并到master分支进行发布。如图: shell

这种开发模式下的特色:

  1. test分支是一个“大杂烩”,全部开发完成(包括未测试完成)的feature分支都会合并到test分支。
  2. master分支根据多个feature测试结果来进行选择性合并到release,做为当前版本最终须要发布的分支,合并到master进行上线发布。

问题

在最近一次项目代码合并的时候发现了两个问题:编辑器

  1. 一些新开发中的feature分支没法被合并到master分支,提示已经up-to-date。
  2. 把master分支往开发分支develop合并时发现部分代码被删除了。

回顾

错误的合并

在发现问题后, 通过一个小时的排查,终于发如今某次提交过程当中,咱们的一位开发不当心把test分支合并到了本身的featureA分支上。测试

这意味着,许多开发中的功能被合并到了featureA上。为了解决这个问题,这位同窗经过对比,手动删除了多余的代码,保持了featureA分支只有本身开发的那部分代码,也通过测试经过了。spa

因而分支变成了这个样子:code

发布上线

在上线代码合并到master的时候,我检查merge request进行例行的code-review,发现确实featureA 功能的提交,因而将featureA 合并到了master准备上线,上线后也没有任何问题。后续的功能也一个一个都提交上去了。cdn

发现问题

几天后,一个同窗像我反映,在一个新功能的开发中,基于master切出了featureD分支,开发完成后合并到test分支进行测试的时候,出现了不少不是本身开发的代码,我当时就很纳闷,这种模式下test分支永远是领先于master分支的,基于master的分支开发完成后提交到test应该只会有包含本身开发功能的那部分代码才对呀,最可能是产生一些冲突,不会有太多的文件变动。blog

最初怀疑是否是拉错了分支,一看commit记录,发现了问题的根本缘由:开发

在上次featureA 合并到master的时候,虽然没有多余的文件变动,可是featureA合并过test代码,即featureA包含了添加featureB/C, 删除featureB/C的两次commit记录工作流

因此在后续基于Master拉出来的feature分支都会带上这个错误的commit记录,致使:

  1. test分支上只有添加featureB的代码,基于master的新feature分支却带上了删除featureB的commit且领先于test,合并到test的时候会删除掉featureB的代码。
  2. featureB分支再也没法合并到master分支,由于master上最新的commit已经删除了featureB的代码。

如何解决

方案一:在featureA 分支上revert 撤销那次合并test的Commit

git checkout featureA
git revert commit_id
复制代码

提示失败了

缘由是这个commit是一个merge commit,此次commit包含两个父节点,须要指定你要revert哪个,即若是A,B合并到C,须要告诉git你要revert的是A提交仍是B提交。 这里使用 —m参数就能够了,1和2表明你要revert哪个父提交,大多数状况是1,即撤销“刚才merge进来的那一个提交”

git revert commit_id -m 1
复制代码

可是这里有个须要注意的地方,若是revert掉某次修改后,若是须要再次merge该分支, 须要再作一次反向revert。 即Revert 掉以前的Revert,不然该分支以前的修改没法被提交,由于已是“落后”于主干分支了。

方案二:在featureA 分支上reset掉那一次提交记录

reset和revert不一样的是:

  • revert是根据某次的变动记录,生成一个新的commit,反向删除/添加对应以前某一次commit的代码。
  • reset是“消除”本身的commit记录从新提交,这种状况下若是reset提交到远程的分支,须要push -f强制更新,所以强烈不建议在多人协做的分支上这么作

这里要注意的是,若是在出错的commit版本后还有若干次正确的提交,reset后也会一并消失,须要从新加回来,否则后续正确的代码也会丢失,按照以下操做进行cherry-pick:

git reset --hard commit_id #退回到出错前的一个commit

git cherry-pick commit_id_right #将出错后的commit提交从新加回当前的时间轴

git push -f #强制更新
复制代码

方案三: 在featureA分支上进行rebase操做丢弃错误的提交

rebase即变基 使用git rebase -i 命令能够压缩合并屡次提交

格式:git rebase -i [startpoint] [endpoint]

其中-i的意思是interactive,即弹出交互式的界面让用户编辑完成合并操做,[startpoint] [endpoint]则指定了一个编辑区间,若是不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。

操做方式为:

  1. 首先根据git log,找到出错前的一个commit

  2. 执行git rebase -i commit_id 合并以前的提交记录

  3. 会弹出一个vi编辑器以下:

    将出错的那两次提交,pick改成drop,即丢弃。

  4. Esc :wq保存

  5. 若是出现冲突

    须要手动解决冲突后,执行

    git add xxx
    git rebase --continue
    复制代码

总结:

  • 在多人合做中,尽可能不要把test分支往feature分支上合并
  • 多人协做的分支上出现已经提交到远程的错误的合并时,优先使用revert来进行错误回退,并注意后续分支再次合并是否有问题。
  • resetrebase尽可能在私人分支或者未提交到远程的时候使用,若是过去的分支已经提交到远程,会对其余人的本地分支形成影响。
相关文章
相关标签/搜索