我在master分支中有一个旧的,不同步的项目代码。几个文件已被删除,添加,重写和彻底编辑。我想强制将稳定的最新代码从开发分支合并到master。我正在尝试强制合并,但仍然遇到合并冲突。
这是我遵循的步骤:
➜ project git:(development) git checkout master
➜ project git:(master) git pull
➜ project git:(master) git merge -s recursive -X theirs development
CONFLICT (modify/delete): vendors/popup/magnific-popup.css deleted in HEAD and modified in development. Version development of vendors/popup/magnific-popup.css left in tree.
CONFLICT (modify/delete): vendors/popup/jquery.magnific-popup.min.js deleted in HEAD and modified in development. Version development of vendors/popup/jquery.magnific-popup.min.js left in tree.
CONFLICT (modify/delete): vendors/owl-carousel/assets/animated.css deleted in HEAD and modified in development. Version development of vendors/owl-carousel/assets/animated.css left in tree.
... several similar conflicts
我尝试对我的master分支中的所有文件进行rm
➜ project git:(master) git reset --hard HEAD
➜ project git:(master) rm -rf *
➜ project git:(master) git merge -s recursive -X theirs development
仍然会遇到相同的冲突。我在做什么错了?
编辑:
这里是一个图表,用于更好地了解正在发生的事情。在某些时候,不相关的历史也被推动。
答案 0 :(得分:2)
我认为您根本不需要这种合并。我认为您想要的是“他们的策略”合并,Git不提供。仍然可以完成:请参见VonC's answer here。但请继续阅读以确保该 是您想要的,然后再使用它。
这里发生了两件重要的事情,都是由您的命令序列捕获的:
git checkout master git merge -s recursive -X theirs development
(我没有采取任何措施)。
首先是,大多数合并(包括来自默认-s recursive
合并策略的合并)都是通过找到一个共同的出发点进行工作的:共享的合并基础提交。要将其绘制为一个相当简单的情况,请考虑以下提交图:
C--D--E <-- master (HEAD)
/
...--o--B
\
F--G--H <-- development
很显然,您自己的图要毛茸茸得多,但最终,它们的工作原理是一样的:Git接受当前提交,如您当前的分支master
所指示,是提交E
,作为合并过程的三个输入之一。 Git接受您指定的提交,在这种情况下,提交H
,因为development
是您说要查看的提交,是合并过程的三个输入中的第二个。
第三输入是根据图形计算得出的。我们从两次提交中的每一个开始,然后像Git一样向后走。提交E
返回到D
,后者返回到C
,然后到达B
。同时,提交H
导致G
到F
到B
。提交B
在两个分支上,并且以图形的形式表示,它们是最小祖先。 1 (非正式地,它是最接近这两个分支的技巧。“最接近”在复杂图中分解,但是对于像这样的简单图,这就是最低祖先的意思。)这使其成为最佳的共享提交,因此也是合并基础。
现在发生的事情从总体上来说很简单,但是在某些细节上变得棘手。 Git从“所需结果”方面的合并基础提交开始。也就是说,Git开头的内容是提交B
中快照中的内容。对于这些内容,Git需要将您所做的任何更改和他们所做的任何更改的组合应用。因此,Git需要运行两个git diff
命令:
git diff --find-renames hash-of-B hash-of-E
:我们在master
上所做的更改git diff --find-renames hash-of-B hash-of-H
:它们在development
上的变化如果合并基础与此处的两个技巧都很接近,那么这两个差异中的每个差异可能并没有显示太多。将这两组更改组合在一起将变得简单而直接。如果我们更改了README.md
的第12行,而他们根本没有碰到README.md
,则Git会进行更改,并给我们的README.md
版本进行新的合并提交。如果他们碰到README.md
的另一行,Git会将我们的两个更改放在一起:都应用于B:README.md
以为新提交生成README.md
。对所有文件重复此过程。
但是,如果我们和他们俩都碰到相同文件的相同行,则Git通常会声明合并冲突并停止,从而使我们清理混乱。这就是-X theirs
选项出现的位置:这是一个扩展选项,传递给-s
策略。 2 在这种情况下,{ {1}}策略将recursive
扩展选项视为:在发生冲突的情况下,放弃我的更改并使用他们的更改。
请注意,如果没有冲突,Git将使用我们的更改!有时候这就是我们想要的。如果 是我们想要的,那么theirs
是正确的主意。如果不是我们想要的,-X theirs
是错误的主意。所以这就是您需要决定的地方:是使用-X theirs
,还是使用我们必须像VonC的答案那样构造的-X theirs
?
1 它是最低的共同祖先,因为计算机科学家颠倒了他们的树木:
-s theirs
E和F的共同祖先是C,B和A,但C是最低。 F和G的共同祖先是B和A。 B最低。 Git的提交图是有向无环图或DAG,而不是树,因此“ LCA”并不像在树中那样简单,并且图中的两个节点可以有多个LCA(或根本没有LCA) 。对于某些定义,Git明智地处理了所有这些事情。
2 Git将 A
|
B
/ \
C D
/ \ \
E F G
称为策略选项,但这听起来与-X
参数完全一样。从字面上看,这是该策略的一种选择,因此Git的选择不佳。我认为扩展选项是一个更好的名称,部分原因是它解释了-s strategy
。
-X
:请参阅我链接的其他答案无需多说:-X theirs
曾经是Git合并策略。不再了。您仍然可以通过多种方式来合成它。我最喜欢的实际上是Michal Soltys' answer中的管道命令。
-s theirs
:为什么抱怨冲突?我在上面提到,合并过程(-X theirs
的要合并部分)“非常简单……但在某些细节上有些棘手”。您刚刚击中了其中一个细节。
Git通过扩散找到的合并基础而获得的大量git merge
与您指定的两个提示提交中的每一个相比,有很多情况下文件已被完全删除一侧,但另一侧被修改:
git diff
在庞大的匿名...--B--o--o--...--o--o <-- master (HEAD)
\
o--o--...--o--o <-- development
链中的某个位置,顶部是“我们”(基本对主),已删除了一些文件。 “他们”(基础与开发)更改了该文件。 Git不知道如何将“已删除”与“已更改”组合在一起。
我将这些冲突称为高级,因为它们是对文件本质或存在的更改,而不是对文件中各个行的更改。好吧,我也这样称呼它,因为Git本身将组合各行的代码部分称为“低级合并驱动程序”,因此它们必须是相反的 high 级别。这类冲突-无论是添加/添加,修改/删除,重命名/删除还是其他冲突-总是会导致o
-s recursive
停止并让您修复混乱。扩展选项仅提供给策略调用的低级别合并驱动程序。
事实上,唯一不会停止的策略就是git merge
策略。当您使用-s ours
策略时,该完全忽略“其”提交中的内容。 Git甚至根本不用理会合并基础,它只是将 our 提交中的内容用作合并结果。
当然,-s ours
需要我们的。您想要的东西,至少在这种情况下,甚至在所有情况下,都花了他们的钱。但是,如果您真的不想要与-s ours
等效,而在这些情况下宁愿-s theirs
提取整个文件,则必须解决每个冲突事后。
您可以使用脚本(必须自己编写)来执行此操作。不过这有点棘手。诀窍是使用-X theirs
:对于Git抱怨的每个文件,您都会看到:
git ls-files --stage
Git将在第1阶段输入一个名称(CONFLICT (modify/delete): vendors/popup/magnific-popup.css deleted in HEAD and modified in development. Version development of vendors/popup/magnific-popup.css left in tree.
),在第3阶段输入另一个名称(它们),但是在第2阶段没有输入(我们的)。要解决此问题,请使用vendors/popup/magnific-popup.css
将工作树的第3阶段条目写入零阶段的索引:git add
将删除第1阶段和第3阶段的副本。您只需收集所有这些文件名并将它们全部传递给git add
。
答案 1 :(得分:0)
一个分支只是一个指针,而requestPermission() {
this.angularFireMessaging.requestToken.subscribe( <-- THIS LINE
(token) => {
console.log(token);
this.updateToken(token);
},
(err) => {
console.error(err);
}
);
}
只是另一个分支。如果您在进行过程中没有合并更改,而master
表示项目的当前稳定状态,那么可以避免经历所有冲突的一种选择是:
dev
根据您的远程设置方式,可能需要调整跟踪关系。
答案 2 :(得分:0)
这只会将master
设置为与您的development
分支相同-在development
的最后一次合并之后提交的master中的所有内容都会丢失。
git checkout -B master development