2 декабря 2010 в 06:49

Hg Init: Часть 5. Процесс слияния перевод

Это пятая часть из серии Hg Init: Учебное пособие по Mercurial от Джоэля Спольски (Joel Spolsky). Предыдущие части:


Иногда при слияниях возникают конфликты. Обычно их легко разрешить. В любом случае их надо разрешить, или у вас будет несколько «голов». А кому это нужно?

Часть 5. Процесс слияния




Обеспечение слаженной работы нескольких людей над одним и тем же кодом — это важная функция системы контроля версий.

Представьте что и Роза, и я хотим внести изменения в рецепт гуакамоле. Роза работает над качеством авокадо. Перед тем как начать, она обновляет свой рабочий каталог, вытягивая свежие изменения из центрального репозитория.





Теперь небольшая правка:



Она фиксирует изменения и проталкивает их в центральный репозиторий:



В это же время я делаю изменение в другой части файла:



Я могу сделать коммит, но не могу протолкнуть изменения в центральный репозиторий.



Это, пожалуй, наименее полезное сообщение об ошибке в Mercurial. Лучше было бы так:



Так я и поступлю:



Хотите узнать, что за изменения только что были получены? Для этого есть удобный способ — команда hg log -P .



Ну точно, это те изменения, что сделала Роза. И что там с моим репозиторием сейчас?



У моего репозитория «несколько голов». По сути, мой репозиторий выглядит так:



Видите две головы? Они появились, потому что Роза сделала свои изменения, работая с седьмым набором изменений, и я тоже сделал свои изменения, работая с тем же набором. Так что теперь требуется слияние (merge). [Редактор подсказывает, что нельзя использовать пассивный залог] Я должен сделать слияние.



Команда слияния, hg merge, взяла две головы и объединила их. После этого она поместила результат в мой рабочий каталог. Она не закоммитила его. Это дает мне шанс проверить, что результат слияния корректен:



Похоже на правду: авокадо сорта Хасс и перчики халапеньо. Так что я сделаю коммит и протолкну изменения на сервер.



Я проталкиваю два набора изменений: мои изменения про халапеньо и результат слияния, который тоже является набором изменений.

Обратите внимание на то, что в наших изменениях не было конфликтов, потому что Роза и я работали над разными частями рецепта. Потому слияние было супер-пупер простым. Это наиболее частая ситуация, потому что в большинстве организаций разные программисты работают над разными частями кода.

Иногда бывают странные организации, в которых никто не готов стукнуть кулаком по столу и все-таки разделить зоны ответственности. Это может спровоцировать неожиданное и часто необъяснимое чувство грусти среди программистов. Эту ситуацию непросто распознать. Но есть симптомы: программисты закрываются в туалетах, программисты закрываются в серверных, высокая текучесть кадров, звуки сдавленных рыданий в помещении, а также неожиданное повреждение барабанных перепонок из-за многократных выстрелов штурмовой винтовки.

НО, даже в самых замечательных организациях с наилучшим руководством конфликты при слиянии иногда случаются, и Mercurial потребует от того, кто делает слияние, разрешить конфликт. Давайте посмотрим как это делается.

Для начала… я хочу чтобы Роза была в курсе моих изменений про халапеньо:



Сейчас мы увидим что случается когда у вас на-сто-я-щий конфликт: мы оба немного накосячим с ингредиентами.

Я добавил банан:



И первым зафиксировал изменения:



А Роза, господи прости, добавила МАНГО в ТОМ ЖЕ МЕСТЕ рецепта.



«Зрелый молодой» манго, я не шучу.



В этот раз я первым зафиксировал изменения, так что теперь Розе придется заниматься слиянием. Ха-ха!



И вдруг, обнаруживается конфликт и выскакивает окошко какой-то программы для разрешения конфликтов со столь страшным интерфейсом, что только матери этой программы он может нравиться. Но программа обычно достаточно неплохо делает то, для чего предназначена, надо только разобраться как она работает. Наиболее распространенной программой для разрешения конфликтов в наше время является KDiff3, так что Роза увидит следующее:



