Улаживание конфликтов

Когда-нибудь у вас возникнет конфликт при обновлении/слиянии ваших файлов из хранилища или при переключении рабочей копии на другой URL. Существует два типа конфликтов:

конфликты файлов

Конфликт файлов возникает, когда двое (или более) разработчиков изменили одни и те же строки файла.

конфликты деревьев

Конфликт деревьев возникает, когда разработчик переместил/переименовал/удалил файл или папку, которые другой разработчик также переместил/переименовал/удалил или же только изменил.

Конфликты файлов

Конфликт в файле происходит, когда несколько разработчиков внесли изменения в одни и те же строки. Subversion не знает ничего о вашем проекте, поэтому разрешение конфликтов ложится на плечи разработчиков. Зона конфликта в текстовом файле отмечена следующим образом:


<<<<<<< имя файла

ваши изменения

=======

результат автоматического мержа с репозиторием

>>>>>>> ревизия

Также, для каждого файла, имеющего конфликты, Subversion создает в том же каталоге три дополнительных файла:

filename.ext.mine

Это ваш файл, каким он был в рабочей копии перед выполнением обновления, т.е. без конфликтных отметок. В этом файле содержатся ваши последние в нём изменения, и ничего другого.

filename.ext.rСТАРАЯ_РЕВИЗИЯ

Это файл, который был базовой ревизией перед обновлением вашей рабочей копии, т.е. это тот файл, который был извлечён до того, как вы начали вносить ваши последние изменения.

filename.ext.rНОВАЯ_РЕВИЗИЯ

Это файл, который был получен с сервера клиентом Subversion при обновлении вашей рабочей копии. Этот файл соответствует ведущей (HEAD) ревизии хранилища.

Вы можете либо запустить внешнюю утилиту слияния / редактор конфликтов с помощью TortoiseSVNРедактировать конфликты, либо использовать любой текстовый редактор для ручного улаживания конфликта. Вы должны решить, как должен выглядеть код, сделать необходимые изменения и сохранить файл. Использование инструмента слияния, например, TortoiseMerge или другого популярного инструмента, обычно является более простым вариантом, т.к. в большинстве случаев они отображают файлы в 3-х панелях и вам не нужно беспокоиться о маркерах конфликта. Если же вы используете текстовый редактор, то вы должны найти строки начинающиеся с символов <<<<<<<.

После этого выполните команду TortoiseSVNУлажено и зафиксируйте ваши изменения в хранилище. Пожалуйста, помните, что команда 'Улажено' на самом деле конфликты не улаживает. Она только удаляет файлы filename.ext.mine и filename.ext.r* для того, чтобы вы могли зафиксировать ваши изменения.

Если конфликты возникли в двоичных файлах, Subversion не пытается самостоятельно слить эти файлы. Локальный файл остаётся неизменённым (точно таким, как при последнем вашем изменении) и у вас есть файлы filename.ext.r*. Если вы хотите отменить ваши изменения, и сохранить версию из хранилища, используйте команду 'Убрать изменения'. Если вы хотите сохранить вашу версию и переписать версию в хранилище, используйте команду 'Улажено', после чего зафиксируйте вашу версию.

Вы можете использовать команду 'Улажено' для нескольких файлов, если, после щелчка правой клавишей на родительской папке, выбрать TortoiseSVNУладить... Появится диалог со списком всех конфликтующих файлов в этой папке, и вы сможете выбрать, какие из них пометить как улаженные.

Конфликт свойств

Конфликт свойств возникает когда два или более разработчиков изменили одно и то же свойство. Как и содержимое файла, разрешение конфликта может быть выполнено только разработчиками.

Если одно из изменений должно перекрыть другое, то выберите вариант Уладить, применив локальное свойство или Resolve using remote property. Если изменения должны быть слиты, выберите Редактировать свойство вручную, решите каким должно быть значение свойства и отметьте как разрешенный.

Конфликты деревьев

Конфликт деревьев возникает, когда разработчик переместил/переименовал/удалил файл или папку, которые другой разработчик также переместил/переименовал/удалил или же только изменил. Есть множество различных ситуаций, которые могут привести к конфликту деревьев, и все они требуют различных шагов для улаживания конфликта.

Когда файл удаляется локально в Subversion, файл также удаляется и в локальной файловой системе, поэтому, даже если он участвует в конфликте деревьев, на нём не может быть показана пометка конфликта и вы не можете щёлкнуть на нём правой кнопкой и уладить конфликт. Воспользуйтесь вместо этого диалогом Проверка на наличие изменений для доступа к опции Редактировать конфликты.

