合并两个分支,如何为所有冲突接受一个分支

时间:2018-06-22 15:58:21

标签: git git-merge

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

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

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

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

谢谢

2 个答案:

答案 0 :(得分:5)

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

git checkout branchA
git merge -X theirs branchB

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

合并要领

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

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

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

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

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

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

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

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

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

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

与新提交M相关的快照是Git将您的更改{*A –及其更改{{1 }}与*相比较,应用于B。 (在此过程中,任何中间提交都将被完全忽略。Git只想将两个变更集的并集应用于*。)

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

假设B-vs-*变更集包含文件A的以下说明:

  • 在第3行上将单词“ yellow”更改为“ brown”(它实际上看到整行都已更改,但在这里让我们使用“ word”。)

  • 在第20行将“黄牛”改为“棕牛”。

假设README.txt-vs-*变更集包含文件B的以下说明:

  • 在第20行将“黄牛”改为“大黄牛”。

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

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

高级冲突

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

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

在所有这些情况下,Git都会因合并冲突而停止,就像您没有使用read-me.rst一样。当Git停止这种方式时,它会使用阶段编号来识别哪个文件,从而将 all 文件留在索引/暂存区域中。例如,如果-X theirs中存在冲突,则索引中现在有-X三份

  • README.txt是基础提交的版本,即提交README.txt
  • :1:README.txt*提交,:2:README.txt提交的版本。
  • HEAD是他们提交的版本,提交A

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

您可以在以下名称上使用AB以查看基本版本。

工作树具有git show一个副本,这通常是Git尽最大努力将三个输入(可能带有冲突标记)组合在一起的方法。 / p>

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

您还可以运行:

git add README.txt

或:

git add

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

您还可以运行:

git checkout --ours README.txt

或:

git checkout --theirs README.txt

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

您还可以运行:

A

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

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

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

-X theirs

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

答案 1 :(得分:0)

保持当前分支的更改或将要合并的分支的更改。

有时我们会预先知道代码版本在哪个分支中。在这种情况下,我们可以使用以下命令来保留该分支的更改:

git checkout -ours

或与分支的那些合并:

git checkout -theirs