为什么我会在git rebase交互中遇到这种合并冲突? [英] Why do I get this merge conflict with git rebase interactive?

查看:278
本文介绍了为什么我会在git rebase交互中遇到这种合并冲突?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我还在学习git.

我有一个名为names.txt的文件.带有此文字.

I have a file called names.txt. With this text.

这是我的提交历史记录

第一次提交已添加文件. 第二个提交添加了第一行Mary. 第三次提交添加了第二行约翰.

The first commit added the file. The second commit added the first line Mary. The third commit added the second line John.

git show 7bdb5ef

git show 80384aa

我想以此为基础并编辑提交Mary以将文本更改为Mary Shelly.

I want to rebase this and edit the commit Mary to change the text to Mary Shelly.

I do git rebase -i 4a5244b

接下来,我将提交Mary设置为编辑并运行变基.

Next I set commit Mary to edit and run the rebase.

调整停在这里.

现在name.txt的值是Mary commit的值.

Now name.txt has the value at Mary commit.

我将其更改为Mary Shelly并进行登台.

I change it to Mary Shelly and stage it.

我跑步

git commit --amend 

跟着

git rebase --continue

现在我遇到了合并冲突.

Now I get this merge conflict.

我不明白为什么会这样.提交John仅更改文件中的第二行.当我们编辑提交Mary时,我们仅更改文件的第一行. 这怎么引起冲突?

I don't understand why this happens. Commit John only changes the second line in the file. When we edit the commit Mary we only change the first line of the file. How does this cause a conflict?

推荐答案

问题是存在合并冲突,并且

The problem is that there is a merge conflict, and chepner's comment is the key to understanding why. Well, that, and the commit graph, plus the fact that git rebase consists of repeated git cherry-pick operations. Interactive rebase allows you to add your own commands between each git cherry-pick, or even change the cherry-picks to something else. (The initial command-sheet starts out as all-pick commands, each of which means do a cherry-pick.)

您的提交历史记录是您的提交图的摘要-本质上是从某个特定终点(当前分支的尖端)开始并工作的访问该提交图 中的每个提交的结果向后.如果使用git log --graph,您会获得一些潜在的重要信息,而这些信息在没有--graph的情况下就被忽略了,尽管在这种特殊情况下,很容易看到图形是线性的.因此,您只有三个提交:

Your commit history is a summary of your commit graph—essentially, the result of visiting each commit in the commit graph, starting at some particular ending point (the tip of your current branch) and working backwards. If you use git log --graph you get some potentially-important information that is left out without --graph, although in this particular case, it's easy to see that the graph is linear. So you just have three commits:

A <-B <-C   <-- master (HEAD)

其中A实际上是4a5244bB代表7bdb5ef,而C代表80384aa(如果我正确转录了图像).每个提交都具有文件names.txt的完整副本.当然,副本在提交ABC中为不同,因为在A中为空.在B中,它是读取Mary的一行;在C中,有两行分别显示MaryJohn

where A is actually 4a5244b, B stands for 7bdb5ef, and C stands for 80384aa (if I've transcribed the images correctly). Each commit has a full, complete copy of the file names.txt. The copy is of course different in commits A, B, and C, in that in A, it's empty; in B, it is one line reading Mary; and in C, it is two lines reading Mary and then John

图形本身是由于以下事实而产生的:提交C80384aa包含在C本身内部的提交B7bdb5ef 的哈希ID.这就是为什么我从C拔出一个箭头指向B的原因. Git将此称为C parent 提交. Git在名称master中记录C的哈希ID,然后在名称master上附加特殊名称HEAD ,这样它就知道这是git log应该开始,并且提交C是您现在要进行的工作.

The graph itself arises from the fact that commit C, or 80384aa, contains the hash ID of commit B, or 7bdb5ef, inside C itself. That's why I drew an arrow coming out of C pointing to B. Git calls this C's parent commit. Git records C's hash ID in the name master, and then attaches the special name HEAD to the name master, so that it knows that this is where git log should start, and that commit C is the one you have out, for working-on, right now.

运行git rebase -i 4a5244b时-选择commit A作为新的基础-Git指出这意味着 copy提交BC ,因此它将其哈希ID放入pick命令列表.然后,它将在命令表上打开您的编辑器.您将pick更改为edit,这会告诉Git:在执行操作的中间执行樱桃拾取"操作,然后退出rebase.

When you run git rebase -i 4a5244b—choosing commit A as the new base—Git figures out that this means copy commits B and C, so it puts their hash IDs into the list of pick commands. It then opens your editor on the command-sheet. You change pick to edit, which tells Git: Do the cherry-pick, then exit the rebase, in the middle of the operation.

您没有强制重新建立真实副本. (为此,使用-f--no-ff--force-rebase都是相同的意思.这在这里并不重要,在大多数情况下也是如此.)因此,Git看到有一条指令复制B,使其出现在A 之后,并意识到:嘿,等等,B已经在A之后.我会把它留在那里. Git做完了然后停下来,让你保持这种状态:

You didn't force rebase to make a true copy. (To do that, use -f or --no-ff or --force-rebase—all mean the same thing. It doesn't really matter here, nor in most cases.) So Git saw that there was an instruction, Copy B so that it comes after A, and realized: Hey, wait, B is already after A. I'll just leave it there. Git did that and stopped, leaving you in this state:

A--B   <-- HEAD
    \
     C   <-- master

请注意,HEAD不再附加到master:现在它直接指向提交B.提交C仍然存在,并且master仍指向它,但是Git已停止在分离的HEAD"模式下,允许您进行编辑.

Note that HEAD is no longer attached to master: it now points directly to commit B. Commit C remains, and master still points to it, but Git has stopped in "detached HEAD" mode to allow you to do your edit.

