合并git分支时一个分支有一个不想要的还原(revert),另一个分支没有,该怎么办?

3
我们正在开发两个版本,一个是小版本,一个是大版本,每个版本都有自己的git分支。在创建大版本之前,该功能最初添加到小版本中。后来,我们从小版本中删除了该功能(使用revert提交),因为我们决定在大版本中引入该功能。
所以现在我们的情况是,如果我们将从小版本合并的更改合并到大版本中,它将包括revert提交,在大版本中这是没有意义的。
我考虑的一个选项是在revert提交后使用cherry-pick处理小分支中的提交,但这样做的缺点是基于小分支的任何分支都无法与大分支合并。尽管如此,它具有更准确的历史记录,因为不包括revert提交。
另一个选择是将整个小分支合并到大分支中,然后“忽略”revert更改。通过“忽略”,我的意思是在进行合并时手动还原被还原的更改。从git的角度来看,这更好地保留了历史记录,但可能需要在合并期间进行一些解纷。
通常,我们只在主要分支中使用合并,并且仅使用cherry-pick来调整修复最新代码之前的内容。因此,我更倾向于选择第二个选项,但我想在这里了解是否这是处理这种情况的正确方式,或者是否我遗漏了什么。
*   (major)
| * (minor)
* | ...
| * revert feature on minor
* | major: unrelated commit
| * minor: unrelated commit
* |
|/
*   common ancestor
|
*   add feature to main branch

1
你的问题缺少ASCII-Art :). 你是回滚了一个只存在于次要分支上的提交,还是该提交是在主分支上创建并在次要分支合并之前? - Chronial
在特性添加到小分支之后,但是在撤销添加到小分支之前,是否已经将小分支合并到主分支了? - Richard Hansen
我没有清楚地意识到功能提交在两个分支上都是通用的。 - Michael Best
2个回答

6
我对你所说的“在主干上没有意义”感到好奇。你是担心该功能将在主干上被还原吗?还是你只是因为类似于“还原功能”的提交标题将出现在主干的历史记录中,而实际上该功能确实存在而感到烦恼?
如果没有更多细节很难确定合并的结果,但以下是一些可能性:
如果您的历史记录类似于此:
*   (major)
| * (minor)
* |
| * revert feature on minor
* | cherry-pick feature onto major
| * add feature to minor
* |
|/
*   common ancestor
|

然后,您可以将minor合并到major中,而不会出现任何问题。
为什么呢?这样想:当您将minor合并到major中时,实际上是在取得共同祖先(git merge-base major minor)和minor之间的差异,将其应用为补丁到major上,然后创建一个提交,该提交恰好具有majorminor作为父级。
共同祖先和minor之间的差异不会包含添加然后撤消的功能的任何提示,因为两个提交相互抵消。因此,引入到major中的唯一更改将是由于minor上的其他提交所导致的更改。
如果您的历史记录如下:
*   (major)
| * (minor)
* |
| * revert feature on minor
* | merge minor into major
|\|
* | cherry-pick feature onto major
| * add feature to minor
* |
|/
*
|

那么你会有问题。在这种情况下,major和minor之间的共同祖先是标记为“add feature to minor”的提交。如果您查看此共同祖先和minor之间的差异,差异将包括对功能的还原。当你将minor合并到major时,这个差异将应用到major上,在major上撤销该功能。
在这种情况下,有几种简单的方法可以避免在major上丢失该功能:
  • Merge minor into major, then revert the revert. The resulting graph would look like this:

    *   revert the revert (major)
    |
    *   merge minor into major
    |\
    * |
    | * (minor)
    * |
    | * revert feature on minor
    * | merge minor into major
    |\|
    * | cherry-pick feature onto major
    | * add feature to minor
    * |
    |/
    *
    |
    
  • Create a new branch off of minor. Let's call it minor-for-merge. On this branch, revert the revert. Then merge the branch to major and delete the branch. The resulting graph would look like this:

    *     merge minor-for-merge into major (major)
    |\
    | *   revert the revert
    *  \
    |   * (minor)
    *   |
    |   * revert feature on minor
    *   | merge minor into major
    |\_ |
    *  \| cherry-pick feature onto major
    |   * add feature to minor
    * _/
    |/
    *
    |
    
无论哪种方式都可以。后者有点笨拙——撤销还原的提交有点悬空,但它可以帮助您在合并到“major”时避免许多合并冲突。
无论您选择哪种方式,从“minor”分支出来的任何分支都可以合并到“major”中,而不需要还原该功能。如果在还原之前创建了一个从“minor”分支出来的分支,则还原不会出现在要合并的历史记录中。如果在还原之后创建了从“minor”分支出来的分支(或者如果在还原之后将“minor”合并到了该分支中),那么还原仍然不会出现在要合并的历史记录中,因为该提交已经在“major”的祖先中。

实际上你的第二种情况和我的情况很相似。我喜欢在合并之前撤销撤销提交的想法。我会尝试一下,看看效果如何。感谢你详细的回答。 - Michael Best
所以在合并之前,我撤销了撤销提交。这个过程非常顺利。再次感谢。 - Michael Best

2

我认为你可以合并小分支并“撤销还原”,我的意思是:

git merge <minor branch>
git revert <revert commit>

还要检查这个 '如何撤销错误合并',虽然不完全与您的问题相关,但您可以了解“撤消撤消”的效果。


@MichaelBest 没关系 :) 我很高兴Richard Hansen提供了一个出色的答案,解释了我因我的糟糕英语而无法表达的内容。 - dyng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接