git:合并两个分支:什么方向?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2351108/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
git: merge two branches: what direction?
提问by Albert
We have the following situation:
我们有以下情况:
A --- B --- C --- ... --- iphone
/
... --- last-working --- ... --- master
Between last-working and iPhone, 32 commits were made. Between last-working and master, a lotof commits were made.
在上次工作和 iPhone 之间,进行了 32 次提交。在 last-working 和 master 之间,进行了很多提交。
What I want now is a new branch where I have iphone and current master merged together. And at some later time, this should be merged into the master.
我现在想要的是一个新的分支,我将 iphone 和当前的 master 合并在一起。稍后,这应该合并到 master 中。
First, I planned to do:
首先,我打算这样做:
git checkout iphone -b iphone31
git merge master
But then I thought, if it would be better to do:
但后来我想,如果这样做会更好:
git checkout master -b iphone31
git merge iphone
Now I am wondering. What would be the difference in the result?Would the merge behave different?
现在我想知道。结果会有什么不同?合并的行为会有所不同吗?
I already tried both and as I have expected, I got manyconflicts because iphone is really old compared to master. Now I wonder about the easiest way to merge them.
我已经尝试了这两种方法,正如我所料,我遇到了很多冲突,因为与 master 相比,iphone 真的很旧。现在我想知道合并它们的最简单方法。
Maybe even starting with master and merging each single commit of iphone into it would be easier? Like doing this:
也许甚至从 master 开始并将 iphone 的每个提交合并到它会更容易?喜欢这样做:
git checkout master -b iphone31
git merge A
git merge B
git merge C
...
git merge iphone
At the very end, when this merge is done (i.e. all conflicts are resolved and it is working), I want to do this:
最后,当这个合并完成时(即所有冲突都解决了并且它正在工作),我想这样做:
git checkout master
git merge iphone31
回答by hlovdal
Regarding the alternatives
关于替代方案
git checkout iphone -b iphone31
git merge master
and
和
git checkout master -b iphone31
git merge iphone
they will have identical ease or difficulty, it is like arguing whether a glass is half full or half empty.
他们将有相同的难易程度,就像争论一个杯子是半满还是半空。
Version tree perception
版本树感知
How we look at version trees are in some way just our arbitrary perception. Let's say that we have a version tree like the following:
我们如何看待版本树在某种程度上只是我们的任意感知。假设我们有一个如下所示的版本树:
A----------+
| |
| |
\_/ \_/
B X
| |
| |
\_/ \_/
C Y
|
|
\_/
D
|
|
\_/
E
And let's say that we want to make a new version Z checked out from Y based on the changes from C to E but not including the changes made from A to C.
假设我们想要根据从 C 到 E 的更改从 Y 检出一个新版本 Z,但不包括从 A 到 C 所做的更改。
"Oh, that will be difficult because there is no common starting point." Well not really. If we just place the objects a little differently in the graphical layout like this
“哦,那会很困难,因为没有共同的起点。” 不是真的。如果我们像这样在图形布局中稍微不同地放置对象
/
C+---------+
| \ |
| |
\_/ |
D B
| / \
| |
\_/ |
E A
|
|
\_/
X
|
|
\_/
Y
now things are starting to look promising. Notice that I have not changed any relation ships here, the arrows all point the same way as in the previous picture and version A is still the common base. Only the layout is changed.
现在事情开始看起来很有希望。请注意,我在这里没有更改任何关系,箭头都指向与上一张图片相同的方向,并且版本 A 仍然是共同的基础。仅更改布局。
But it now trivial to imagine a different tree
但现在想象一棵不同的树是微不足道的
C'---------+
| |
| |
\_/ \_/
D B'
| |
| |
\_/ \_/
E A
|
|
\_/
X
|
|
\_/
Y
where the task would just be to merge version E normally.
任务只是正常合并版本E。
So you can merge anything you want, the only thing that influence the ease or difficulty is the aggregate of changes done between where you select as a starting point or common base and where you merge to. You are not limited to using the natural starting point the your versioning tool suggest.
所以你可以合并任何你想要的东西,唯一影响难易程度的是你选择作为起点或公共基础的地方和你合并到的地方之间所做的更改的聚合。您不仅限于使用版本控制工具建议的自然起点。
This might not be simple with some version control systems/tools,
but if all else fails there
is nothing that stops you from doing this manually by
checking out version C and save the file as file1,
checking out version E and save the file as file2,
checking out version Y and save the file as file3,
and run kdiff3 -o merge_result file1 file2 file3
.
对于某些版本控制系统/工具,这可能并不简单,但是如果所有其他方法都失败了,没有什么可以阻止您通过检查版本 C 并将文件另存为 file1、检查版本 E 并将文件另存为 file2 来手动执行此操作,检出版本 Y 并将文件另存为 file3,然后运行kdiff3 -o merge_result file1 file2 file3
.
Answer
回答
Now for your specific situation it is difficult to say exactly what strategy that will produce the least amount of problems, but if there are many changes that create some kind of conflict it probably is easier to split up and merge smaller parts.
现在,对于您的具体情况,很难确切地说哪种策略会产生最少的问题,但是如果有很多变化会产生某种冲突,那么拆分和合并较小的部分可能会更容易。
My suggestion would be that since there are 32 commits between last-working and iphone, you could for instance start by branching of master and then merge in the first 16 commits. If that turns out to be too much trouble, revert and try to merge the 8 first commits. And so on. In worst case you end up merging each of the 32 commits one by one, but it would probably be easier than having to handle all the accumulated conflicts in one single merge operation (and in that case you are working with a reallydiverging code base).
我的建议是,由于 last-working 和 iphone 之间有 32 个提交,例如,您可以从 master 分支开始,然后合并前 16 个提交。如果结果证明这太麻烦,请还原并尝试合并 8 个首次提交。等等。在最坏的情况下,您最终会一一合并 32 个提交中的每一个,但这可能比必须在一个合并操作中处理所有累积的冲突更容易(在这种情况下,您正在使用真正不同的代码库) .
Tips:
提示:
Draw on paper a version tree and note with arrows what you want to merge. Cross off things as they are done if you split up the process in several steps. This will give you a clearer picture of what you want to achieve, what you have done so far and what is left.
在纸上画一个版本树,并用箭头注明要合并的内容。如果您将过程分成几个步骤,则将已完成的事情划掉。这将使您更清楚地了解您想要实现的目标、到目前为止您已经完成的工作以及还剩下什么。
I can really recommend KDiff3, it is an excellent diff/merge tool.
我真的可以推荐KDiff3,它是一个出色的差异/合并工具。
回答by Ryuu
There is a difference.
它们是有区别的。
Always check out the target branch during a merge(i.e. if merging A into B, checkout B).
在合并期间始终检查目标分支(即,如果将 A 合并到 B,则检查 B)。
Folks often say that the merge direction does not matter, but this is wrong. While the resulting content will be the same regardless of the merge direction, there are several aspects that are different:
人们常说合并方向无所谓,但这是错误的。尽管无论合并方向如何,生成的内容都将相同,但有几个方面不同:
- The diffs listed in the resulting merge-commit will be different depending on the direction.
- Most branch visualizers will decide which branch is "primary" using the merge direction.
- 结果合并提交中列出的差异将根据方向而有所不同。
- 大多数分支可视化器将使用合并方向决定哪个分支是“主要”分支。
To elaborate, imagine this exaggerated example:
为了详细说明,想象一下这个夸张的例子:
- You branched off from MASTER at 1000 commits behind, and named it DEVELOP (or in a tracking-branch scenario, you have not fetch for quite some time).
- You add one commit into DEVELOP. You know there are no conflicts for this change.
- You want to push your changes into MASTER.
- You incorrectly merge MASTER intoDEVELOP (i.e. DEVELOP is checked out during the merge). Then, you push DEVELOP as the new MASTER.
- The diffs in the resulting merge-commit will show all 1000 commits that happened in MASTER, because DEVELOP is the reference point.
- 您在后面 1000 次提交时从 MASTER 分支,并将其命名为 DEVELOP(或者在跟踪分支场景中,您已经有一段时间没有获取了)。
- 您向 DEVELOP 添加一个提交。您知道此更改没有冲突。
- 您想将更改推送到 MASTER。
- 您错误地将 MASTER 合并到DEVELOP(即在合并期间检出 DEVELOP)。然后,您将 DEVELOP 推为新的 MASTER。
- 结果合并提交中的差异将显示 MASTER 中发生的所有 1000 次提交,因为 DEVELOP 是参考点。
Not only is this data useless, it's hard to read what's going on. Most visualizer will make it look like your DEVELOP line was the primary all along, with 1000 commits brought into it.
这些数据不仅无用,而且很难阅读正在发生的事情。大多数可视化工具会让它看起来像你的 DEVELOP 线一直是主要的,有 1000 次提交。
My suggestion is this: Always check out the target branch during a merge(i.e. if merging A into B, checkout B).
我的建议是: 在合并期间始终检查目标分支(即,如果将 A 合并到 B,则检查 B)。
- If you are working on a parallel branch and want to periodically bring in changes from a main branch, then checkout your parallel branch. The diffs will make sense -- you will see the changes done in the main branch w.r.t to your branch.
- When you are done working in parallel and wish to merge your changes into the main branch, checkout the main branch and merge with your parallel branch. The diff again will make sense -- it will show what your parallel changes are w.r.t to the main branch.
- 如果您在并行分支上工作并希望定期从主分支引入更改,请检查您的并行分支。差异将是有意义的——您将看到在主分支中所做的更改与您的分支相关。
- 当您完成并行工作并希望将更改合并到主分支时,请检查主分支并与并行分支合并。diff 再次有意义——它将显示您对主分支的并行更改。
The readability of the log, in my opinion, matters.
在我看来,日志的可读性很重要。
回答by seanhodges
The best approach really depends on whether other people have remote copies of your code. If the masterbranch is only on your local machine, you can use the rebase command to interactively apply the commits from the feature branch into master:
最好的方法实际上取决于其他人是否拥有您代码的远程副本。如果master分支仅在您的本地机器上,您可以使用 rebase 命令以交互方式将来自 feature 分支的提交应用到 master:
git checkout master -b iphone-merge-branch
git rebase -i iphone
Note that this alters the commit history of your new iphone-merge-branchbranch, which may cause problems for anyone else trying to pull your changes into their checkout later on. By contrast, the merge command applies the changes as a new commit, which is safer when collaborating because it doesn't affect the branch history. See this articlefor some useful tips on using rebase.
请注意,这会更改您的新iphone-merge-branch分支的提交历史记录,这可能会给稍后尝试将您的更改拉入他们的结帐的其他人造成问题。相比之下,merge 命令将更改应用为新提交,这在协作时更安全,因为它不会影响分支历史记录。有关使用 rebase 的一些有用提示,请参阅本文。
If you need to keep your commit history in sync, you are better off performing a merge. You can use git mergetoolto interactively fix conflicts one-by-one using a visual diff tool (a tutorial on this can be found here):
如果您需要保持提交历史同步,最好执行合并。您可以使用git mergetool使用可视化差异工具(可以在此处找到有关此的教程)以交互方式逐一修复冲突:
git checkout master -b iphone-merge-branch
git merge iphone
git mergetool -t kdiff3
A third option, if you want absolute control over the process, would be to use git cherry-pick. You can use gitk (or your favourite history viewer) to view the commit hashes in the iphone branch, note them down, and cherry pick them individually into the merging branch - fixing conflicts as you go. An explanation of this process can be found here. This process will be the slowest, but might be the best fall-back option if the other methods do not work out:
第三种选择,如果你想绝对控制这个过程,将使用git cherry-pick。您可以使用 gitk(或您最喜欢的历史查看器)查看 iphone 分支中的提交哈希,记下它们,然后将它们单独挑选到合并分支中 - 随时修复冲突。可以在此处找到此过程的说明。此过程将是最慢的,但如果其他方法不起作用,则可能是最好的回退选项:
gitk iphone
<note down the 35 commit SHA hashes in this branch>
git checkout master -b iphone-merge-branch
git cherry-pick b50788b
git cherry-pick g614590
...
回答by ardsrk
You say:
你说:
iphone branch is very old compared to master
与master相比,iphone分支非常老
Do you really want to merge them both forming a new branch?
你真的想合并它们形成一个新的分支吗?
The purpose of master and iphone branches would now have been very different ( because iphone is very old ). A new branch merging iphone with an ancestor ofmaster would be better? Think about it.
master 和 iphone 分支的目的现在已经大不相同了(因为 iphone 已经很老了)。将 iphone 与master的祖先合并的新分支会更好吗?想想看。
I highly recommend that you read Fun with merges and purposes of branches.
我强烈建议您阅读具有合并和分支目的的乐趣。
After reading that article if you still feel you want to merge iphone and master then @seanhodges explains how to handle the conflicts really well.
读完那篇文章后,如果你仍然觉得你想要合并 iphone 和 master,那么@seanhodges 解释了如何很好地处理冲突。
回答by Thinkeye
You may want to make a local backup of your work before experimenting, so you can restart, if you stop understanding what has happened.
您可能希望在试验之前对您的工作进行本地备份,以便在您不再理解发生的事情时重新开始。
Make a backup branch of your work so not lose it during rebase, if you want to keep it for reference.
如果您想保留它以供参考,请为您的工作创建一个备份分支,以免在变基期间丢失它。
git checkout iphone -b iphone_backup
Create a new branch from master
从 master 创建一个新分支
git checkout master -b iphone31
then rebase on top of it.
然后在它的基础上变基。
git rebase -i --onto iphone31 iphone
Sean above is correct about rebase applying one commit at a time. But don't worry about existing commits on the branch you rebase onto - they will not be changed. Rebase puts new (adapted) commits on top of them. While done one commit at a time you have better control over conflicts. What is important though, you must rebase your work on top of the master and not vice versa, so the history of master won't change.
上面的肖恩关于一次应用一次提交的变基是正确的。但是不要担心您变基到的分支上的现有提交 - 它们不会被更改。Rebase 将新的(适应的)提交放在它们之上。一次完成一次提交时,您可以更好地控制冲突。但重要的是,您必须将您的工作重新建立在 master 之上,而不是相反,因此 master 的历史不会改变。
Alternatively, you can do only
或者,你只能做
git rebase -i master iphone
if you don't care about backing up the iphone branch. Look into rebase documentation for details and alternatives http://git-scm.com/docs/git-rebase.
如果您不关心备份 iphone 分支。查看 rebase 文档以获取详细信息和替代方法http://git-scm.com/docs/git-rebase。