如何在同一个git分支中复活旧功能?

时间:2014-05-20 13:36:29

标签: git merge git-merge

我想我的问题可能比较常见,它应该有众所周知的解决方案或最佳实践。 不幸的是,我发现和/或尝试的每种解决方案都会产生某种不良副作用。

我的回购基本上看起来像下面这样,即使在我的真实回购中,E和G之间有25个左右的提交,而其他一些分支在两侧突出:

A--B------E--F--G   <-- master
    \    /
     C--D           <-- branch_1

Branch_1包含提交B中存在的功能的实施提议,但实现方式不同。决定branch_1中的实施提案应该是正式的,因此branch_1被合并为master。 由于在提交F和G中已经对branch_1进行了多次错误修复,因此一些与该功能相关,而另一些则与此不相关。 事实证明,来自branch_1的实现提议毕竟不是那么大,所以我需要将提交B中的实现提交给master的一个新提交。我还希望明确提交B是新提交的贡献者,例如当我发出git log --graph --oneline --decorate --all时。我想要的是这样的:

     -------------H <-- branch_2
    /            /
A--B------E--F--G   <-- master
    \    /
     C--D           <-- branch_1

TLDR; 如何创建branch_2并将提交G合并到其中,不包括commit_1在commit E中引入的更改?

请继续阅读我迄今为止尝试过的内容......

我尝试的第一件事就是结帐B,创建一个新的分支&#39; branch_2&#39;并将master合并到branch_2。发生了什么事情是git得出结论,快进是有序的,因为所有后续提交都是新的,所以我最终得到了一个与master相同的branch_2,从而失去了我在commit B中所需要的东西。当然--no-ff给出了出于同样的原因,结果相同。 我尝试过各种合并策略,除了ours之外,它们都创建了相同的结果。我希望手动合并零碎,但我希望尽可能减少这种劳动。我试图找到一种方法来使git创建合并冲突,但我总是最终得到一个与master或commit B相同的代码库而没有任何冲突。

由于以这种方式合并似乎并没有解决我的问题,我认为我会选择樱桃。所以我用git reset --hard B重置了我的branch_2并尝试了git cherry-pick F --no-commit,因为提交E只是一个合并提交。 生成的代码库包含一个易于解决的合并冲突。但是当我解决冲突时,我意识到我错过了我需要的F代码变化的80%以上。我尝试从E中采摘樱桃而git告诉我使用-m,但取决于我是否使用&#39; 1&#39;或者&#39; 2&#39;作为主线,我最终遇到了类似于合并时的问题;生成的代码库与B或E相同。

此时我花了很多时间绕过git diffinterdiffrediff/recountdiff尝试创建补丁,其中B和G之间的差异与E和G之间的差异相比较。我猜这是可能的,但我仍然没有想出如何完成我之后的事情。另一方面,我想git应该能够帮助我。

对我而言,上述是使用版本控制系统/软件的主要目的;我可以回到我的开发历史中,恢复我需要的代码片段。 我确定这是关于我的git技能有限,我只使用git半年。也许git中有一个概念让我无法理解,或者我目前不熟悉的一个术语,因为我无法在搜索中找到问题的正确答案。 我知道如何在ClearCase中完成上述操作,但这并没有帮助...; - )

2 个答案:

答案 0 :(得分:1)

一个更简单的解决方案是恢复Egit revert

git checkout master
git checkout -b branch_2
git revert -m 1 <SHA1 of commit E>

这将取消E引入的任何修改,创建新的提交H,这将是E的负面形象。
FG仍然是新历史的一部分。

                  H <-- branch_2
                 /
A--B------E--F--G   <-- master
    \    /
     C--D           <-- branch_1

答案 1 :(得分:1)

常规

  

...尝试创建具有B和G之间差异的补丁   与E和G之间的差异相比。我想这是可能的,但我   仍然没有弄清楚如何完成我所追求的目标。在   另一方面我想认为git应该能够帮助我   有这个。

在这种情况下,我会使用git rebase --onto使用显式版本参数。你想要的是一个基于B的新分支,其中添加了FG的更改,对吗?这可以通过

完成
$ git branch branch_2 master     # Point branch_2 to the latest change to include
$ git rebase --onto B E branch_2        # Take changes from E (not including)
                                        # to (including) G and put on top of B

那应该给你一些像

     --F'--G'       <-- branch_2
    /            
A--B------E--F--G   <-- master
    \    /
     C--D           <-- branch_1

F'G'提交是F和G相对于B的变化。

提交的拆分

  

由于branch_1的合并已经进行了多次修复   提交F和G,一些与功能相关,另一些则不然   相关。

因此,我会尝试将提交分为两部分,一部分与branch_1相关的更改,另一部分用于其余部分。

$ git branch branch_2 master
$ git rebase -i E
...
# Select `edit` for all versions and exit the editor
...

Git现在将带您回到第一个版本,F。要分割提交,我执行以下操作:重置/删除存储在git数据库中的提交但不使用命令撤消/删除现有文件中的任何内容

$ git reset HEAD^

现在,在F中完成的所有更改仍然存在但是作为未经修改的更改(您可以使用git status进行检查)。现在,您希望再次提交更改,但需要两个(或更多)步骤。运行

$ git add -p
...
# Add only those parts related to branch_1
...
$ git diff --cached       # Should show only changes related to branch_1
$ git diff                # Should show the other changes

同时检查(使用git status)是否有任何未跟踪的文件应与git add一起添加。满意后运行

$ git commit -m "commit F1"           # Possibly some other commit message...
$ git add <all_the_remaining_files>
$ git commit -m "commit F2"
$ git rebase --continue

Git现在将停止在G版本上,相应地重复上述内容。

以上所有“拆分提交操作”都不会引入任何合并冲突,并且100%安全(并且在某种程度上没有改变任何内容......),但现在希望包含/排除你想要的东西。

你现在应该

            --F1--F2--G1--G2       <-- branch_2
           /            
A--B------E--F--G                  <-- master
    \    /
     C--D                          <-- branch_1

排除/包含

此时你可以做到

$ git checkout -b branch_2 B
$ git cherry-pick F2
$ git cherry-pick G2

如果没有发生冲突,你就完成了。但是在发生冲突的情况下,当cherry-pick失败时,git对使用mergetool没有任何支持,所以从 1 中恢复有点麻烦,所以以下是更好的方法。

$ git checkout -b branch_2 master
$ git rebase -i E
...
# Remove the F1 and G1 commits
...

这可能会导致冲突,就像樱桃选择一样,但我认为git mergetool在这种情况下会起作用(我总是使用自己的脚本......)。如果没有解决冲突或冲突,请继续

$ git rebase --onto B E branch_2

你现在应该

     --F2--G2       <-- branch_2
    /            
A--B------E--F--G   <-- master
    \    /
     C--D           <-- branch_1

1 我有自己的“git add -p”脚本解析git ls-files -u并使用git cat-file获取版本并将其提供给kdiff3。

相关问题