Решение конфликтов сцен в Unity и git при помощи UnityYAMLMerge
Tulenber ⸱
1 May, 2020 ⸱
Intermediate ⸱
7 min ⸱
2019.3.11f1 ⸱
Пришло время выполнить обещание данное в статье о настройке git для работы с Unity и разобраться, как с помощью UnityYAMLMerge решить конфликт, раз уж вы не успели закоммититься раньше вашего напарника.
В предыдущей статье "Кастомные элементы в редакторе Unity" мельком упоминалось о проблемах, которые могут появиться при распределённом использовании всяческих визуальных редакторов, как, например, blueprints в Unreal. В Unity, в полной мере этой проблеме подвержены сцены и префабы.
UnityYAMLMerge
Для решения конфликтов возникших со сценами и префабами Unity предлагает использовать утилиту под названием UnityYAMLMerge, по ссылке можно найти статью по её использованию, которая хоть и даёт всю необходимую информацию, но немного лаконична и не акцентирует внимание на важных аспектах её использования, о которых будет сказано ниже.
По сути, конфликты сцен и префабов в Unity можно разбить на 2 составляющие это конфликты объектов и конфликты параметров, соответственно их решение делится на 2 стадии:
- UnityYAMLMerge пытается объединить объекты в сцену, чтобы впоследствии конфликт можно было решить в редакторе Unity
- Конфликты параметров, не решённые на первой стадии, разрешается теми же средствами, что и обычные конфликты кода
Подготовка
В статье "Unity и git" приведена первоначальная настройка git необходимая для старта любого проекта. Для решения конфликтов нам дополнительно потребуется настроить в качестве git mergetool предоставляемый Unity - UnityYAMLMerge, а также вызываемый через mergespecfile.txt инструмент с возможностями трёхстороннего слияния, который поможет решить конфликты параметров.
Все настройки будут проводиться над локальными репозиториями, т.к. они являются специфическими для Unity, а их глобальное применение может сказаться на работе с другими типами проектов.
При возникновении конфликта и дальнейшем его решении git создаёт файлы, содержащие оригинал данных, *.orig, которые призваны обезопасить процесс, но определенно не нуждаются в дальнейшем хранении. Да и в целом при необходимости всегда можно откатить merge без применения этого файла. Для отключения их генерации используется настройка:
1
2
|
# Отключаем генерацию *.orig файлов в репозитории
git config --add mergetool.keepBackup false
|
Настройка UnityYAMLMerge в качестве инструмента слияния для git выглядит следующим образом:
1
2
3
4
5
6
7
8
9
|
# Добавляем UnityYAMLMerge в качестве инструмента для слияния
git config --add merge.tool unityyamlmerge
# Для macOs
# <path_to_unity_app> - путь до текущего расположения редактора Unity
git config --add mergetool.unityyamlmerge.cmd '<path_to_unity_app>/Unity.app/Contents/Tools/UnityYAMLMerge merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"'
# Для Windows
# git config --add mergetool.unityyamlmerge.cmd 'C:\Program Files (x86)\Unity\Editor\Data\Tools\UnityYAMLMerge.exe merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"'
|
Стандартные средства слияния
Также необходимо настроить работу стандартных средств слияния и вот тут-то и начинаются основные трудности =)
В директории рядом с исполняемым файлом UnityYAMLMerge находится файл mergespecfile.txt, он отвечает за инструмент слияния, который будет вызван при наличии конфликта параметров, которые утилита не может решить сама.
Данная статья писалась под macOs и мне так и не удалось заставить нормально работать стандартный opendiff(FileMerge), хоть он и делал вид, что всё нормально, на практике при изменении исходных значений слияние ломалось. Другие инструменты, такие как VSCode, Atom, Rider от Jet Brains, Sublime-Text, Sublime-Merge, KDiff3 или Diffuse не подошли по разным причинам, кто-то отказывается работать по схеме, предлагаемой UnityYAMLMerge, кому-то нужны дополнительные библиотеки. Самым рабочим из протестированных вариантов оказался включённый в mergespecfile.txt по умолчанию DiffMerge, который завёлся сразу и без приседаний, видимо, потому, что является одним из тестируемых инструментов. P4Merge(Perforce merge) тоже работает, но не совсем стабильно. Так что при возникновении проблем на macOs не забудьте закомментировать opendiff и настроить альтернативу.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
# UnityYAMLMerge fallback file
# Modify the next two lines if scene or prefab files should fallback
# on other that the default fallbacks listed below.
# %l is replaced with the path of you local version
# %r is replaced with the path of the incoming remote version
# %b is replaced with the common base version
# %d is replaced with a path where the result should be written to
# On Windows %programs% is replaced with "C:\Program Files" and "C:\Program Files (x86)" there by resulting in two entries to try out
# On OSX %programs% is replaced with "/Applications" and "$HOME/Applications" thereby resulting in two entries to try out
unity use "%programs%\YouFallbackMergeToolForScenesHere.exe" "%l" "%r" "%b" "%d"
prefab use "%programs%\YouFallbackMergeToolForPrefabsHere.exe" "%l" "%r" "%b" "%d"
# Default fallbacks for unknown files. First tool found is used.
# Apple File Merge
# Практически не работал на момент написания статьи, так что советую закомментировать и использовать DiffMerge
#* use "/usr/bin/opendiff" %r %l -ancestor %b -merge %d
# Beyond Compare
* use "%programs%\Beyond Compare 4\bcomp.exe" "%r" "%l" "%b" "%d"
* use "%programs%\Beyond Compare 3\bcomp.exe" "%r" "%l" "%b" "%d"
* use "%programs%/Beyond Compare.app/Contents/MacOS/bcomp" "%r" "%l" "%b" "%d"
* use "/usr/bin/bcompare" "%r" "%l" "%b" "%d"
# Araxis Merge
* use "%programs%\Araxis\Araxis Merge\compare.exe" /3 /a2 /wait /title1:"Other" /title2:"Base" /title3:"Local" "%l" "%b" "%r" "%d"
* use "%programs%/Araxis Merge.app/Contents/Utilities/compare" -3 -a2 -wait -title1:"Other" -title2:"Base" -title3:"Local" "%l" "%b" "%r" "%d"
# Perforce merge
* use "%programs%\Perforce\p4merge.exe" "%b" "%r" "%l" "%d"
* use "%programs%/p4merge.app/Contents/Resources/launchp4merge" "%b" "%r" "%l" "%d"
# PlasticSCM merge
* use "%programs%\PlasticSCM5\client\mergetool.exe" -b=%b -s=%l -d=%r -r=%d
* use "%programs%\PlasticSCM4\client\mergetool.exe" -b=%b -s=%l -d=%r -r=%d
* use "%programs%/PlasticSCM/client/mergetool" -b=%b -s=%l -d=%r -r=%d
* use "/opt/plasticscm/client/mergetool" -b=%b -s=%l -d=%r -r=%d
* use "/opt/plasticscm4/client/mergetool" -b=%b -s=%l -d=%r -r=%d
# SourceGear DiffMerge
* use "%programs%\SourceGear\DiffMerge\DiffMerge.exe" --nosplash -m -t1="Incoming Changes" -t2="Base" -t3="Working Copy" -r="%d" "%l" "%b" "%r"
* use "%programs%\SourceGear\Common\DiffMerge\sgdm.exe" --nosplash -m -t1="Incoming Changes" -t2="Base" -t3="Working Copy" -r="%d" "%l" "%b" "%r"
* use "%programs%/DiffMerge.app/Contents/MacOS/DiffMerge" --nosplash -m -t1="Incoming Changes" -t2="Base" -t3="Working Copy" -r="%d" "%l" "%b" "%r"
* use "%programs%/Utilities/DiffMerge.app/Contents/MacOS/DiffMerge" --nosplash -m -t1="Incoming Changes" -t2="Base" -t3="Working Copy" -r="%d" "%l" "%b" "%r"
|
У VSCode в планах на 2020 год стоит добавление полноценной поддержки трёхстороннего слияния, будем надеяться, что она будет нормально интегрироваться с UnityYAMLMerge.
Тестовый проект
Для теста был создан проект с двумя ветками green_spheres:
red_cubes:
Попытка слить ветку red_cubes в green_spheres приводит к конфликту
1
2
3
4
5
6
7
8
9
10
11
|
tulenber@mac-tulenber Merge % git status
On branch red_cubes
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: Assets/Scenes/MergeScene.unity
no changes added to commit (use "git add" and/or "git commit -a")
|
Использование
Вызов git mergetool сливает объекты в одну сцену
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
tulenber@mac-tulenber Merge % git mergetool --tool=unityyamlmerge
Merging:
Merge/Assets/Scenes/MergeScene.unity
Normal merge conflict for 'Merge/Assets/Scenes/MergeScene.unity':
{local}: modified file
{remote}: modified file
Conflicts:
Left 705507994.Light.m_Color
r change to 0
g change to 0.735849
b change to 0.01896981
Right 705507994.Light.m_Color
g change to 0.41037738
b change to 0.44684783
Conflict handling:
|
Неразрешённые конфликты параметров вызывают DiffMerge:
Результат
Объекты из обоих веток доступны для редактирования, а параметры зависят от слияния в DiffMerge:
Sourcetree
Sourcetree - клиент git, разрабатываемый компанией Atlassian, который прекрасно работает как на Windows, так и на macOs. Bitbucket для него является родным сервисом, но также не представляет проблем и настройка на Github. Определённо он очень распространён, так что приведём настройку и для него.
Настройка схожа с консольным вариантом. Добавление UnityYAMLMerge в External Merge tool - Preferences > Diff > External Diff / Merge
:
Merge command
- 〈path_to_unity_app〉/Unity.app/Contents/Tools/UnityYAMLMerge
Arguments
- merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"
Также не забываем про настройку интеграции с другими редакторами в mergespecfile.txt, о которой говорилось выше в консольной версии, без этого ничего работать не будет.
Использование:
Во время работы, так же как и при работе с консолью, будет вызван DiffMerge и мы получим тот же результат.
Альтернативы
- Основным методом борьбы с конфликтами в Unity является их недопущение:
- Деление сцены на большее количество префабов - это приведёт к разделению настроек объектов на разные уровни, в результате сцена не будет затрагиваться при их изменении и конфликты будут возникать сильно реже.
- Минимум одновременной работы со сценами - самым простой и доступный способ избежать конфликтов =)
- Для больших (и богатых) команд также есть альтернативы в виде плагинов, которые позволяют одновременное удалённое редактирование сцен, например, Scene Fusion. Пример работы можно посмотреть на Youtube.
Заключение
Слияние веток и решение конфликтов само по себе может быть не самой тривиальной задачей. Unity добавляет к этому ещё один уровень трудностей, связанный с настройкой UnityYAMLMerge, mergespecfile.txt и ваших любимых утилит для слияний, но это предсказуемая расплата за использование высокоуровневых редакторов объектов. Надеюсь, данная статья показала: “Не так страшен чёрт, как его малюют”. Главное понимать принципы работы и настроить подходящие(и работающие) инструменты. Конфликтуйте поменьше. Пока! =)