Ответ 1
Не обязательно придумывать простые соответствующие примеры, и этот комментарий лучше всего объясняет:
Если изменения близки, то тривиальные разрешения с большей вероятностью будут правильными (поскольку те, которые являются неправильными, более склонны касаться одних и тех же частей кода и, следовательно, приводят к нетривиальным конфликтам), и в тех немногих случаи, когда они возникают, проблема будет проявляться относительно быстро и, вероятно, очевидным образом.
[Что в основном иллюстрирует ваш пример]
Но обнаружение семантических конфликтов, возникающих в результате слияния между изменениями в широко разделенных областях кода, скорее всего, потребует большего количества программы в вашей голове, чем большинство программистов, - или в проектах размером с ядро, чем любой программист.
Поэтому, даже если вы просмотрите эти трехсторонние различия вручную, это будет сравнительно бесполезным упражнением: усилия будут намного несоразмерны с уверенностью в себе.На самом деле, я бы сказал, что слияние - это красная селедка:
этот тип семантического столкновения между разрозненными, но взаимозависимыми частями кода неизбежен в тот момент, когда они могут развиваться отдельно.
Как организовывается этот параллельный процесс разработки - DVCS; ЦВК; архивы и патчи; все редактируют одни и те же файлы на сетевом ресурсе - не имеет никакого значения для этого факта.
Слияние не вызывает семантических столкновений, программирование вызывает семантические столкновения.
Иными словами, реальный случай семантических конфликтов, с которыми я столкнулся в реальном коде после слияния, был не простым, а довольно сложным.
Как говорится, самый простой пример, проиллюстрированный Мартин Фаулер в своей статье Feature Branch - это метод переименования:
Проблема, о которой я больше беспокоюсь, - это семантический конфликт.
Простым примером этого является то, что если профессор Плаум изменяет имя метода, который вызывает призыв преподобного Грина. Инструменты рефакторинга позволяют безопасно переименовывать метод, но только на базе кода.
Поэтому, если G1-6 содержит новый код, который вызывает foo, профессор Плам не может сказать в своей базе кода, поскольку у него его нет. Вы только узнаете о большом слиянии.Переименование функции - относительно очевидный случай семантического конфликта.
На практике они могут быть гораздо более тонкими.
Тесты - это ключ к их обнаружению, но , чем больше кода для слияния, тем вероятнее, что у вас будут конфликты, и тем труднее их исправить.. Это риск конфликтов, особенно семантических конфликтов, которые делают большие слияния страшными.
Как Ole Lynge упоминает в свой ответ (upvoted), Мартин Фаулер написал сегодня (время этого редактирования) сообщение о "семантическом конфликте", включая следующую иллюстрацию:
Опять же, это основано на переименовании функций, хотя упоминается более тонкий случай, основанный на рефакторинге внутренней функции:
Самый простой пример - переименование функции.
Скажем, я думаю, что с помощью методаclcBl
было бы легче работать, если бы оно называлосьcalculateBill
.Итак, первое, что нужно сделать, это то, что, насколько бы мощным ни был ваш инструмент, он защитит вас только от текстовых конфликтов.
Есть, однако, несколько стратегий, которые могут значительно помочь нам справиться с ними.
- Первый из них SelfTestingCode. Тесты эффективно исследуют наш код, чтобы увидеть, согласуется ли их взгляд на семантику кода с тем, что на самом деле делает код
- Другим способом, который помогает, является более частое слияние
Часто люди пытаются обосновать DVCS, основываясь на том, как они облегчают ветвление функций. Но это не учитывает вопросы семантических конфликтов.
Если ваши функции будут построены быстро, через пару дней, вы столкнетесь с меньшими семантическими конфликтами (а если меньше, чем за один день, то это по сути то же, что и CI). Однако мы не видим таких коротких ветвей функций очень часто.
Я думаю, что между разветвленными ветвями и ветвями-чертами должно быть найдено среднее место.
И слияние часто является ключевым, если у вас есть группа разработчиков в той же ветки функции.