Svn 更好、更简单的'示例;语义冲突';?

Svn 更好、更简单的'示例;语义冲突';?,svn,version-control,conflict,Svn,Version Control,Conflict,我想从版本控制系统(VCS)中区分三种不同类型的冲突: 文本的 句法的 语义的 文本冲突是由合并或更新过程检测到的冲突。这是由系统标记的。在冲突解决之前,VCS不允许提交结果 VCS不会标记语法冲突,但不会编译结果。因此,即使是一个稍微谨慎的程序员也应该了解这一点。(一个简单的例子可能是一个变量按左重命名,一些行按右使用该变量。合并可能会有一个未解析的符号。或者,这可能会通过变量隐藏引入语义冲突。) 最后,VCS不会标记语义冲突,结果会编译,但代码在运行时可能会出现问题。在轻微的情况下,会产

我想从版本控制系统(VCS)中区分三种不同类型的冲突:

  • 文本的
  • 句法的
  • 语义的
文本冲突是由合并或更新过程检测到的冲突。这是由系统标记的。在冲突解决之前,VCS不允许提交结果

VCS不会标记语法冲突,但不会编译结果。因此,即使是一个稍微谨慎的程序员也应该了解这一点。(一个简单的例子可能是一个变量按左重命名,一些行按右使用该变量。合并可能会有一个未解析的符号。或者,这可能会通过变量隐藏引入语义冲突。)

最后,VCS不会标记语义冲突,结果会编译,但代码在运行时可能会出现问题。在轻微的情况下,会产生不正确的结果。在严重的情况下,可能会发生碰撞。即使是这些,也应该在提交之前由非常谨慎的程序员通过代码审查或单元测试进行检测

我的语义冲突的例子使用了Svn(SudiVIEW)和C++,但是这些选择与问题的本质并不相关。 基本代码是:

int i = 0;
int odds = 0;
while (i < 10)
{
    if ((i & 1) != 0)
    {
        odds *= 10;
        odds += i;
    }
    // next
    ++ i;
}
assert (odds == 13579)
右侧的“优化”(更改循环变量的使用方式):

inti=0;
int比值=0;
而(i<5)//R
{
赔率*=10;
赔率+=2*i+1;//R
//下一个
++一,;
}
断言(赔率=13579)
这是合并或更新的结果,SVN没有检测到(这是VCS的正确行为),因此它不是文本冲突。请注意,它是编译的,因此不是语法冲突

int i = 1; // L
int odds = 0;
while (i < 5) // R
{
    odds *= 10;
    odds += 2 * i + 1; // R
    // next
    i += 2; // L
}
assert (odds == 13579)
int i=1;//L
int比值=0;
而(i<5)//R
{
赔率*=10;
赔率+=2*i+1;//R
//下一个
i+=2;//L
}
断言(赔率=13579)
断言
失败,因为
几率
为37

因此,我的问题如下。有没有比这更简单的例子?有没有一个简单的例子说明编译后的可执行文件发生了新的崩溃


作为第二个问题,您在实际代码中是否遇到过这种情况?同样,简单的例子特别受欢迎。

提出简单的相关例子并不明显,这一评论最好地总结了原因:

如果更改很接近,那么琐碎的解决方案更有可能是正确的(因为那些不正确的解决方案更有可能触及代码的相同部分,从而导致非琐碎的冲突),并且在那些不正确的少数情况下,问题将相对快速地、可能以一种明显的方式表现出来

[这基本上就是您的示例所说明的]

但是,要检测代码中广泛分离的区域中的更改之间的合并所引入的语义冲突,可能需要在您的头脑中掌握比大多数程序员所能掌握的更多的程序——或者在内核大小的项目中,比任何程序员所能掌握的都要多。
因此,即使你确实手动查看了这些三向差异,这也将是一个相对无用的练习:努力与信心的提升将远远不成比例

事实上,我认为合并是一种转移注意力的手段:
在代码的不同但相互依赖的部分之间发生这种语义冲突是不可避免的,因为它们可以单独发展。
这种并行开发过程是如何组织的–DVCS;CVCS;柏油球和补丁;每个人都在网络共享上编辑相同的文件,这与事实毫无关系。
合并不会导致语义冲突,编程会导致语义冲突。

换句话说,我在合并后的实际代码中遇到的语义冲突的实际情况并不简单,而是相当复杂


也就是说,最简单的示例是方法重命名,如所示:

我更担心的问题是语义冲突。
一个简单的例子是,如果Plum教授更改了Green牧师的代码调用的方法的名称。重构工具允许您安全地重命名方法,但只能在代码基础上进行重命名。
所以,如果G1-6包含调用foo的新代码,Plum教授无法在他的代码库中分辨,因为他没有代码库。你只会在大合并中发现

函数重命名是一种相对明显的语义冲突。
实际上,它们可能更加微妙。

测试是发现它们的关键,但是要合并的代码越多,冲突的可能性就越大,修复它们就越困难 冲突的风险,尤其是语义冲突,使大型合并变得可怕


正如(投票表决)中提到的,Dod在今天(编辑时间)写了一篇关于“语义冲突”的帖子,包括以下插图:

同样,这是基于函数重命名的,尽管提到了基于内部函数重构的更微妙的情况:

最简单的例子是重命名函数。
比如说,我认为如果将
clcBl
方法称为
calculateBill
,它将更容易使用

因此,这里的第一点是,无论您的工具多么强大,它只会保护您免受文本冲突的影响

然而,有几种策略可以显著帮助我们应对这些问题

  • 第一个是。测试有效地探测我们的代码,以查看他们对代码语义的看法是否与代码的实际功能一致
  • 另一个有帮助的技巧是更频繁地合并
通常,人们试图根据DVCSs使功能分支变得容易的方式来证明DVCSs的合理性。但这忽略了语义冲突的问题。
如果您的功能在几天内快速构建,那么您将
int i = 0;
int odds = 0;
while (i < 5) // R
{
    odds *= 10;
    odds += 2 * i + 1; // R
    // next
    ++ i;
}
assert (odds == 13579)
int i = 1; // L
int odds = 0;
while (i < 5) // R
{
    odds *= 10;
    odds += 2 * i + 1; // R
    // next
    i += 2; // L
}
assert (odds == 13579)