В программе KDiff3 у вас есть четыре панели. Верхняя левая — это оригинальный файл. Верхняя средняя показывает Розе ее версию файла. Верхняя правая показывает Розе мою версию. Нижняя панель — это редактор, в котором Роза собирает итоговый файл по мере разрешения конфликтов.

Разрешать конфликты достаточно просто. Нужно пройтись по всем конфликтам и выбрать каким образом разрешить каждый из них. Роза сошла с ума и решила, что бананово-манговая гуакамоле не так уж плоха:



Кстати, я говорил вам, что Роза, похоже, кое с кем встречается? Как-то раз ее видели уходящей с работы с парнем, который выглядел примерно как Деннис Франц. В таком прекрасном настроении как тогда ее давненько не видели.

Роза сохраняет изменения и закрывает KDiff3.



И конфликт разрешен.

Вот что вам стоит запомнить: вы не обязаны проводить слияние, подстраиваясь под чье-либо расписание. Вы можете выполнять hg pull когда угодно и, если не хочется сразу же разрешать конфликты, то можете свободно продолжать работать и счастливо коммитить до тех пор, пока не найдете время заняться слиянием.

Проверь себя


Вот то, что вы должны уметь делать после прочтения данной части:
  1. Работать с кодом совместно с другими людьми.
  2. Получать их изменения.
  3. Проталкивать свои изменения.
  4. Разрешать конфликты, которые время от времени случаются.
  5. Диагностировать некоторые виды программерской меланхолии.


