合并两个分支,如何为所有冲突接受一个分支 [英] Merging two branches, how do I accept one branch for all conflicts

查看:167
本文介绍了合并两个分支,如何为所有冲突接受一个分支的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将两个分支合并在一起,让我们说branchA和branchB.他们有大约100个有冲突的文件.

Im merging two branches together, lets say branchA and branchB. They have about 100 files that conflict.

branchB可以接受所有工作,并且100%是我所需要的.我不想强制推送branchB或其他任何内容.

branchB has the accepted work for everything and is 100% what I need. I don't want to force push branchB or anything.

有没有办法将两者合并,并且说出任何冲突,请接受branchB上的内容,这样我就不必打开每个文件或他们的"或我们的"每个文件.

Is there a way I can merge the two and just say for any conflict accept whats on branchB so I don't have to open the files or "theirs" or "ours" every single file.

正在尝试从branchB进行递归合并,并使用-s和-x选项拉出branchA,但这似乎没有按预期工作

was trying a recursive merge from branchB pulling branchA with the -s and -x option in but that didnt seem to work as expected

谢谢

推荐答案

给出您的要求,答案就是简单的顺序:

Given what you asked, the answer is the simple sequence:

git checkout branchA
git merge -X theirs branchB

在盲目应用此功能之前,请确保您知道自己在做什么!您还说过您使用了-s-x,但是git merge没有-x选项. (也许您的意思是-X.显示您使用的实际命令和至少某些结果可能会有所帮助.)如果您得到了我所说的高级冲突-X选项将无济于事,您需要进行一些手动清理,但是您可以自动化其中的一部分甚至全部.

Before you blindly apply this, make sure you know what you are doing! You also say that you used -s and -x, but git merge does not have a -x option. (Perhaps you meant -X. Showing the actual commands you used, and at least some of the results, would probably have helped.) If you got what I call high level conflicts, the -X option won't help and you'll need to do some manual cleanup, but you can automate some or even all of it.

请记住,git merge所做的是对 combine 进行更改.为此,它需要找到一个共同的起点.假设您是在BranchA上工作的Alice或Adam,或者在branchB上工作的Bob或Barbara.用户"A"从某些提交*开始,进行了更多的提交o以结束A结尾:

Remember that what git merge does is to combine changes. To do this, it needs to find a common starting point. Let's say you're either Alice or Adam, working on branchA, or Bob or Barbara, working on branchB. User "A" started from some commit * and made some more commits o ending in commit A:

          o--o--A   <-- branchA
         /
...--o--*

与此同时,用户"B"从完全相同的提交(标为*的那个)开始,并进行了一些提交:

Meanwhile, user "B" started from the exact same commit, the one labeled *, and made some commits:

...--o--*
         \
          o--o--B   <-- branchB

例如,在运行git fetch之后,您现在在存储库中拥有的是完整的提交集:

What you have now, in your repository, after running git fetch for instance, is the complete set of commits:

          o--o--A   <-- branchA
         /
...--o--*
         \
          o--o--B   <-- branchB

当您运行git checkout brachA; git merge branchB时,您会为自己的Git find 提交*-这是你们俩都从那里开始的,但是历史可能很久了-然后您有了您的Git运行两个diff命令:

When you run git checkout brachA; git merge branchB you have your Git find commit * for you—this is the one you both started from, however far back it may be in history—and then you have your Git run two diff commands:

git diff --find-renames <hash-of-*> <hash-of-A>
git diff --find-renames <hash-of-*> <hash-of-B>

如果可以的话,Git现在将尝试合并这两组更改,并将其应用于提交*中的所有更改.如果Git能够自己完成所有这些操作,它会进行最终的 merge commit -几乎是普通的提交,除了它有两个父指针,它们都指向commit A和commit B.这也会将名称branchA更改为也指向新的提交,从而给出:

Git will now attempt, if it can, to combine both sets of changes, applying them to whatever was in commit *. If Git can do all of this on its own, it makes a final merge commit—an almost-ordinary commit, except that it has two parent pointers, pointing back to both commit A and commit B. This changes the name branchA to point to the new commit as well, giving:

          o--o--A
         /       \
...--o--*         M   <-- branchA (HEAD)
         \       /
          o--o--B   <-- branchB

与新提交M关联的快照是Git结合以下更改(*A)及其更改(*B)应用的结果到*. (在此过程中,任何中间提交都将被完全忽略.Git仅对将两个变更集的并集应用于*感兴趣.)

The snapshot associated with new commit M is the result of Git's combination of your changes—* vs A—with their changes, * vs B, applied to *. (Any intermediate commits are completely ignored during this process. Git is only interested in applying to * the union of your two change-sets.)

