如何在GIT中将一个分支合并到另一个分支?

发布于 2024-08-10 18:49:04 字数 259 浏览 8 评论 0原文

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

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

有什么想法吗?

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

Let me explain the problem in detail.

I have a main git branch on which I created a new side branch bug10101010, now I wan't to merge the bug10101010 to main. So far everything is good.
Now I have a different branch of the same product, named legacy. I wan't to merge the bug10101010 to the legacy branch in GIT.

Any ideas?

I can't just merge it directly, as the branch bug10101010 is spin off from the main branch and in the legacy I need only the diff between the branch bug10101010 and its parent branch.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼泪淡了忧伤 2024-08-17 18:49:04

您应该在此处使用 git rebase --onto 并指定一个范围。
(请参阅 git rebase 手册页

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

)。

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

因此,一种解决方法是在克隆存储库中执行变基操作,然后合并该“增强”遗留分支(克隆存储库中的分支,与bug10 修改)到本地和当前的legacy 分支(您要修改的分支,同时保留 bug10独自的)。

现在:

  • 这涉及到一个额外的存储库(这可能会导致磁盘空间限制)
  • 总而言之,这相当于定义一个补丁并将其应用到legacy分支,所以其他答案(补丁)是有效(并且更简单)。
  • 我在这种方法中看到的唯一优点是有机会定义一个遗留环境,在该环境中您可以在仅推送该分支legacy之前重新设置您想要的内容(例如bug10提交)到您的原始存储库(您不会推送 bug10,因为它的历史记录将被完全重写!)

我只是想看看它是否有效,所以...让我们测试一下该方法。
(Git1.6.5.1,在旧的 XP SP2 上,具有 Powershell 1.0 会话,因为 Start-Transcript 命令)


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 init自 1.6.5 起

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

这太棒了!

让我们创建 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

让我们构建一个legacy分支

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 中进行任何进一步的操作。我只会克隆它来进行一些测试。如果这些失败,我可以随时返回此存储库并再次克隆它。

第一个克隆实际上是强制性的,为了执行我们的 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 进行变基(即 < 之后的所有提交) code>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 已在顶部重放遗留 没有所有其他中间提交
现在,我们可以将 legacyHEAD 快进到重播的 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 开始) code> 标记,并且不会像我们在 rebaseRepo 上那样在任何地方重播。
在此克隆的存储库中,我跟踪 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

在这个原始存储库中(我克隆它只是为了不弄乱 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

我们现在可以更新legacy,而无需触及bug10

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(-)

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

You should use git rebase --onto here, and specify a range.
(see git rebase man page:

transplant a topic branch based on one branch to another, to pretend that you forked the topic branch from the latter branch, using rebase --onto.

).

Of course, this would move your bug10 branch on top of the legacy branch, which is not what you want/need.

So, one workaround would be to do that rebase in a cloned repo, then merge that 'enhanced' legacy branch (the one in the clone repo, with the bug10 modifications on top of it) to the local and current legacy branch (the one you want to modify, while leaving bug10 alone).

Now:

  • this involves an extra repo (which can lead to disk space limitation)
  • all in all, this is fairly equivalent to define a patch and apply it to legacy branch, so the other answers (patch) are valid (and simpler).
  • the only advantage I see in this method is the opportunity to define a legacy environment in which you rebase what you want (like the bug10 commits), before pushing only that branch legacy to your original repo (you would not push bug10, since its history would have been entirely rewritten!)

I just wanted to see if it works, so... Let's test that approach.
(Git1.6.5.1, on a old XP SP2, with a Powershell 1.0 session because of the Start-Transcript command)


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

I like how I do not have anymore to make the git repo directory first, then type in it git init! Since 1.6.5:

"git init" learned to mkdir/chdir into a directory when given an extra argument (i.e. "git init this").

This is GREAT!

Let's create 3 files, for 3 different purposes.
(For the sake of example, I will keep the file modifications separate per branch: no conflict during merge or rebase here.)

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

At this point, a git log --graph --oneline --branches returns:

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

Let's build a 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"

We return to master, make another commit, which we will tag "2.0" (a release which will need some bug-fixing!)

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

We have:

* 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

Now we do a bug10 bug-fixing branch:

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"

Let's add a final commit on the main branch

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"

Final state of our main repo:

* 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

At this stage, I will not make any further manipulation in mainRepo. I will only clone it to make some tests. If those fails, I can always get back to this repo and clone it again.

The first clone is actually mandatory, in order to perform our git rebase --onto

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

We need two of the mainRepo branches in our cloned repo:

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

Let's rebase only bug10 (that is all commits after 2.0 tag up to HEAD of bug10 branch):

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

At this point bug10 has been replayed on top of legacy without all the other intermediate commits.
We can now fast-forward HEADof legacy to the top of the replayed bug10 branch.

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(-)

The content follow what we need:

  • We do have all the legacy content:

 

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

 

  • the content for the main branch is there only up to 1.0 tag (root for legacy branch), and not any further.

 

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

 

  • and the bug10 fixes are here:

 

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

 

That's it.
The idea is to to pull that 'enhanced' legacy branch in your original repo, which will still have its bug10 unchanged (i.e. still starting from the 2.0 tag, and not replayed anywhere like we did on the rebaseRepo.
In this cloned repo, I track the origin/legacy branch, in order to merge on it the legacy branch of another remote source: the 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

In this original repo (I only cloned it to not mess with the state of the mainRepo, in case I had some other experiments to do), I will declare rebaseRepo as a remote, and fetch its branches.

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

We can now update legacy without touching to bug10:

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(-)

You can repeat the process as many time as you want, whenever new bug10 commits need to be replayed on top of an old legacy branch, without including all the intermediate commits.

追我者格杀勿论 2024-08-17 18:49:04

这很难做到。 Git 保存合并历史记录,如果你“cherrypick”并指向 bug10101010 中的提交作为父项(表明你已经完成了合并),Git 会假设之前的所有提交(回到它们拆分的点)都已合并为出色地。当您想要进行“真正的”合并时会给您带来问题。

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

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

这是关于该主题的有趣博客文章

This is hard to do. Git saves merge history, and if you "cherrypick" and point at a commit in bug10101010 as a parent (indicating you have done a merge) Git will assume that all commits before that (back to the point where they split) as been merged as well. Giving you problems when you want to do a "real" merge.

On the other hand you can just manually generate a patch from that (and only that) specific commit. But that will also give you problems when you later do the "real" merge, since it tries to apply your manually handled commit twice.

But then again, since one branch is named "Legacy" I suspect that you dont plan to do that real merge anyway, in which case youre pretty much free to do it anyway you please.

Heres an interesting blog post on the topic.

原来是傀儡 2024-08-17 18:49:04

使用 git-diff 然后 git-apply

Use git-diff and then git-apply?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文