正确地将特征合并到母版中 [英] Correctly merging a feature into master

查看:58
本文介绍了正确地将特征合并到母版中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

当涉及到多个依赖的功能分支时,我总是遇到同样的问题.

I'm always running into the same problem when it comes to having several dependent feature branches.

master ---A---B---C
           \
feature1    D---E---F
                     \
feature2              G---H

我有这样的东西.假设这两个分支都经过审核,我会将 feature1 合并到 master.然后结帐并拉取master,然后结帐并将feature2 重新设置为master.这样做,我总是一遍又一遍地看到相同的冲突,尤其是在几个分支上.

I have something like this. Assuming both of these branches have been reviewed, I will merge feature1 to master. Then checkout and pull master, then checkout and rebase feature2 to master. Doing this, I always end up seeing the same conflicts over and over, especially with several branches.

良好的变基:

我在网上看到在上面的例子中,首先我应该做这样的事情以确保我正确地重新定位:

I've seen online that in the above example, first I should do something like this to make sure I'm rebasing correctly:

Rebase feature1master

master ---A---B---C
           \       \
feature1    \       D'--E'--F'
             \       
feature2      D---E---F---G---H

feature2 重新绑定到新的 feature1 提交

Rebase feature2 onto the new feature1 commits

master ---A---B---C
                   \
feature1            D'--E'--F'
                             \
feature2                      G'--H'

我会使用 git rebase --onto feature1 feature1@{1} feature2 来做到这一点.

I would do this using git rebase --onto feature1 feature1@{1} feature2.

困惑:

据我所知,最好像这样变基,因为当您变基时,您的分支实际上将包含全新的提交(即上面的 FF'),这可能会导致不必要的冲突.

As I understand it, it's better to rebase like this because when you rebase, your branch will actually contain entirely new commits (i.e. F and F' above), which can cause unnecessary conflicts.

考虑到所有这些,正确的方法是:

With all this in mind, what would be the correct approach to:

  • 合并 feature1master
  • feature2 合并到 master`
  • Merge feature1 into master
  • Merge feature2 into master`

我想尝试学习一种推荐的方法,我可以确信我不会每次都遇到与多个依赖分支的痛苦冲突.

I want to try and learn a recommended approach where I can be confident I won't receive painful conflicts every time with several dependent branches.

推荐答案

注意,这个答案分为两部分.第一个是关于rebase的机制,第二个是rebase vs merge.

Note, this answer is two parts. The first is about the mechanics of rebase, and the second is rebase vs merge.

我会使用 git rebase --onto feature1 feature1@{1} feature2

是的:这是通过将参数拆分为 rebase 来实现的:现在不是 feature1,而是 --onto feature1 feature1@{1}.

Yes: this works by splitting the argument to rebase: instead of just feature1, it's now --onto feature1 feature1@{1}.

通常,我们运行 git rebase name,例如,git rebase feature1.我们首先要git checkout feature2.将 feature2 添加到命令的末尾(如上所述)只是为我们执行了这个 git checkout 步骤.所以在这种情况下,我称之为正常".在这里,git rebase 只有一个参数,通常是另一个分支名称,如 feature1.

Normally, we run git rebase name, e.g., git rebase feature1. We have to first git checkout feature2. Adding feature2 to the end of the command (as quoted above) just does this git checkout step for us. So in the case I'm calling "normal" here, there is only one argument to git rebase, typically another branch name like feature1.

但是git rebase 所做的是复制一些提交,为此,它需要知道两件事:

But what git rebase does is to copy some commits, and to do this, it needs to know two things:

  • 复制什么(提交列表),以及
  • 在哪里放置新副本.
  • what to copy (a list of commits), and
  • where to put the new copies.

feature1 这个参数为两者做了繁重的工作.这很好当它工作时,但是对于将 feature2 重新定位到已经重新定位的 feature1,它并不总是有效.

That one argument, feature1, does the heavy lifting for both of these. That's great when it works, but for rebasing feature2 onto the already-rebased feature1, it doesn't always work.

它不起作用的原因(当它不起作用时)与您绘制的图形有关.你用一种奇怪的方式画了它们,左边有分支名称.这种绘图具有误导性:它意味着每个提交都在 一个 分支上,但事实并非如此.

The reason it doesn't work (when it doesn't work) has to do with the graphs you drew. You drew them in a kind of odd way, with branch names on the left. This kind of drawing is misleading: it implies that each commit is on one branch, which just is not true.

这是第一张图:

master ---A---B---C
           \
feature1    D---E---F
                     \
feature2              G---H

问:A 在哪个分支上提交?(技巧问题!)

Q: Which branch is commit A on? (Trick question!)

A:它在所有分支上.

这些图应该用左边的提交和右边标签来绘制,标签指向一个特定的提交——因为这就是这些东西在 Git 中的实际工作方式.这是相同的图表,重新绘制:

These diagrams should be drawn with the commits on the left and the labels on the right, with the labels pointing to one specific commit—because that's how these things actually work in Git. Here's the same diagram, redrawn:

--A--B--C   <-- master
   \
    D--E--F   <-- feature1
           \
            G--H  <-- feature2