* -vs- A中对某些文件的某些更改与* -vs- B中对某些文件的某些更改冲突时,Git通常会因合并冲突而停止.大写的-X选项可让您告诉Git,如果发生冲突, ,它应该使用我们的"(* -vs- A)或他们的"(* -vs- B)更改.但是,如果没有冲突,Git会继续进行两项变更.这适用于在单个文件中.一个例子可能会有所帮助.

When some change(s) to some file(s) in *-vs-A conflict with some change(s) to some file(s) in *-vs-B, Git will typically stop with a merge conflict. The uppercase -X option lets you tell Git that, in the event of a conflict, it should prefer either "our" (*-vs-A) or "their" (*-vs-B) change. However, if there isn't a conflict, Git will go ahead and take both changes. This applies within a single file. An example may help.

假设* -vs- A更改集包括文件README.txt的这些说明:

Suppose that the *-vs-A change-set includes these instructions for file README.txt:

  • 在第3行上将单词"yellow"更改为"brown"(实际上,整个行都已更改,但在这里让我们使用"word".)

  • Change the word "yellow" to "brown" on line 3. (It actually sees the whole line as changed, but let's go with "word" here.)

在第20行将黄牛"改为棕牛".

Change the words "the yellow cow" to "a brown cow" on line 20.

假设* -vs- B更改集包括文件README.txt的这些指令:

Suppose that the *-vs-B change-set includes these instructions for file README.txt:

  • 在第20行将黄牛"改为大黄牛".

由于两个更改集都尝试更改第20行,因此您将在此处遇到冲突.因为只有 one 变更集会更改第3行,所以该变更不会冲突,因此Git会应用它.使用-X theirs,Git将更愿意在第20行进行更改,即使将第3行更改为棕色",Git现在仍将带有大黄牛"一词.

Because both change-sets try to change line 20, you will get a conflict here. Because only one change-set changes line 3, that change will not conflict, so Git will apply it. With -X theirs, Git will prefer their change on line 20, which will now have the words "the large yellow cow" even though it changed line 3 to "brown".

给出-X theirs Git 认为这是正确的解决方案:您的无冲突的更改带到第3行,然后 与第20行的更改冲突.这很可能是错误的,但这就是Git要做的.有时最好让冲突发生,然后亲自检查一下事情,看看正确的解决方案是什么;但是,如果您进行了良好的测试,则无论如何,您都应该抓住大多数逃避Git的问题,因此-X theirs(或-X ours)是一个有用的工具.

Given -X theirs, Git thinks this is the correct resolution: take your unconflicted change to line 3, and their conflicted change to line 20. It's quite likely wrong, but that's what Git will do. It's sometimes better to let the conflict happen, and then go inspect things yourself to see what the correct resolution is; but if you have good tests, you should catch most problems that escape Git anyway, so -X theirs (or -X ours) is a useful tool.

如果您确实已经使用过-X theirs并且仍然存在冲突,那么您所拥有的就是我所说的高级冲突.请注意,上面的两个git diff命令用于查找从*A以及从*B的更改集,都使用--find-renames.这意味着在*A之间,Git可能会决定您(或用户A)将重命名 README.txtREADME.rst.用户B也将其重命名,但是重命名为read-me.rst. Git不知道使用哪个名称,并且-X theirs不告诉它:使用其名称. Git只是因冲突而停止.

If you did already use -X theirs and still have conflicts, what you have are what I call high level conflicts. Note that the two git diff commands above, to find the change-sets from * to A, and from * to B, both use --find-renames. This means that between * and A, Git may decide that you (or user A anyway) renamed README.txt to README.rst. User B renamed it as well, but to read-me.rst. Git does not know which name to use, and -X theirs does not tell it: use their name. Git just stops with a conflict.

如果您都添加了一个具有相同名称的新文件,或者您修改了某个文件并将其删除,则发生了类似的高级冲突.前者是添加/添加冲突,后者是修改/删除冲突.还有更多这样的冲突.所有这些都意味着Git要么不知道要保留哪个文件,要么不知道要使用哪个名称.

Similar high-level conflicts occur if you both added a new file with the same name, or if you modified some file and they deleted it or vice versa. The former is an add/add conflict, and the latter is a modify/delete conflict. There are several more such conflicts. All of them mean that Git either doesn't know which file(s) to keep or which name to use.

在所有这些情况下,Git都会因合并冲突而停止,就像您不使用-X一样.当Git确实停止这种方式时,它将 all 文件保留在索引/暂存区域中,并使用 stage number 来识别哪个文件.例如,如果README.txt中存在冲突,则索引中现在存在 README.txt的三个副本:

In all of these cases, Git will stop with a merge conflict, just as it would if you had not used -X. When Git does stop this way, it leaves all the files in the index / staging-area, using stage numbers to identify which one is which. For instance, if there are conflicts in README.txt, there are now three copies of README.txt in the index:

  • :1:README.txt是来自基本提交(提交*)的版本.
  • :2:README.txt是来自HEAD提交(提交A)的版本.
  • :3:README.txt是他们提交的版本,提交B.
  • :1:README.txt is the version from the base commit, commit *.
  • :2:README.txt is the version from the HEAD commit, commit A.
  • :3:README.txt is the version from their commit, commit B.

对于添加/添加冲突,版本1不存在(该文件不在基础文件中).对于修改/删除冲突,版本2或3不存在(该文件已在AB中删除).

For add/add conflicts, version 1 does not exist (the file was not in the base). For modify/delete conflicts, either of versions 2 or 3 does not exist (the file was deleted in A or B).

您可以在这些名称上使用git show:例如,git show :1:README.txt以查看基本版本.

You can use git show on these names: git show :1:README.txt to see the base version, for instance.

工作树具有README.txt一个副本,这通常是Git尽最大努力将这三个输入(可能带有冲突标记)组合在一起的方式.

The work-tree has one copy of README.txt, which is typically Git's best-effort at combining the three inputs, perhaps with conflict markers.

您现在的任务是为文件创建阶段0条目:0:README.txt,以清除阶段1-2-3的条目.最简单的方法是编辑工作树文件并运行git add README.txt. git add命令将工作树中的所有内容复制到阶段0,如果存在阶段1-3,则将其删除.

Your task is now to create a stage-zero entry, :0:README.txt, for the file, wiping out the stages 1-2-3 entries. The easiest way to do that is often to edit the work-tree file and run git add README.txt. The git add command copies whatever is in the work-tree into stage zero, removing stages 1-3 if they exist.

您还可以运行:

git checkout --ours README.txt

或:

git checkout --theirs README.txt

将从索引分别复制版本2或版本3到工作树.请注意,这不会影响索引内容!它只会从索引中提取 (记住,这也称为暂存区域,但是其中有三个条目尚未暂存)到工作树.

which will copy version 2 or version 3 respectively, from the index, to the work-tree. Note that this does not affect the index contents! It only extracts from the index—remember, this is also called the staging area, but with three entries in it none of them are staged yet—to the work-tree.

您还可以运行:

git checkout branchA -- README.txt

或:

git checkout branchB -- README.txt

将这些文件从 commit A或commit B复制 committed 文件到阶段0的索引中,然后从索引复制到工作树.复制到阶段0使得文件已准备就绪,因为它已经擦除了插槽1-3的条目.

These copy the committed file from commit A or commit B, into the index at stage zero, and then from the index to the work-tree. The copying into stage-zero makes the file ready to be committed, as it has wiped out the slot 1-3 entries.

您还可以运行:

git rm README.txt

这将在所有阶段和工作树中删除文件. (仅当正确的合并结果应缺少文件README.txt时,才应执行此操作.)

which will remove the file from all stages and from the work-tree. (You should do this only if the correct merge result should lack the file README.txt.)

请注意,您可以从编写的脚本中执行任何这些操作.您可以使用git ls-files --stage检查索引.在合并期间,冲突文件及其非零阶段号将显示在此处.或者,您可以使用git ls-files -u仅显示未合并(阶段大于零)的条目.

Note that you can do any of these actions from a script that you write. You can use git ls-files --stage to examine the index. During a merge, the conflicted files and their nonzero stage numbers will show up here. Or, you can use git ls-files -u to show only the unmerged (stage greater than zero) entries.

因此,如果在使用-X theirs时遇到合并冲突后运行git ls-files -u,您将看到仍然存在问题的文件集,根据定义,所有这些文件都是由于高级冲突而导致的.然后,您可以由此确定是否可以进行en-masse操作以提取所有此类文件的版本.如果是这样,只需编写一个简短的命令或脚本即可获取所有这些文件名,并将它们传递给git checkout branchB,例如:

Hence, if you run git ls-files -u after getting merge conflicts while using -X theirs, you will see the set of files that still have issues, all of which are by definition due to high level conflicts. You can then decide from this whether it is OK to do an en-masse operation to extract their version of all such files. If so, simply write a short command or script to take all those file names and pass them to git checkout branchB, e.g.:

git ls-files -u | cut -d$'\t' -f 2 | uniq | xargs git checkout branchB --

(只要文件名中没有空格).

(as long as no file names have white-space in them).

这篇关于合并两个分支,如何为所有冲突接受一个分支的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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