【问题标题】:How to merge a branch to another branch in GIT?如何将一个分支合并到 GIT 中的另一个分支?
【发布时间】:2010-12-15 19:02:59
【问题描述】:

让我详细解释一下这个问题。

我有一个主 git 分支,我在其上创建了一个新的侧分支 bug10101010,现在我不想将 bug10101010 合并到主分支。到目前为止一切都很好。 现在我有一个相同产品的不同分支,名为 legacy。我不想将 bug10101010 合并到 GIT 中的遗留分支。

有什么想法吗?

我不能直接合并它,因为分支 bug10101010 是从主分支分拆出来的,而在旧版中,我只需要分支 bug10101010 与其父分支之间的差异。

【问题讨论】:

  • @Priyank:我同意,补丁更简单。但我描述的方法并不复杂。它还说明了您可以轻松地克隆 repo 并进行任何您想要的 Git 操作,前提是您没有从那里推送。

标签: git branch


【解决方案1】:

您应该在此处使用 git rebase --onto,并指定一个范围。
(见git rebase man page

将基于一个分支的主题分支移植到另一个分支,以假装您从后一个分支分叉出主题分支,使用rebase --onto

)。

当然,这会将您的 bug10 分支移动到 legacy 分支之上,这不是您想要/需要的。

因此,一种解决方法是在克隆的存储库中执行该变基,然后合并该“增强”legacy 分支(克隆存储库中的分支,带有 bug10 修改最重要的是)到本地和当前的legacy 分支(您要修改的分支,同时不理会bug10)。

现在:

  • 这涉及额外的存储库(可能导致磁盘空间限制)
  • 总而言之,这相当于定义一个补丁并将其应用于legacy 分支,因此其他答案(补丁)是有效的(并且更简单)。
  • 我在这种方法中看到的唯一优势是有机会定义一个遗留环境,在该环境中你重新定义你想要的东西(比如 bug10 提交),然后只将那个分支 legacy 推送到你的原始仓库(你会不要推bug10,因为它的历史会被完全改写!)

我只是想看看它是否有效,所以...让我们测试一下这种方法。
(Git1.6.5.1,在旧的 XP SP2 上,由于 Start-Transcript command 而使用 Powershell 1.0 会话)


PS D:\> mkdir git
PS D:\> cd git
PS D:\git> mkdir tests
PS D:\git> cd tests
PS D:\git\tests> git init mainRepo

我喜欢不用先创建 git repo 目录,然后输入git initSince 1.6.5:

git init”在给定额外参数(即“git init this”)时学会将mkdir/chdir 放入目录中。

这太棒了!

让我们创建 3 个文件,用于 3 个不同的目的。
(为了举例,我将每个分支分开文件修改:在合并或变基期间没有冲突。)

PS D:\git\tests> cd mainRepo
PS D:\git\tests\mainRepo> echo mainFile > mainFile.txt
PS D:\git\tests\mainRepo> echo contentToBeFixed > toBeFixedFile.txt
PS D:\git\tests\mainRepo> echo legacyContent > legacy.txt
PS D:\git\tests\mainRepo> git add -A
PS D:\git\tests\mainRepo> git ci -m "first commit"
PS D:\git\tests\mainRepo> echo firstMainEvol >> mainFile.txt
PS D:\git\tests\mainRepo> git ci -a -m "first evol, for making 1.0"
PS D:\git\tests\mainRepo> git tag -m "1.0 legacy content" 1.0

此时,git log --graph --oneline --branches 返回:

* b68c1f5 first evol, for making 1.0
* 93f9f7c first commit

让我们建立一个legacybranch

PS D:\git\tests\mainRepo> git co -b legacy
PS D:\git\tests\mainRepo> echo aFirstLegacyEvol >> legacy.txt
PS D:\git\tests\mainRepo> git ci -a -m "a first legacy evolution"

我们回到master,再次提交,我们将标记为“2.0”(需要一些错误修复的版本!)

PS D:\git\tests\mainRepo> git co -b master
PS D:\git\tests\mainRepo> git co master
PS D:\git\tests\mainRepo> echo aMainEvol >> mainFile.txt
PS D:\git\tests\mainRepo> git ci -a -m "a main evol"
PS D:\git\tests\mainRepo> echo aSecondMainEvolFor2.0 >> mainFile.txt
PS D:\git\tests\mainRepo> git ci -a -m "a second evol for 2.0"
PS D:\git\tests\mainRepo> git tag -m "main 2.0 before bugfix" 2.0

