阅读视图

发现新文章,点击刷新页面。

关于git merge -s ours xxx 的使用

需求背景:开发分支(feat1、feat2、....featn),测试分支(dev),预生产分支(release),上线分支(master)。协作过程是,项目一个大版本上线从release合并到master,上线后反合dev。下一个大版本初始大家都从release分支拉取feat,提测后所有feat都合并到dev,有不规范的操作会从dev直接提交代码,测试完成从dev合并到release。但是在测试的过程中,feat1出现了需求变更,不跟随本次上线了

解决方案

使用git merge -s ours xxx

这条命令是 Git 合并操作 的一种特殊用法,核心是用当前分支的内容覆盖掉要合并的分支内容

假设你当前在 release 分支,执行 git merge -s ours feat

  1. Git 会创建一个新的合并提交(merge commit);
  2. 这个合并提交的内容和当前 dev 分支完全一致origin/feat 分支的所有修改都不会被引入;
  3. Git 的分支历史中会显示 release 已经合并过 origin/feat,后续如果再执行常规合并,Git 会认为该合并的都合过了不会再处理这个分支的历史修改

如上操作之后,如3所说,再次合并feat到release分支,会显示:Already up to date.

但是,我们的需求是feat分支的内容只是当前版本不上线了,但是后续的版本还是会上线的,这并不满足我们的需求。 所以,我们可以,先merge再reset再cherry-pick

  1. 切换到release分支,执行git merge -s ours feat => 得到一个没有内容变更的merge
  2. release分支上,执行git merge origin dev => 得到一个没有feat分支变更内容的dev分支到release分支的merge,同时我们记下这个commitId
  3. release分支reset到执行git merge -s ours feat之前的那个提交 => 通过git reset xxx --hard
  4. 然后将刚才2记下的commitId通过cherry-pcik拿过来 => 使用git cherry-pick xxx -m 1(此处的xxx是个mergeId)
  5. 推送到远端

如上所述,即可实现把dev合并到release且不包含feat分支的改动,并且后续也不会影响feat分支往release分支的合并。但是,对release分支进行reset --hard并不符合常规的要求,对于很多公司来讲,release分支应该是受保护的分支,不应该被随便reset。所以,我们可以从release分支上先切出一个新分支,在新分支上进行上述操作,操作完成之后,再把新分支合并到release分支上。

关于其它解决方案的考虑

  1. 不使用dev合并到release,而是用feat1、feat2...featn逐一合并到release。
  2. 找到 dev 分支上所有非 feat 产生的提交,逐个挑选(cherry-pick)到 release 分支。
  3. dev上使用git rebase -i剔除feat的提交。 对于方案1,在实际开发过程中,每个feat分支可能就对应一个开发者,逐一合并可能会涉及到很多人来处理,而且比如在测试过程中有些非常规的操作(在dev上直接提交一些代码),那这部分的提交就会被忽略掉。对于方案2、3,变更比较少的情况下是适用的,但是变更比较多的情况下逐一排查commit也不现实。

思考

一个未解决的问题留给大家:在release分支使用git merge -s ours feat之后,如何在不reset的情况下,可以让feat分支正常合并release呢?

❌