Решение конфликтов сцен в 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 стадии:

  1. UnityYAMLMerge пытается объединить объекты в сцену, чтобы впоследствии конфликт можно было решить в редакторе Unity
  2. Конфликты параметров, не решённые на первой стадии, разрешается теми же средствами, что и обычные конфликты кода

Подготовка

В статье "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:
Green spheres

red_cubes:
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

Результат

Объекты из обоих веток доступны для редактирования, а параметры зависят от слияния в DiffMerge:
Merge red

Merge green

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"

Sourcetree settings

Также не забываем про настройку интеграции с другими редакторами в mergespecfile.txt, о которой говорилось выше в консольной версии, без этого ничего работать не будет.

Использование:
Sourcetree external

Во время работы, так же как и при работе с консолью, будет вызван DiffMerge и мы получим тот же результат.

Альтернативы

  1. Основным методом борьбы с конфликтами в Unity является их недопущение:
    1. Деление сцены на большее количество префабов - это приведёт к разделению настроек объектов на разные уровни, в результате сцена не будет затрагиваться при их изменении и конфликты будут возникать сильно реже.
    2. Минимум одновременной работы со сценами - самым простой и доступный способ избежать конфликтов =)
  2. Для больших (и богатых) команд также есть альтернативы в виде плагинов, которые позволяют одновременное удалённое редактирование сцен, например, Scene Fusion. Пример работы можно посмотреть на Youtube.

Заключение

Слияние веток и решение конфликтов само по себе может быть не самой тривиальной задачей. Unity добавляет к этому ещё один уровень трудностей, связанный с настройкой UnityYAMLMerge, mergespecfile.txt и ваших любимых утилит для слияний, но это предсказуемая расплата за использование высокоуровневых редакторов объектов. Надеюсь, данная статья показала: “Не так страшен чёрт, как его малюют”. Главное понимать принципы работы и настроить подходящие(и работающие) инструменты. Конфликтуйте поменьше. Пока! =)



Privacy policyCookie policyTerms of service
Tulenber 2020