合并成功后Git rebase冲突? [英] Git rebase conflicts after successful merge?

查看:124
本文介绍了合并成功后Git rebase冲突?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个分支:让我们称它们为 master 功能。我现在正试图将最近从主变更到功能。我通常比合并更喜欢rebase,但是这两个分支有显着的分歧,所以我决定做一个合并来记录所有的冲突解决方案。我完成了合并,并将其投入功能,并认为我完成了。一切看起来都不错。

现在,我对主进行了一些小改动,并希望将其重新转换为功能,但 git rebase master 现在让我与在上次合并中已经处理的较旧提交发生冲突。奇怪的是, git merge master 没有按预期发生冲突。什么给了?

解决方案

你的措词(rebase [我通常会将特性转换为 master 。 (into一词并不适用。)除此之外,我认为绘制提交图总是有帮助的。您可以使用 gitk 或类似的查看器来绘制它,或者使用 git log --graph ,或许使用 - oneline 以绘制垂直方向的图。但是在这里我会画一个水平的,用单个大写字母代表特别有趣的提交,小写 o 代表更无聊的提交。



对于我们的目的,我将忽略任何配置的上游( origin / master 和/或 origin / feature )。如果它们确实存在,则可能需要将它们添加到自己的图形中,然后注意,当 git rebase 创建提交副本时,它不会移动任何其他标签(包括这些远程跟踪分支)指向现有提交:它只移动一个标签,即当前分支标签。

  ...  -  A  -  o  -  o  -  o  -  F < -  master 
\\\
B - C - D - E - G < - HEAD - >功能

幸运的是,这相当接近您的预先设定,准确地反映了结果你的 git merge 。在合并之前和之后,提交 A 是原始基础,其中功能从<$ c分离$ C>主;提交 B E 是在功能;各种不太有趣的 o 提交是在 master ;并提交 F 是主控的提示。您在分支功能(以便 HEAD >命名分支功能 >和 git status 在分支功能上说),然后运行 git merge master ,并进行了合并和提交。

这个合并创建了特性中的最小提交,它是提交 G ,这是一个合并提交。



之后,您检出分支 master (使 HEAD 指向名称 master ),并提交了一个新的提交,将 master ,所以让我们将其添加到我们的图表中:

  ...  - A  -  o  -  o  -  o  -  F  -  H  -   -   -   -   -   -   - master 
\\\
B - C - D - E - G < - 特征

最后,你想在 master (的新提示)上重新命名特性 git checkout feature

  ...  -  A  -  o  -  o - ○ -  F  -  H < - 主
\\
B - C - D - E - G < - 头 - >功能

现在运行命令 git rebase master
$ b $ rebase does是 copy 提交。



首先,它必须找到要复制的提交。它应该复制的提交是那些可从当前分支到达的提交 - 即从名称特性 - 但不是来自您作为上游提供的名称的分支,即, master



以下是我们遇到的一个相当大的问题。看看最近的<$ c(相当密集)段落$ c $> git rebase 文档

lockquote

当前分支中的所有更改提交,但是不在
<上游>被保存到临时区域。这是与 git log< upstream> .. HEAD 所显示的相同的一组提交。或 git log'fork_point'.. HEAD ,如果 - fork-point 处于活动状态(请参阅 - 下面的叉点);或者如果指定了 - root 选项, git log HEAD


分叉点本身有点复杂,但现在我们可以忽略它,因为使用命令 git rebase master 意味着它已关闭。因此,您可以通过 git log master..HEAD 查看提交。这是提交 B C D E G (除了通常会发生合并)。

您可能想知道为什么 B E 包含在这里,因为 master 特性是commit G 。问题是,当合并提交 G 指向提交 F (可从master访问)时,提交 F 没有(也不能)指向前到 G 。因此,当我们从 master (新提交 H )的提示开始并向后工作时,我们得到 H F ,所有无聊 o s, A ,以及 A 之前的所有内容:这些是排除的提交 。当我们从特性(提交 G )的提示开始并向后工作时,我们得到 G E D C B ,然后我们点击排除的第一个( A )。因此,这些都是rebasing的候选人。



如果您允许rebase继续进行并解决所有冲突,那么您最终会得到:

  B' -  C' -  D' -  E'<  -  HEAD  - >特征
/
... - A - o - o - o - F - H - -
\\ -
B - C - D - E - G [弃用]

(假设所有待复制的提交都有实际的复制修改;提交 G 不需要复制,因为这次不会提供任何内容)。


I have two branches: let's call them master and feature. I'm now trying to merge recent changes from master into feature. I normally prefer rebases over merges, but these two branches have diverged significantly, so I decided to do a merge instead to have a record of all the conflict resolution. I finished up the merge, and committed it on feature, and thought I was done. Everything looked good.

Now, I made a small change to master and wanted to just rebase that into feature, but git rebase master now gives me conflicts with older commits that were already dealt with in my last merge. Weirdly, git merge master gives no conflicts as expected. What gives?

解决方案

Your phrasing ("rebase [a small change made to master] into feature") seems a bit weird to me, since normally you'll be rebasing feature onto master. (The word "into" doesn't really apply well.) That aside, I think it always helps to draw the commit graph. You can use gitk or a similar viewer to draw it, or git log --graph, perhaps with --oneline as well, to draw a vertically oriented graph. But here I'll draw a horizontal one, with single uppercase letters representing particularly interesting commits, and lowercase os representing more-boring commits.

For our purposes here I will leave out any configured upstreams (origin/master and/or origin/feature). If they do exist, you might want to add them to your own drawing, and then note that when git rebase makes copies of commits, it does not move any of the other labels (including these remote-tracking branches) pointing to existing commits: it only moves one single label, that of the current branch.

... - A - o - o - o - F      <-- master
       \               \
         B - C - D - E - G   <-- HEAD -> feature

With any luck this is reasonably close to your pre-rebase setup, and accurately reflects the result of your git merge. Both before and after you did the merge, commit A is the original base at which feature split off from master; commits B through E were made on feature; the various less-interesting o commits were made on master; and commit F was the tip of master. You were on branch feature (so that HEAD named branch feature, and git status said "on branch feature") and you ran git merge master and did the merge and committed.

This merge created the tip-most commit on feature, which is commit G, which is a merge commit.

After that, you checked out branch master (making HEAD point to the name master) and made a new commit that moved the tip of master, so let's add that to our graph-so-far:

... - A - o - o - o - F - H     <-- HEAD -> master
       \               \
         B - C - D - E - G      <-- feature

Finally, you wanted to rebase feature on the (new tip of) master so you did git checkout feature:

... - A - o - o - o - F - H     <-- master
       \               \
         B - C - D - E - G      <-- HEAD -> feature

and now you run the command git rebase master.

What rebase does is copy commits.

First, it has to find which commits to copy. The commits it should copy are those that are reachable from the current branch—i.e., from the name feature—but not from the branch whose name you give as the upstream, i.e., master.

Here's where we run into a rather large problem. Look at this (rather dense) paragraph from recent git rebase documentation:

All changes made by commits in the current branch but that are not in <upstream> are saved to a temporary area. This is the same set of commits that would be shown by git log <upstream>..HEAD; or by git log 'fork_point'..HEAD, if --fork-point is active (see the description on --fork-point below); or by git log HEAD, if the --root option is specified.

The fork point stuff is itself a bit complicated but we can ignore it for now because using the command git rebase master means it's turned off. You can therefore see the commits that are to be rebased with git log master..HEAD. This is commits B, C, D, E, and G (except that rebase normally tosses out merges).

You might wonder why B through E are included here, given that the merge base of master and feature is commit G. The problem is that, while merge commit G points back at commit F (reachable from master), commit F does not (and cannot) "point forward" to G. So when we start from the tip of master (new commit H) and work backwards, we get H, F, all the boring os, A, and everything before A: these are the commits excluded. When we start from the tip of feature (commit G) and work backwards, we get G, E, D, C, and B before we hit the first excluded one (A). Thus these are the candidates for rebasing.

If you allow the rebase to proceed, and resolve all the conflicts, you'll end up with:

                            B' - C' - D' - E'   <-- HEAD -> feature
                           /
... - A - o - o - o - F - H     <-- master
       \               \
         B - C - D - E - G      [abandoned]

(assuming all of the to-be-copied commits have actual changes to copy; commit G won't need to be copied as it won't contribute anything this time).

这篇关于合并成功后Git rebase冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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