我们有:

* e727105 a second evol for 2.0
* 473d44e a main evol
| * dbcc7aa a first legacy evolution
|/
* b68c1f5 first evol, for making 1.0
* 93f9f7c first commit

现在我们做一个bug10 错误修复分支:

PS D:\git\tests\mainRepo> git co -b bug10
PS D:\git\tests\mainRepo> echo aFirstBug10Fix >> toBeFixedFile.txt
PS D:\git\tests\mainRepo> git ci -a -m "a first bug10 fix"
PS D:\git\tests\mainRepo> echo aSecondBug10Fix >> toBeFixedFile.txt
PS D:\git\tests\mainRepo> git ci -a -m "a second bug10 fix"

让我们在主分支上添加一个最终提交

PS D:\git\tests\mainRepo> git co master
PS D:\git\tests\mainRepo> echo anotherMainEvol >> mainFile.txt
PS D:\git\tests\mainRepo> git ci -a -m "another main evol"

我们主仓库的最终状态:

* 55aac85 another main evol
| * 47e6ee1 a second bug10 fix
| * 8183707 a first bug10 fix
|/
* e727105 a second evol for 2.0
* 473d44e a main evol
| * dbcc7aa a first legacy evolution
|/
* b68c1f5 first evol, for making 1.0
* 93f9f7c first commit

在这个阶段,我不会对 mainRepo 做任何进一步的操作。我只会克隆它以进行一些测试。如果这些都失败了,我总是可以回到这个 repo 并再次克隆它。

第一个克隆实际上是强制性的,为了执行我们的git rebase --onto

PS D:\git\tests\mainRepo> cd ..
PS D:\git\tests> git clone mainRepo rebaseRepo
PS D:\git\tests> cd rebaseRepo

我们需要克隆仓库中的两个 mainRepo 分支:

PS D:\git\tests\rebaseRepo> git co -b bug10 origin/bug10
PS D:\git\tests\rebaseRepo> git co -b legacy origin/legacy

让我们仅对 bug10 进行变基(即在 2.0 标记之后直到 bug10 分支的 HEAD 的所有提交)

PS D:\git\tests\rebaseRepo> git co bug10
PS D:\git\tests\rebaseRepo> git rebase --onto legacy 2.0
First, rewinding head to replay your work on top of it...
Applying: a first bug10 fix
Applying: a second bug10 fix

此时bug10 已在legacy 之上重放没有所有其他中间提交
我们现在可以将HEADof legacy 快进到重放的bug10 分支的顶部。

PS D:\git\tests\rebaseRepo> git co legacy
Switched to branch 'legacy'
PS D:\git\tests\rebaseRepo> git merge bug10
Updating dbcc7aa..cf02bfc
Fast forward
 toBeFixedFile.txt |  Bin 38 -> 104 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)

内容符合我们的需要:

  • 我们确实拥有所有遗留内容:

 

PS D:\git\tests\rebaseRepo> type legacy.txt
legacyContent
aFirstLegacyEvol

 

  • main 分支的内容仅存在于 1.0 标记(legacy 分支的根),并且没有更多

 

PS D:\git\tests\rebaseRepo> type mainFile.txt
mainFile
firstMainEvol

 

  • bug10 修复在这里:

 

PS D:\git\tests\rebaseRepo> type toBeFixedFile.txt
contentToBeFixed
aFirstBug10Fix
aSecondBug10Fix

 