TortoiseSVN может помочь обнаружить подходящее место для слияния изменений, но, возможно, потребуются дополнительные усилия по улаживанию конфликтов. Помните, после обновления рабочая БАЗА всегда содержит ту ревизию каждого элемента, которая была у него в хранилище во время обновления. И когда вы убираете изменение после обновления, оно вернётся к состоянию, каким оно было в хранилище, а не к тому, каким оно было, когда вы начали делать свои локальные изменения.

Локальное удаление, поступающее при обновлении редактирование

  1. Разработчик А изменяет Foo.c и фиксирует это в хранилище.

  2. Одновременно разработчик Б переименовывает Foo.c в Bar.c в своей рабочей копии, или просто удаляет Foo.c или его родительскую папку.

Обновление рабочей копии разработчика Б приводит к конфликту деревьев:

  • Foo.c удалён из рабочей копии, но помечен как участвующий в конфликте деревьев.

  • Если конфликт произошёл из-за переименования, а не из-за удаления, то Bar.c помечен как добавленный, но он не содержит изменений, выполненных разработчиком А.

Разработчик Б теперь должен решить, оставлять ли изменения разработчика А. В случае переименования файла, он может перенести изменения из Foo.c в переименованный файл Bar.c путём слияния. Для простых удалений файлов или папок он может оставить элементы с изменениями разработчика А и отказаться от удаления. Или, пометив конфликт как улаженный и ничего больше не делая, отказаться в итоге от изменений разработчика А.

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

Локальное редактирование, поступающее при обновлении удаление

  1. Разработчик А переименовывает Foo.c в Bar.c и фиксирует это в хранилище.

  2. Разработчик Б изменяет Foo.c в своей рабочей копии.

Или в случае переименования папки...

  1. Разработчик А переименовывает родительскую папку FooFolder в BarFolder и фиксирует это в хранилище.

  2. Разработчик Б изменяет Foo.c в своей рабочей копии.

Обновление рабочей копии разработчика Б приводит к конфликту деревьев. Для простого конфликта файлов:

  • Bar.c добавлен в рабочую копию как обычный файл.

  • Foo.c помечен как добавленный (с историей) и как участвующий в конфликте деревьев.

Для конфликта папок:

  • BarFolder добавлена в рабочую копию как обычная папка.

  • FooFolder помечена как добавленная (с историей) и как участвующая в конфликте деревьев.

    Foo.c помечен как добавленный.

Теперь разработчик Б должен решить, принять ли проведённую разработчиком А реорганизацию и слить свои изменения с соответствующим файлом в новой структуре, или просто отменить эти изменения и оставить локальный файл.

Чтобы выполнить слияние своих локальных изменений с такой перетасовкой, разработчик Б сначала должен выяснить, какое имя получил конфликтующий файл Foo.c при переименовании/перемещении в хранилище. Это можно сделать при помощи диалога журнала. Затем изменения должны быть слиты вручную, поскольку на данный момент нет способа автоматизировать или даже упростить этот процесс. Как только изменения перенесены, конфликтующий файл больше не нужен и может быть удалён. В этом случае используйте кнопку Удалить в диалоге редактирования конфликтов для наведения порядка и для пометки конфликта как улаженного.

Если разработчик Б решает, что изменения разработчика А были неправильными, то он должен выбрать кнопку Оставить в диалоге редактирования конфликтов. Это помечает конфликтующий файл/папку как улаженные, но изменения разработчика А необходимо будет убрать вручную. Опять же диалог журнала поможет разыскать то, что было перемещено.

Локальное удаление, поступающее при обновлении удаление

  1. Разработчик А переименовывает Foo.c в Bar.c и фиксирует это в хранилище.

  2. Разработчик Б переименовывает Foo.c в Bix.c.

Обновление рабочей копии разработчика Б приводит к конфликту деревьев:

  • Bar.c помечен как добавленный с историей.

  • Bar.c добавлен в рабочую копию со статусом 'нормальный'.

  • Foo.c помечен как изменённый и участвующий в конфликте деревьев.

Для улаживания этого конфликта разработчик Б должен выяснить, какое имя получил конфликтующий файл Foo.c при переименовании/перемещении в хранилище. Это можно сделать при помощи диалога журнала.

Затем разработчик Б должен решить, какое из новых имён файла Foo.cоставить - то, которое дал разработчик А или то, в которое он переименовал его сам.