Заключительная часть здесь:
Hg Init: Часть 6. Архитектура репозиториев
Автор оригинала: Joel Spolsky
Сергей Бобровский @Bobrovsky
карма
145,0
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (21)

  • 0
    С нетерпением жду окончания

    ЗЫ

    «Это может спровоцировать неожиданное и часто необъяснимое чувство грусти среди программистов.» — убило :D
  • 0
    Мне нравится стиль изложения. Все доступно.
    А меня убило «А Роза, господи прости, добавила МАНГО в ТОМ ЖЕ МЕСТЕ рецепта.» — как это знакомо!
    Розовая консоль смотрится устрашающе.
  • 0
    Оперативно О_о' Спасибо!
  • +1
    На этой консоли у Джоеля есть косяк:
    консоль
    После того как он сделал merge он не закомитился, а в логе у него уже есть changeset с мерджем
  • +4
    Мммм…

    В самой первой части «Переобучение для пользователей Subversion» было написано, что merge в hg работает как-то по другому и позволяет избегать «собраний у одного компьютера в попытке объединить несколько веток». Хотелось бы понять в чем заключается это отличие, потому как принципиальных различий между hg и svn не увидел (те же конфликты, та же схема их разрешения)…
    • +1
      В той же части написано, что одно из принципиальных отличий в том, как Subversion и Mercurial запоминают, что было изменено. Из-за того, что у Mercurial информации об изменениях больше, merge работает более надежно. Реже возникают конфликты, например.
      • +7
        Это я читал, но из этой статьи я сделал вывод, что конфликт возникает в том случае, когда редактировалась одна и та же строка файла одновременно. В svn точно так же.

        Другими словами, хотелось бы увидеть пример, где работа merge действительно отличается.
        • +4
          Поддерживаю! Очень хочется увидеть реальный пример, где Subversion выдаст конфликт а Mercurial все объединит.
    • +2
  • 0
    А подскажите, пожалуйста, какое решение возможно для такой ситуации:
    Есть файл, который нельзя исключать из репозитария, но в строчке ХХ у одного разработчика должно стоять одно значение, а у другого — другое. Допустим, вынести эту настройку во внешний файл, который не участвует в репозитарии, по каким-то причинам нельзя. Городить логику из if-else тоже не хочется.
    Как быть?
    Может, можно сделать игнор не всего файла, а какой-то строки или нескольких строк?
    • 0
      > Может, можно сделать игнор не всего файла, а какой-то строки или нескольких строк?
      Не-а.

      > Допустим, вынести эту настройку во внешний файл, который не участвует в репозитарии, по каким-то причинам нельзя.
      По каким? :-)
      • 0
        Чтобы не выносить файл, имеющий отношение к проекту за каталог проекта?

        Вообще задача, имхо, довольно частая: разработчиков много, настройки доступа к development серверам (логины/пароли) у каждого свои, но файл с дефолтными настройками должен быть в центральном репозитории (чтобы новый разработчик/пользователь мог его получить), а в рабочих копиях пользователя должны стоять его правки, не синхронизирующиеся с центральным сервером (но в случае hg/git поддерживающие историю правок и т. п. — в svn локальных коммитов нет, а значит выход только ignore) — как сделать чтобы файл клонировался с центрального репа, но потом изменения (модификации отдельных строк, добавления/удаление строк обрабатывается штатно) в локальном имели автоматический приоритет при пуллинге с центрального, но при пушинге на центральный приоритет имели центральные без постоянного ручного разрешения конфликтов. Реально малой кровью?
        • 0
          Про svn:
          Берём папку, кладём в неё конфиг и коммитим это дело.
          В свойствах папки ставим файл в игнор (или *)
          И это коммитим.

          У разработчика:
          В черепахе вешаем хук на чекаут, который будет подкладывать индивидуальный конфиг в папку для конфигов.

          (или не делаем игнор, а в хуке меняем логин пароль к БД и т.п. в забраном из репозитория файле)
        • 0
          В опрос не в том, зачем это нужно (прекрасно понимаю описанную вами ситуацию). вопрос в том, при каких условиях не применима схема с двумя файлами config.global + config.local, при которой второй записан в игнор и переопределяет отдельные параметры?
          • 0
            Сторонним приложением (фреймворк или, чаще, CMS) для которого ведётся разработка, например, модуля, такая логика «наследования» может быть не предусмотрена (или в ТЗ к разрабатываему явно указано, что все настройки должны храниться в config.ini). Обойти можно, выше вон хук советуют, но костыль же, не?
            • 0
              Да, тоже считаю костылём. Имхо, если возникает проблема с многими разработчиками, которые не могу договориться об одинаковых настройках своих окружений, то при таких масштабах можно и дописать вышестоящий фреймворк. Ну а остальным придётся костылять.
            • 0
              Имхо, различия конфига между проектом и его девелоперской копией (не говоря уже о продакшне) есть не костыль, а суровая реальность, и честный выход из положения — это в каком-нибудь bootstrap'е или прямо в конфиг-файле приложения подцеплять свой отдельный конфиг.

              Ещё есть вариант, что для развертывания проекта на своей машине разраб должен запустить скрипт, который запишет нужный конфиг, тогда конфиги для всех разрабов можно и в версиях хранить. Этакая мини-интеграция. Её можно на хук повесить, чтобы проводилась при апдейте рабочей копии или при изменении определенных файлов.
    • 0
      Я точно знаю, что для этих целей можно использовать mq, расширение, которое входит в базовую поставку. Но как точно — не подскажу.
  • 0
    А если у меня при конфликте в слиянии открывается вим. А в нем только 3 окна: исходная версия, моя версия и версия другого человека. Четвертого окна, для правки изменений нету. Как поступать в этом случае?
    • 0
      Редактировать прям в первом окне, это то которое результат.
      1 — результат, 2 — ваша локальная версия, 3 — пришло с репо.
  • 0
    Как-то Джоэль обошел сторой сам процесс слияния в kdiff3, никак не могу понять, что там нажимать. Слишком много кнопок(

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.