我将两个分支合并在一起,比如说branchA和branchB。他们大约有100个冲突的文件。
branchB可以接受所有工作,并且100%是我所需要的。我不想强制推送branchB或其他任何内容。
有没有办法将两者合并,并且说出任何冲突,请接受branchB上的内容,这样我就不必打开每个文件或“他们的”或“我们的”每个文件。
正在尝试从branchB进行递归合并,并使用-s和-x选项将BranchA拉出,但似乎没有按预期工作
谢谢
答案 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行,因此您会在此处遇到冲突。因为只有 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.txt
或B
中删除)。
您可以在以下名称上使用A
:B
以查看基本版本。
工作树具有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