git - 轻松自动合并出错
问题描述
我合并了两个分支:
- 分支
master
将行添加到文件config_dev.yml
- 分支
report
没有碰它(所以这个文件没有冲突)。
我合并report
进去master
,结果是:线条消失了。
1 2 3 4 5 6 7 8 9 10
master: ---O--O--O-----O--O-----O--O--O----
report: -------\----O--------O-------/
changes on master__^ ^__merge that silently removes changes
为什么?我可以信任git merge
吗?
可能相关的其他信息:
- 还有一个第三个分支(没有触及该文件)从提交 3 开始
master
并且有点“合并”(实际上是一个空白合并,“仅我的”)到report
提交 7
解决方案
这不是真正的答案(应该是评论),但它需要格式化并且不适合评论空间。相反,这是关于如何找到答案的说明,或者至少想出正确的输入来得出答案。
当你运行时:
git checkout master
git merge report
Git 首先找到一个合并基础提交。很少——可能不是这里的情况——Git 发现不止一个合并基础提交,但我们会确保不是这种情况。
假设这个合并会出错,但是——重要的是——<em>还没有完成。如果它已经完成,我们需要一个技巧,或者一个尚未完成的单独存储库:任何一个都足够了。诀窍是创建一个新的分支,而不是命名master
,它指向master
在合并之前将指向的提交:
git checkout -b test-the-merge <hash-ID>
(我们可以稍后丢弃这个分支。或者,我们甚至可以根本不创建它,使用另一种技巧,但为简单起见,使用测试分支更容易。)
现在我们处于尚未完成合并的状态,我们首先运行:
git merge-base --all HEAD report
理想情况下,这会产生一个哈希 ID。如果它产生多个哈希 ID,我们会遇到一种罕见的情况,即有多个合并基,我们需要一个我将省略的过程,因为它很长而且很无聊。:-)
现在我们知道了作为合并基础的一个哈希 ID,下面是当 Git 进行合并时我们如何看到 Git 将看到的内容:
git diff --find-renames <hash> HEAD # what does Git think *we* changed?
git diff --find-renames <hash> report # what does Git think *they* changed?
您可能希望将这两个git diff
s 发送到文件中,以便您可以在闲暇时和/或并行阅读它们。如果有很多正确合并的差异并且您只想关注未正确合并的特定文件,您还可以将输出限制为特定文件。
请注意,git diff
发现的不一定是某个人所做的更改。找到的是产生相同效果git diff
的最小指令集。这通常足够好。例如,假设在左侧提交(合并基础,由哈希 ID 指定)和右侧提交之间,有人删除了冗余段落的第二行第一个单词:the
Paris in
the
the
spring
而 Git 选择生成指令:删除第二the
行(第三行)。
有关系吗?可能不会——但有时会。如果左右两边分别读:
some vaguely C like code {
with redundant stuff
}
more vaguely C like code {
with redundant stuff
}
和:
some vaguely C like code {
with redundant stuff
}
still vaguely C like code {
with redundant stuff
}
more vaguely C like code {
with redundant stuff
}
和 Git 错误地在右大括号上同步并产生语法上无效的差异?好吧,即使这样通常仍然有效,但有时会产生不适当的冲突。在极少数情况下(尽管确实会发生但很难说明),您可能会错过本应发生的冲突,因为 Git 提供了语法正确但语义错误的最小编辑。
在任何情况下,Git 现在所做的,已经产生了两个差异列表,就是想出合并的源文件集。为此,Git 从所有文件的合并基础版本开始。然后:
对于您、他们或两者都更改的每个文件...
你改过文件吗?他们没有更改文件吗?如果是这样,把你的文件。
他们是否更改了文件,而您没有更改它?如果是这样,请拿走他们的档案。
否则,你们俩都更改了文件。尝试通过差异逐行合并更改。无论您在哪里添加了一些线条,都可以使用您添加的线条。无论他们在哪里添加了一些,都使用他们添加的行。无论您或他们在何处删除了某些行,请进行删除。如果你们都对完全相同的行进行了完全相同的更改,请复制一份更改。如果您对同一行或相邻(相互接触)或到达文件末尾的行进行了不同的更改,请声明合并冲突。
对于您或他们完全删除、创建为全新或重命名的文件,请执行适当的操作。(究竟什么是合适的意思会变得复杂,在这里似乎不是你的情况,所以我不会深入探讨。)
将所有内容尽其所能地组合在一起,Git 现在:
- 因合并冲突而停止,或
- 停止,因为你告诉它(
--no-commit
例如),或者 - 进行合并提交,因为一切似乎都很顺利。
如果 Git 进行了合并提交——或者如果它停止并让你提交并且你确实成功了——合并提交将你当前分支的旧提示提交作为它的第一个父项——新提示提交是合并提交本身——并且合并commit 将另一个分支的提示提交作为其第二个父级。也就是说,在此合并之后master
或test-the-merge
(无论我们在哪个分支上),我们有:
git rev-parse <branch>^1 => hash ID of the previous branch tip
git rev-parse <branch>^2 => same hash ID as git rev-parse report
您可以查看两个输入,来自三个提交的两个差异 - 合并基础,HEAD
以及他们的 / 提示 -report
以查看 Git 看到的内容,这将解释 Git 进行合并的原因。
无论如何,这就是这样git merge
做的:它找到一个合并基础,制作两个差异,然后组合差异并将组合的差异应用于合并基础以得出合并结果。(这当然忽略了所有特殊情况,例如由于各种原因而没有实际合并:-s ours
,或快进,或不相关的历史,或合并冲突等)差异本质上是面向行的,无法重建某人的内容真的做到了:他们只产生一组指令,会产生相同的最终文本。结合这些指令往往适用于大多数编程语言,但绝对不是完美的。
如果该过程适用于您的文件,您可以信任它。如果该过程不适用于您的文件,则您不能信任它,并且您必须仔细检查 - 并在需要时更正 - 每次合并。
推荐阅读
- c# - 为什么我无法在此 Azure 功能中读取应用设置?
- html - 如何更改标题属性css?
- java - 使用gson解析,空对象的List类型如何解析为[]
- javascript - 如何解决这个我的菜鸟屁股已经尝试解决三天的 javascript 错误?
- excel - Excel 的特定数据验证
- django - 无法将视频从 ReactJS 上传到 Django
- excel - 一步复制、重命名和填充复制工作表中的单元格
- visual-studio-code - python.testing.autoTestDiscoverOnSaveEnabled 不起作用
- python - Python 请求未编码正斜杠
- qt - QT5自定义QWidget无法显示