После того, как разработчик Б вручную уладил этот конфликт, конфликт деревьев помечается как улаженный при помощи кнопки в диалоге редактирования конфликтов.

Локально отсутствующее, поступающее при обновлении редактирование

  1. Разработчик А, работая в стволе, изменяет Foo.c и фиксирует это в хранилище.

  2. Разработчик Б, работая в ответвлении, переименовывает Foo.c в Bar.c и фиксирует это в хранилище.

Слияние изменений разработчика А в стволе с ответвлением в рабочей копии разработчика Б приводит к конфликту деревьев:

  • Bar.c уже в рабочей копии со статусом 'нормальный'.

  • Foo.c помечен как отсутствующий и участвующий в конфликте деревьев.

Для улаживания этого конфликта разработчик Б должен пометить файл как улаженный в диалоге редактирования конфликтов, который уберёт его из списка конфликтов. После этого он должен решить, скопировать отсутствующий файл Foo.c из хранилища в рабочую копию, или слить изменения разработчика А в файле Foo.c в переименованный Bar.c, или же проигнорировать изменения, пометив конфликт как улаженный и больше ничего не делая.

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

Локальное редактирование, поступающее при слиянии удаление

  1. Разработчик A работающий в trunk перемещает Foo.c в Bar.c и фиксирует это в хранилище.

  2. Разработчик Б, работая в ответвлении, изменяет Foo.c и фиксирует это в хранилище.

  1. Разработчик А, работая в стволе, переименовывает родительскую папку FooFolder в BarFolder и фиксирует это в хранилище.

  2. Разработчик Б, работая в ответвлении, изменяет Foo.c в своей рабочей копии.

Слияние изменений разработчика А в стволе с ответвлением в рабочей копии разработчика Б приводит к конфликту деревьев:

  • Bar.c помечен как добавленный.

  • Foo.c помечен как изменённый и участвующий в конфликте деревьев.

Теперь разработчик Б должен решить, принять ли проведённую разработчиком А реорганизацию и слить свои изменения с соответствующим файлом в новой структуре, или просто отменить эти изменения и оставить локальный файл.

Чтобы выполнить слияние своих локальных изменений с такой перетасовкой, разработчик Б сначала должен выяснить, какое имя получил конфликтующий файл Foo.c при переименовании/перемещении в хранилище. Это можно сделать при помощи диалога журнала для источника слияния. Редактор конфликтов показывает только журнал для рабочей копии, так как ему не известно, какой путь был использован при слиянии, и поэтому вы должны найти его самостоятельно. Затем изменения должны быть слиты вручную, поскольку на данный момент нет способа автоматизировать или даже упростить этот процесс. Как только изменения перенесены, конфликтующий файл больше не нужен и может быть удалён. В этом случае используйте кнопку Удалить в диалоге редактирования конфликтов для наведения порядка и для пометки конфликта как улаженного.

Если разработчик Б решает, что изменения разработчика А были неправильными, то он должен выбрать кнопку Оставить в диалоге редактирования конфликтов. Это помечает конфликтующий файл/папку как улаженные, но изменения разработчика А необходимо будет убрать вручную. Опять же диалог журнала для источника слияния поможет разыскать то, что было перемещено.

Локальное удаление, поступающее при слиянии удаление

  1. Разработчик A работающий в trunk перемещает Foo.c в Bar.c и фиксирует это в хранилище.

  2. Разработчик B работающий в ответвлении перемещает Foo.c в Bix.c и фиксирует это в хранилище.

Слияние изменений разработчика А в стволе с ответвлением в рабочей копии разработчика Б приводит к конфликту деревьев:

  • Bix.c помечен как имеющий нормальный (неизменённый) статус.

  • Bar.c помечен как добавленный с историей.

  • Foo.c помечен как отсутствующий и участвующий в конфликте деревьев.

Для улаживания этого конфликта разработчик Б должен выяснить, какое имя получил конфликтующий файл Foo.c при переименовании/перемещении в хранилище. Это можно сделать при помощи диалога журнала для источника слияния. Редактор конфликтов показывает только журнал для рабочей копии, так как ему не известно, какой путь был использован при слиянии, и поэтому вы должны найти его самостоятельно.

Затем разработчик Б должен решить, какое из новых имён файла Foo.cоставить - то, которое дал разработчик А или то, в которое он переименовал его сам.

После того, как разработчик Б вручную уладил этот конфликт, конфликт деревьев помечается как улаженный при помощи кнопки в диалоге редактирования конфликтов.

Другие конфликты деревьев

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