就是这样。
我们的想法是在您的原始存储库中拉出“增强的”legacy 分支,它的bug10 仍将保持不变(即仍然从2.0 标签开始,并且不会像我们在@987654378 上所做的那样在任何地方重播@.
在这个克隆的 repo 中,我跟踪 origin/legacy 分支,以便在其上合并 另一个 远程源的 legacy 分支:rebaseRepo

PS D:\git\tests\rebaseRepo> cd ..
PS D:\git\tests> git clone mainRepo finalRepo
PS D:\git\tests> cd finalRepo

PS D:\git\tests\finalRepo> git co -b legacy origin/legacy

在这个原始 repo 中(我只是为了不弄乱 mainRepo 的状态而克隆它,以防我有其他实验要做),我将声明 rebaseRepo 为远程,并获取它的分支。

PS D:\git\tests\finalRepo> git remote add rebasedRepo D:/git/tests/rebaseRepo
PS D:\git\tests\finalRepo> type D:\git\tests\finalRepo\.git\config
[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = D:/git/tests/mainRepo
[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "legacy"]
    remote = origin
    merge = refs/heads/legacy
[remote "rebasedRepo"]
    url = D:/git/tests/rebaseRepo
    fetch = +refs/heads/*:refs/remotes/rebasedRepo/*

PS D:\git\tests\finalRepo> git fetch rebasedRepo
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6 (delta 3), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From D:/git/tests/rebaseRepo
 * [new branch]      bug10      -> rebasedRepo/bug10
 * [new branch]      legacy     -> rebasedRepo/legacy
 * [new branch]      master     -> rebasedRepo/master

我们现在可以在不接触bug10 的情况下更新legacy

PS D:\git\tests\finalRepo> git merge rebasedRepo/legacy
Updating dbcc7aa..4919b68
Fast forward
 toBeFixedFile.txt |  Bin 38 -> 104 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)

只要需要在旧的legacy 分支上重放新的bug10 提交,您就可以多次重复该过程,而不包括所有中间提交。

【讨论】:

  • 我必须说哇!,但我几乎对这些步骤感到困惑,而且对于像我这样的新手来说,这似乎太复杂了。我只是使用手动补丁方式。 git diff label label~ 然后 git apply,这对我来说似乎很容易。
  • 最后master分支没有bug10的变化,对吧?我认为原始发布者(和我)想要的是在 legacy 和 master 分支中都有 bug10?
  • @huggie OP 确实提到了“我不想”,四年多以前,我的解释肯定有所不同。
【解决方案2】:

这很难做到。 Git 保存合并历史记录,如果您“挑选”并指向 bug10101010 中的提交作为父级(表明您已完成合并),Git 将假定在此之前的所有提交(返回到它们拆分的点)已合并为好吧。当您想要进行“真正的”合并时给您带来问题。

另一方面,您可以手动从那个(并且只有那个)特定的提交中生成一个补丁。但是,当您稍后进行“真正的”合并时,这也会给您带来问题,因为它会尝试应用您手动处理的提交两次。

但是话又说回来,由于一个分支被命名为“Legacy”,我怀疑您无论如何都不打算进行真正的合并,在这种情况下,您几乎可以随意进行。

这是interesting blog post on the topic

【讨论】:

  • 感谢您提供的精彩链接。那么,您的建议是什么,以及如何执行上述操作。或者让我换个说法:我需要能够创建始终合并到 main 的特定于 bug 的事务,但需要能够在其他分支上随意重放这些事务。
  • “总是合并到主目录”是什么意思?一个特定的 bug 分支应该只需要合并回主分支一次。如果我的一般答案,加上博客链接和一般 git 文档,没有让您获得任何地方,您可能会考虑更新您的原始问题,详细说明您的目标具体工作流程。那我也许能帮上忙。
  • 问题相同,分支 bug10101010 合并到主分支,因为所有错误修复都必须存在于主分支中。但是,您如何将已完成分支 bug10101010 中相对于其父级的特定更改合并到遗留分支。正如您建议手动生成一个补丁并应用它,但这样做我失去了跟踪此更改来自此分支的能力。
  • 那么 bug 分支是从遗留分支分支出来的,而遗留分支本身是从主分支分支的?现在bug分支应该合并回main然后删除(既然bug分支的目的,修复bug,就实现了)?
  • bug 分支是从 main 分支而不是从 legacy 分支,因为可以有 legacy 1.0.3、legacy 2.0.3 等。bug 分支的想法是创建一个事务,相同当您手动创建补丁时。
【解决方案3】:

使用git-diff,然后使用git-apply

【讨论】:

  • 那么您将如何跟踪,您合并的内容来自分支 bug10101010,这基本上只是一个事务。它也不是直截了当的。我需要能够仅指定分支名称并合并更改。
  • 这个想法也是创建一个错误事务(使用小分支)并重放这些事务,毫不费力地到任何地方(任何分支)。创建补丁和合并补丁,也可以在 CVS/SVN 中完成,然后转移到 Git 没有用。
  • 如果分支是一个事务,是否应该在其目的完成后,有效地删除分支,从而简单地记录补丁是针对 bugXXXXXXXXX 的修复就足够了?既然事务的重点是封装更改,那么可以将其总和作为聚合进行跟踪?
猜你喜欢
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
  • 2016-03-23
  • 2014-10-28
  • 1970-01-01
  • 2017-08-04
相关资源
最近更新 更多