您对文件git addgit commit --amend进行了更改.这会产生一个 new 提交-我们可以将其称为B'D,通常我使用B',因为通常它与B很像,但是这次却足够不同了,因此,让我们使用D.新提交将A作为其父级-这就是--amend的作用. Git更新HEAD指向新的提交.现有提交B保持不变.所以现在您有了:

You make your change to the file, git add, and git commit --amend. This makes a new commit—we could call it B' or D, and usually I use B' since usually it's a whole lot like B, but this time it's different enough, so let's use D. The new commit has A as its parent—that's what --amend does. Git updates HEAD to point to the new commit. Existing commit B remains intact. So now you have:

  D   <-- HEAD
 /
A--B
    \
     C   <-- master

D中的文件names.txt具有新的单行,显示为Mary Shelly.

The file names.txt in D has the new single line reading Mary Shelly.

您现在运行git rebase --continue,因此Git继续使用说明表中的内容.它由pick <hash-of-C>组成,这使得Git运行git cherry-pick来复制C.此副本需要在当前提交D之后执行.现有的提交C不会,因此Git这次必须真正完成这项工作.

You now run git rebase --continue, so Git continues with what's left in the instruction sheet. That consists of pick <hash-of-C>, which makes Git run git cherry-pick to copy C. This copy needs to go after the current commit, D. Existing commit C doesn't, so Git has to really do the job this time.

要执行合并操作(要合并),操作-Git需要三个输入.这三个输入是 merge base 提交,当前或--ours提交(有时也称为 local ,特别是git mergetool),另一个是--theirs提交(有时称为 remote ).对于常规合并,基址通常有点远:这是两行提交分开的地方.对于挑剔"和还原"而言,该基础就在提交旁边.此操作的合并基础是C的父提交B

To perform a merge operation—to merge, the action—Git needs three inputs. These three inputs are the merge base commit, the current or --ours commit (also sometimes called local, particularly by git mergetool), and the other or --theirs commit (sometimes called remote). For regular merges, the base is often a bit distant: it's where the two lines of commits diverged. For cherry-pick—and for revert, for that matter—the base is right next to the commit. The merge base of this operation is C's parent commit B!

合并的实际操作包括在整个提交中运行两个git diff命令:

The actual operation of merge consists of running two git diff commands on the entire commits:

  • git diff --find-renames hash-of-base hash-of-ours:我们做了什么更改?
  • git diff --find-renames hash-of-base hash-of-theirs:它们发生了什么变化?

因此,Git现在比较基本的提交B与您当前的/我们的提交D的差异.该差异影响文件names.txt并说:将表示玛丽的一行更改为两行:一读玛丽·雪莱,另一读约翰.然后,Git将BC进行对比.看看他们"(您,之前)做了什么.差异影响文件names.txt并说:在读取文件Mary的行之后,在文件末尾添加读取John的行.

So Git now diffs commit B, the base, vs commit D, your current/ours commit. That diff affects file names.txt and says: change the one line that says Mary to two lines: one reading Mary Shelly, and one reading John. Then Git diffs B vs C, to see what "they" (you, earlier) did. The diff affects file names.txt and says: add the line reading John at the end of the file, after the line reading Mary.

这就是Git在合并冲突部分向您显示的内容:一个文件说用Mary Shelly代替Mary ,另一个文件说 keep Mary并添加John .如果愿意,您可以告诉Git在合并冲突部分保留更多信息.为此,将diff.conflictStyle设置为diff3. (如果未设置,默认值为merge.)

That's what Git shows you in the merge-conflict section: one file says replace Mary with Mary Shelly, the other says keep Mary and add John. If you like, you can tell Git to keep, in the merge-conflict section, more information. To do this, set diff.conflictStyle to diff3. (The default, if it's not set, is merge.)

使用diff3设置,您将看到 base 内容(由|||||||标记)是一行Mary,并且来自冲突提交的两个文件具有分别用Mary ShellyMary +换行John替换了该基数.我发现这种合并冲突更清晰,更易于手动合并.

With the diff3 setting, you'll see that the base content—marked by |||||||—is the one line Mary, and that the two files from the conflicting commits have replaced that base with, respectively, either Mary Shelly or Mary + new line John. I find this kind of merge conflict clearer and easier to merge manually.

无论如何,此时您的工作是想出正确的结果(无论是什么结果)并将其写出并将其复制到索引插槽零中.通常,您只需要编辑Git在工作树中留下的混乱的names.txt,将正确的内容放入其中,然后运行git add names.txt.

In any case, your job at this point is to come up with the correct result—whatever that is—and write that out and copy it into index slot zero. Typically you'll just edit the messy names.txt that Git left in your work-tree, put the right contents into it, and then run git add names.txt.

已解决冲突,请运行git whatever --continue以恢复已停止的任何操作-在这种情况下,请重新设置基准,但这也发生在Cherry-pick和merge中. Git将使用您用git add更新的索引内容进行新的提交,该提交是C的副本:

Having fixed the conflict, run git whatever --continue to resume whatever operation stopped—in this case, rebase, but this happens with cherry-pick and merge as well. Git will use the index contents, which you updated with git add, to make the new commit that's a copy of C:

  D--C'   <-- HEAD
 /
A--B
    \
     C   <-- master

已经到达命令表的末尾,git rebase现在通过将名称master从提交C中移出并将其粘贴到C'(这是它所做的最后一个复制)上来完成,然后重新附加HEAD:

Having reached the end of the command sheet, git rebase now finishes up by yanking the name master off commit C and pasting it onto C', which is the last copy it made, and then re-attaching HEAD:

  D--C'   <-- master (HEAD)
 /
A--B
    \
     C   [abandoned]

这篇关于为什么我会在git rebase交互中遇到这种合并冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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