svn - 更好、更简单的 'semantic conflict' 示例?

标签 svn version-control conflict

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

  • 正文
  • 句法
  • 语义

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

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

    最后,VCS 没有标记语义冲突,结果编译,但代码运行可能有问题。在轻微的情况下,会产生不正确的结果。在严重的情况下,可能会导致崩溃。即使这些也应该在提交之前由非常细心的程序员通过代码审查或单元测试来检测。

    我的语义冲突示例使用 SVN (Subversion) 和 C++,但这些选择与问题的本质并不真正相关。

    基本代码是:
    int i = 0;
    int odds = 0;
    while (i < 10)
    {
        if ((i & 1) != 0)
        {
            odds *= 10;
            odds += i;
        }
        // next
        ++ i;
    }
    assert (odds == 13579)
    

    左 ( L ) 和右 ( R ) 变化如下。

    Left 的“优化”(更改循环变量采用的值):
    int i = 1; // L
    int odds = 0;
    while (i < 10)
    {
        if ((i & 1) != 0)
        {
            odds *= 10;
            odds += i;
        }
        // next
        i += 2; // L
    }
    assert (odds == 13579)
    

    Right 的“优化”(改变循环变量的使用方式):
    int i = 0;
    int odds = 0;
    while (i < 5) // R
    {
        odds *= 10;
        odds += 2 * i + 1; // R
        // next
        ++ i;
    }
    assert (odds == 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)
    
    assert失败,因为 odds是 37。

    所以我的问题如下。还有比这更简单的例子吗?有没有一个简单的例子,编译的可执行文件有一个新的崩溃?

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

    最佳答案

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

    If the changes are close by, then trivial resolutions are more likely to be correct (because those that are incorrect are more likely to touch the same parts of the code and thus result in non-trivial conflicts), and in those few cases where they aren’t, the problem will manifest itself relatively quickly and probably in an obvious way.



    [这基本上就是你的例子所说明的]

    But detecting semantic conflicts introduced by merges between changes in widely separated areas of the code is likely to require holding more of the program in your head than most programmers can – or in projects the size of the kernel, than any programmer can.
    So even if you did review those 3-way diffs manually, it would be a comparatively useless exercise: the effort would be far disproportionate with the gain in confidence.

    In fact, I would argue that merging is a red herring:
    this sort of semantic clash between disparate but interdependent parts of the code is inevitable the moment they can evolve separately.
    How this concurrent development process is organized – DVCS; CVCS; tarballs and patches; everyone edits the same files on a network share – is of no consequence at all to that fact.
    Merging doesn’t cause semantic clashes, programming causes semantic clashes.



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

    话虽如此,最简单的例子,如 Martin Fowler in his article Feature Branch 所示是一个方法重命名:

    The problem I worry more about is a semantic conflict.
    A simple example of this is that if Professor Plum changes the name of a method that Reverend Green's code calls. Refactoring tools allow you to rename a method safely, but only on your code base.
    So if G1-6 contain new code that calls foo, Professor Plum can't tell in his code base as he doesn't have it. You only find out on the big merge.

    A function rename is a relatively obvious case of a semantic conflict.
    In practice they can be much more subtle.

    Tests are the key to discovering them, but the more code there is to merge the more likely you'll have conflicts and the harder it is to fix them.
    It's the risk of conflicts, particularly semantic conflicts, that make big merges scary.



    Ole Lyngehis answer 中提及(赞成),Martin Fowler今天(本次编辑的时间)确实写了一篇关于“语义冲突”的帖子,包括以下插图:

    semantic conflict illustration

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

    The simplest example is that of renaming a function.
    Say I think that the method clcBl would be easier to work with if it were called calculateBill.

    So the first point here is that however powerful your tooling is, it will only protect you from textual conflicts.

    There are, however, a couple of strategies that can significantly help us deal with them

    • The first of these is SelfTestingCode. Tests are effectively probing our code to see if their view of the code's semantics are consistent with what the code actually does
    • The other technique that helps is to merge more often

    Often people try to justify DVCSs based on how they make feature branching easy. But that misses the issues of semantic conflicts.
    If your features are built quickly, within a couple of days, then you'll run into less semantic conflicts (and if less than a day, then it's in effect the same as CI). However we don't see such short feature branches very often.



    我认为需要在临时分支和功能分支之间找到一个中间立场。
    如果您在同一功能分支上有一组开发人员,那么经常合并是关键 .

    关于svn - 更好、更简单的 'semantic conflict' 示例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2514502/

    相关文章:

    svn - CruiseControl.NET 是否支持通过 http 协议(protocol)访问存储库?

    svn - 当修订跨分支重叠时,使用 svn log 提取标签之间的提交消息

    javascript文档onmousedown取消元素onclick

    c - 两个库提供同名函数产生冲突怎么办?

    windows - Groovy 颠覆钩子(Hook)脚本

    svn - 在 subversion 中取消删除文件的简单方法是什么?

    git - 限制某些 GitHub 用户 merge 分支

    wordpress - 避免 WordPress 插件上的 jquery 冲突的防弹方法

    git - git 有类似 svn_load_dirs.pl 的东西吗?

    git - 存储库 [name] 已停用且无法重复使用