git:将子树从一个分支合并到另一个分支
我在将开发分支的子树合并回集成分支时遇到问题。
我有两个分支,一个用于开发,一个用于集成。开发分支中已经完成了广泛的开发,我想将其中的一部分合并回来。我要合并的特定部分全部包含在开发分支的一个子树中。
我的目录结构是这样的:
[Branch A] [Branch B]
| |
+--Dir1 +--Dir1
+--Dir2 +--Dir2
| | |
+--DirA | +--DirA
| | |
+--File1 | +--File1
+--File2 | +--File2
| +--File3
| +--File4
+--Dir3
我想将Branch B/Dir2/DirA合并到Branch A/Dir2/DirA。我希望合并 File1 和 File2,并在分支 A 中创建 File3 和 File4。我不想选取 Dir3 或 Dir1 中的任何更改。
我已经尝试了 kernel.org 为 合并子树,但是当我执行 git read-tree 时,它们失败了:
error: Entry 'Dir1/DirA/File1' overlaps with 'Dir1/DirA/File1'. Cannot bind.
我尝试使用 子树script 托管在 github 上,但我不太幸运。当我这样做时:
git checkout Branch_A
git subtree merge -P Dir2/DirA Branch_B
我看到 Dir3 已被合并的证据,并且合并因冲突而失败。
我可以挑选要合并的文件,但这对于一个常见且直接的问题来说似乎不必要地复杂。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您想要的可能很简单:
详细信息
此配方将子树从 Branch_B 复制到 Branch_A,并且(可选)还在 git 的项目历史记录中创建合并提交:
切换到 Branch_A,以防您尚未到达。
git checkout Branch_A
(可选)建立合并提交,而不更改工作区中的任何文件 (合并策略“我们的”)。这个“空”提交只是将另一个分支添加为第二个父分支,创建历史链接。如果这对您来说不重要,您可以跳过此步骤;后续步骤不需要它。
git merge Branch_B -s ours
注意:只能在干净的工作空间中执行此操作;如果您修改或暂存了任何文件,此命令可能会失败。
将子树 Dir2/DirA 的内容从 Branch_B 复制到您的工作区,而不更改您的活动分支。
git checkout Branch_B Dir2/DirA
将文件从 Branch_B 提交到 Branch_A。如果省略
--amend
则会为此步骤创建一个新的提交;使用它将使新文件成为早期合并提交的一部分。git commit --amend
步骤3中checkout的形式可能看起来很陌生,但官方文档指出,当不使用这种形式时,习惯的分支切换行为实际上只是一种方便:
因此,如果您确实提供了显式路径,它不会切换分支,只是从该路径复制文件。
What you want may be simply:
Details
This recipe copies a subtree from Branch_B to Branch_A, and (OPTIONALLY) also creates a merge-commit in git's project history:
Switch to Branch_A in case you aren't there already.
git checkout Branch_A
(OPTIONAL) Establish a merge commit, without changing any files in your workspace (merge strategy "ours"). This "empty" commit just adds the other branch as a second parent, creating a history link. If that's unimportant to you, you may skip this step; it's not required for the subsequent step.
git merge Branch_B -s ours
NOTE: only do this in a clean workspace; this command may fail if you have any files modified or staged.
Copy the contents of subtree Dir2/DirA from Branch_B into your workspace, without changing your active branch.
git checkout Branch_B Dir2/DirA
Commit the files from Branch_B into Branch_A. If you omit
--amend
then a new commit is created for this step; using it will make the new files part of the earlier merge commit instead.git commit --amend
The form of checkout in step 3 may seem unfamiliar, but the official documentation states that the customary branch-switching behavior is actually just a convenience when this form is not used:
So if you do supply an explicit path, it will not switch branches, just copy the files from that path.
你遇到的问题是 git 不是为做这样的事情而设计的。考虑以下历史记录,可能会导致问题中出现两个分支
A
和B
:分支
A
指向提交I< /code> 和分支
B
指向提交H
。现在您想要将B
中的一些更改接管到A
中。例如提交
D
和F
修改了Dir2
、E
、G
和H
对Dir1
和Dir3
做了一些事情。因此,实际上您只想将提交D
和F
添加到集成分支A
中。这意味着分支
B
的创建不够仔细,您实际上希望将其重做为(至少)两个干净的主题分支。类似于:如果存在同时涉及
Dir1
和Dir2
的提交,那么这些提交是“坏的”,因为它们不涉及单个主题,而是涉及多个主题事情立即发生。在这种情况下,您可能不仅需要重新调整提交,还需要使用 git-rebase -i 来将提交更改为好的提交。当然,您可以只合并分支 A 并修复生成的树。但这将使得继续处理
A
中的“非合并”更改变得几乎不可能,因为当您合并A
的后代时,您将必须修复再次生成结果树,因为E
、G
和H
的更改不会包含在 git 为您准备的树中,如下所示这些提交已经合并。The problem you have is that git isn't designed to do such a thing. Consider the following history that might result in your two branches
A
andB
from the question:with branch
A
pointing at commitI
and branchB
pointing at commitH
. Now you want to take over some changes inB
intoA
.For example commits
D
andF
modifiedDir2
,E
,G
andH
did something toDir1
andDir3
. So actually you only want to have commitsD
andF
added to your integration branchA
.That means that branch
B
wasn't created carefully enough and you actually want to redo it into (at least) two clean topic branches. Something like:If there are commits that are touching both,
Dir1
andDir2
then these commits are "bad", as they don't address a single topic, but does several things at once. In this case you might want not only reshuffle the commits, but also change the commits to be good ones usinggit-rebase -i
.Of course you could just merge branch
A
and fix-up the resulting tree. But that would make it hardly possible to continue working on the "non-merged" changes inA
, because when you merge a descendant ofA
you would have to fix-up the resulting tree once more, because the changes ofE
,G
andH
would not be included in the tree that git prepares for you, as these commits are already merged.合并子树实际上是指将外部项目的一部分合并到您的项目中。我会参考这篇博客文章来完成您想做的事情: http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/
Merging subtrees really refers to merging part of an external project into your project. I'd refer to this blog post to accomplish what you want to do: http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/
我只需将 dirA 设为子模块并为其引入第三个存储库。
I would simply make dirA a submodule and introduce a 3rd repo for it.