一位同事一直在master
的本地资料库中工作,几周后,他做了git pull
。与此同时,master上有一堆活动,包括至少10次合并提交(到目前为止我们一直在使用合并工作流程)。
在拉动之后,有一些文件存在冲突。但出乎意料的是,他的暂存区域有数百个修改他没有工作的文件,而且每个修改都恢复了自共同祖先提交以来origin/master
所做的更改。例如:
他的分支(master
)
origin/master
git pull
临时区域的修改
origin/master
的所有其他更改都已消失。缺少N1-N3,D1-D5又回来了。冲突中
我已经复制了这个问题,以确认他除了普通的git pull
之外没有做任何特别的事情。
不幸的是他提交了所有这些更改,我最终需要还原该提交。但是我想知道为什么会这样,所以我们可以在将来避免它。
我已阅读some related个问题,但没有人回答这个问题:为什么当相应文件没有变化时,Git会从master
恢复更改在他的树枝上?我理解为什么在拉动后发生冲突时会对暂存区域进行修改,但我不明白为什么他们会从共同的祖先那里有效地恢复origin/master
上的工作。
我们现在解决问题的方法是
git pull --rebase
代替合并答案 0 :(得分:3)
编辑(基于问题编辑了解更多详细信息):这可能是重命名检测出错的情况,并且可能会出现纵横交错的情况。历史也是如此,因此Git正在形成一个虚拟的合并基地"。
要了解,请先运行:
git merge-base --all <hash1> <hash2>
关于错误合并发生时两个分支名称master
和origin/master
指向的两个哈希ID。我们需要这个来测试重命名检测是否存在问题,以及是否存在多个合并基础。
如果打印多个哈希ID,您将获得recursive
策略来合并合并库,然后使用生成的合并作为新的合并库。这可能(在极少数情况下)产生非常混乱的结果。如果是这样,切换到-s resolve
策略可能有所帮助。这将选择两个合并基地之一并坚持下去。 (但是您无法控制使用哪个合并基础。)请注意,将merge.conflictStyle
设置为diff3
也会sometimes show you the effect of a virtual merge base(但有时只会)
接下来,无论是否存在多个合并库,我们都可以检查重命名检测是否导致问题。如果是这样,有两件事可能会有所帮助:
-X no-renames
,其匹配git diff
的拼写(尽管它有--no-renames
}})。-X rename-threshold=100
或-X find-renames=100
需要精确匹配而不是近似匹配。新拼写-X find-renames=<n>
与git diff
选项的拼写相匹配,是Git 2.8版中的新拼写,但该选项本身非常陈旧,自1.7.4版本开始出现。请注意,其他阈值也是允许的,尽管100%完全匹配非常值得注意。要确定Git是否检测到重命名,我们需要 合并基础,如果存在多个合并基础,这有点问题:我们必须首先合并合并基础,以获取一个真正的合并提交,Git将用作新的合并基础。我只是假设这是不的情况,因为这个过程有点混乱;所以我们继续看看&#34;&#34;&#34;合并基础,使用:
git diff --name-status --find-renames=50 --diff-filter=R <basehash> <hash1>
git diff --name-status --find-renames=50 --diff-filter=R <basehash> <hash2>
<hash1>
和<hash2>
值与之前相同。我们告诉Git给我们文件名和状态,然后只打印状态为R
(重命名)的文件的名称。如果Git 认为某些文件已重命名,我们将在此处查看其新旧名称。 Git在合并过程中如何将它们结合起来有点棘手,但只有R
- 状态文件存在意味着Git会做这种事情。如果有没有文件,那么它毕竟不是重命名检测。
(有关git diff
中重命名检测的详细说明,请参阅this answer。合并代码使用不同的命令行选项,其中一些在最近相对更改。请参阅VonC's answer到{{ 3}}以及。)
以下原始答案。
一般情况下,合并时,Git不会选择 &#34; side&#34;。相反,它需要两个方面。请记住,这整个三向合并事件都有第三个方:有&#34; s&#34;你的&#34;方(HEAD),&#34;他们的&#34;方(你正在合并)和基础。这形成了一个三角形:
o <-- HEAD
...
o
...
...--o--B (base)
...
o
...
o <-- theirs
并且合并将它们全部组合在一起以制作闪亮的(我们希望的)钻石:
o
/ \
o \
/ \
...--o--B o result
\ /
o /
\ /
o
另请参阅Disable Git Rename Detection和this answer。
同时,事实证明至少有一些GUI界面将这一事实呈现给用户。当他们仅更改一个文件时,许多文件发生了很多变化,这让他们感到害怕。他们指示他们的GUI撤消所有其他更改 - 这意味着抛弃其他用户&#39;工作!他们然后提交这个,你必须恢复他们的合并以获得其他用户&#39;回来工作。
(&#34;触摸每个文件&#34;用户在其设置中启用行尾转换时的另一个来源。它们接收使用仅使用LF或CRLF结尾的传入代码,并将其转换为CRLF,或者只分别使用LF。然后他们提交所有这些更改,这意味着他们已经改变了每个文件的每一行。)