通过从右侧开始并沿着从提交到提交的(内部且始终向后指向的)父链接,我们可以看到 CBA 都在 master 上;FEDAfeature1 上;和 HGFED例如,A 位于 feature2 上.

By starting from the right and following the (internal and always backward-pointing) parent links from commit to commit, we can see that C, B, and A are on master; F, E, D, and A are on feature1; and H, G, F, E, D, andA are on feature2, for instance.

现在我们可以绘制第二个图,在第一个git rebase之后,像这样:

Now we can draw the second diagram, after the first git rebase, like this:

          D'-E'-F'   <-- feature1
         /
--A--B--C   <-- master
   \
    D--E--F   [reflog: feature1@{1}]
           \
            G--H  <-- feature2

这就是 git rebase 的拆分参数的用武之地.

This is where the split-up argument to git rebase comes in.

通常,Git 会使用以下命令查找 git rebase 将复制的提交集:

Normally, Git finds the set of commits that git rebase will copy by using:

git rev-list <argument>..<current-branch>

这里将是 feature1..feature2.这意味着可从 feature2 访问的所有提交,除了可从 feature1 访问的所有提交.现在,之前我们移动了feature1,这是一组正确的提交:它是HG.但是我们移动了 feature1,现在它是 错误的 提交集,因为它也包括 FD.

which here would be feature1..feature2. This means all commits reachable from feature2, except for all commits reachable from feature1. Now, before we moved feature1, that was the right set of commits: it was H and G. But we moved feature1 and now it is the wrong set of commits as it includes F back through D too.

一旦我们说feature1@{1}..feature2,我们又得到了正确的一组提交.但是现在我们已经失去了复制的地方,这就是我们需要 --onto 的原因:那是放置副本的位置.

Once we say feature1@{1}..feature2, though, we get the right set of commits again. But now we've lost the place to copy, and this is why we need --onto: that's where to put the copies.

当第二次 rebase 完成时,我们应该绘制这样的最终结果:

When the second rebase finishes, we should draw the final result like this:

                  G'-H'   <-- feature2
                 /
          D'-E'-F'   <-- feature1
         /
--A--B--C   <-- master
   \
    D--E--F   [reflog: feature1@{1}]
           \
            G--H  [reflog: feature2@{1}]

而且由于引用日志通常是不可见的,我们可以完全删除图表的下半部分.

and since the reflogs are normally invisible, we can drop the bottom half of the diagram entirely.

据我所知,最好像这样变基,因为......

As I understand it, it's better to rebase like this because ...

Better 是一个非常模糊的术语.

Better is a very slippery term.

rebase 有两个问题:

There are two issues with rebase:

  • 复制提交,然后放弃原始副本以支持新副本.其他人有原图吗?如果是这样,那你也给他们添麻烦了:他们也必须放弃原件,转而使用新的副本.

  • It copies commits, then abandons the originals in favor of the new copies. Does anyone else have the originals? If so, you've made things difficult for them too: they, too, must abandon the originals in favor of the new copies.

复制提交.新副本至少与原件有些不同(否则它们实际上会成为原件).确切地说,这些副本有什么不同?是不是重要?您是否在此过程中破坏了某些东西,即引入了错误?

It copies commits. The new copies are at least somewhat different from the originals (otherwise they would actually be the originals). What, precisely, is different in the copies? Is it important? Did you break something in the process, i.e., introduce bugs?

使用 git merge 可以避免这些问题.相反,它插入了它自己的问题:

Using git merge avoids these problems. It inserts, instead, its own problems:

  • 现在的历史很纠结.如果要搞清楚到底发生了什么,谁在探索历史,恐怕都得往下看双腿"了.的合并.有些人认为这是积极的,而不是消极的,因为这是真实的历史,而不是后来经过清理的、虚构的历史.

  • The history is now tangled. If it's necessary to figure out what happened, whoever is exploring the history may have to look down both "legs" of the merge. Some argue that this is a positive, rather than a negative, because this is the real history, rather than a later, cleaned-up, artificial history.

(我倾向于支持清理过的历史,但这个论点的双方都有优点.)

(I tend to favor the cleaned-up history but there is merit to both sides of this argument.)

合并本身可能会引入错误.

The merge itself could introduce bugs.

如果您有一组非常好的测试,这有助于解决引入错误"的问题.问题.

If you have a really good set of tests, that helps with both of the "introduce bugs" problems.

如果它足够有帮助,它只会留下一个变基问题(假设您足够聪明,或者有一个不错的工具,可以像这种情况一样执行自己的复杂变基):其他人是否有原件?平衡你对这个问题的回答和你对纠结的历史是否糟糕的回答,以便决定合并还是 rebase.

If it helps enough, it leaves only one rebase problem (assuming you're smart enough, or have a nice tool, to do your own complex rebases like this case): does someone else have the originals? Balance your answer to that question against your answer to whether the tangled history is bad, in order to decide on merge vs rebase.

如果你没有有好的测试,那么... :-)

If you don't have good tests, well... :-)

这篇关于正确地将特征合并到母版中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