Unidad + git = amistad: parte 1 conjunto de caballeros

imagen
El sistema de control de versiones de git se ha convertido durante mucho tiempo en el estándar de facto en el mundo del desarrollo, pero para la mayoría de los desarrolladores de Unity no es ningún secreto que existen varias dificultades asociadas con las características de Unity que impiden que se use efectivamente con git.

Aquí hay una lista de problemas comunes:

  1. los archivos innecesarios ingresan al repositorio o viceversa, no obtienen los correctos
  2. muchos archivos grandes inflan el tamaño del repositorio
  3. problema con la fusión de archivos yaml Unity
  4. solo el archivo en sí o solo el meta se agrega al repositorio
  5. hay carpetas vacías en el proyecto
  6. Complejidad de la numeración automática de versiones y compilaciones
  7. inconveniencia de usar código entre múltiples proyectos

Puede leer sobre la solución a estos problemas relacionados con el uso conjunto de git y Unity en mi serie de artículos.

Este artículo describirá la solución a los primeros tres problemas.

Intentemos describir en pasos los métodos para resolver cada uno de los problemas.

Lo primero que debemos hacer después de crear el repositorio para su proyecto es configurar excepciones, no me detendré en esto con gran detalle, aquí hay un buen ejemplo .

¡La única observación es que probablemente debería agregar un par de excepciones al final
! *. Dll - porque si usa complementos o activos de terceros, tendrá que almacenar el dll en el repositorio y en Windows git ignora el dll por defecto;
! *. obj: si utiliza modelos en este formato, de nuevo en Windows los archivos obj pueden ignorarse de forma predeterminada

mi versión es .gitignore
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/

# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/

# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta

# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*

# Autogenerated Jetbrains Rider plugin
/[Aa]ssets/Plugins/Editor/JetBrains*

# Visual Studio cache directory
.vs/

# Gradle cache directory
.gradle/

# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db

# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta

# Unity3D generated file on crash reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

# Crashlytics generated file
crashlytics-build.properties

# Packed Addressables
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*

# Temporary auto-generated Android Assets
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*

# Exceptions
!*.dll
!*.obj


El segundo paso trataremos de resolver el problema del crecimiento del repositorio a partir de archivos grandes. Esta solución es LFS

más sobre LFS
LFS — git, git , key-value .

, git LFS checkout .

:
www.atlassian.com/git/tutorials/git-lfs

Para configurar los tipos de archivo lfs para nuestro repositorio, agregue .gitattributesalgunas líneas al archivo en la raíz del proyecto (puede que tenga que crearlo, y Windows puede no permitirle crear un archivo con esto en el Explorador)

## git-lfs ##

#Image
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.cubemap filter=lfs diff=lfs merge=lfs -text
*.svg filter=lfs diff=lfs merge=lfs -text

#Audio
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text

#Video
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text

#3D Object
*.FBX filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text

#ETC
*.a filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.unitypackage filter=lfs diff=lfs merge=lfs -text
*.aif filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.rns filter=lfs diff=lfs merge=lfs -text
*.reason filter=lfs diff=lfs merge=lfs -text
*.lxo filter=lfs diff=lfs merge=lfs -text

La mayoría de los archivos que son binarios y pueden ser bastante grandes se enumeran aquí. Explicaré un poco: las

líneas que comienzan con # son comentarios;
filter=lfs diff=lfs merge=lfs- Estas son palabras mágicas que hacen que git use lfs para este tipo de archivos; -text significa que el archivo es binario y no necesita fusionarlo.

Si su proyecto usa cualquier otro archivo binario grande, agréguelos aquí más adelante, cambiar el tipo de almacenamiento de archivos (transferir a lfs o eliminarlo de allí) será bastante difícil.

El siguiente paso es tratar de mejorar ligeramente la situación con fusiones complejas.
Unity incluye la utilidad UnityYAMLMerge , que le permite fusionar efectivamente archivos yaml. Agregue .gitattributesalgunas líneas al archivo :

*.cs diff=csharp text
*.cginc text
*.shader text

*.mat merge=unityyamlmerge
*.anim merge=unityyamlmerge
*.unity merge=unityyamlmerge
*.prefab merge=unityyamlmerge
*.physicsMaterial2D merge=unityyamlmerge
*.physicsMaterial merge=unityyamlmerge
*.asset merge=unityyamlmerge
*.meta merge=unityyamlmerge
*.controller merge=unityyamlmerge

Permítanme explicar lo que hicimos:
para los archivos .cs sugirieron que habría texto siendo código C #;
también para los archivos cginc y shader, eligieron una representación textual
para la mayoría de los archivos Unity yaml, eligieron un controlador de fusión personalizado unityyamlmerge

También debe configurarlo: agregue el siguiente código a cualquier .gitconfig, más simplemente al local ubicado en la ruta .git / config de raíz del repositorio:

[merge "unityyamlmerge"]
	name = Unity SmartMerge (UnityYamlMerge)
	driver = \"{    Unity}/Editor/Data/Tools/UnityYAMLMerge.exe\" merge -h -p --force --fallback none %O %B %A %A
	recursive = binary

El indicador -p obliga a UnityYamlMerge a cambiar el contenido de los archivos incluso si el conflicto no se puede resolver por completo, y simplifica enormemente su resolución adicional a mano. Por ejemplo, al fusionar dos ramas donde se cambió la misma escena, usando el mecanismo estándar de fusión git, veremos muchos cambios. Al usar un controlador personalizado, incluso si se ha cambiado el mismo campo del mismo componente, habrá exactamente 1 línea en el conflicto.

Por conveniencia, creé un pequeño script que permitirá que unityyamlmerge se instale automáticamente la primera vez que Unity abra un proyecto. Se puede colocar en cualquier lugar de la carpeta Assets (requiere que git esté instalado en el sistema y se registre en la variable PATH, es decir, que sea accesible mediante el comando git);

esta clase
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System;

namespace GitIntegration
{
    [InitializeOnLoad]
    public class SmartMergeRegistrator
    {
        const string SmartMergeRegistratorEditorPrefsKey = "smart_merge_installed";
        const int Version = 1;
        static string VersionKey = $"{Version}_{Application.unityVersion}";

        public static string ExecuteGitWithParams(string param)
        {
            var processInfo = new System.Diagnostics.ProcessStartInfo("git");

            processInfo.UseShellExecute = false;
            processInfo.WorkingDirectory = Environment.CurrentDirectory;
            processInfo.RedirectStandardOutput = true;
            processInfo.RedirectStandardError = true;
            processInfo.CreateNoWindow = true;

            var process = new System.Diagnostics.Process();
            process.StartInfo = processInfo;
            process.StartInfo.FileName = "git";
            process.StartInfo.Arguments = param;
            process.Start();
            process.WaitForExit();

            if (process.ExitCode != 0)
                throw new Exception(process.StandardError.ReadLine());

            return process.StandardOutput.ReadLine();
        }

        [MenuItem("Tools/Git/SmartMerge registration")]
        static void SmartMergeRegister()
        {
            try
            {
                var UnityYAMLMergePath = EditorApplication.applicationContentsPath + "/Tools" + "/UnityYAMLMerge.exe";
                ExecuteGitWithParams("config merge.unityyamlmerge.name \"Unity SmartMerge (UnityYamlMerge)\"");
                ExecuteGitWithParams($"config merge.unityyamlmerge.driver \"\\\"{UnityYAMLMergePath}\\\" merge -h -p --force --fallback none %O %B %A %A\"");
                ExecuteGitWithParams("config merge.unityyamlmerge.recursive binary");
                EditorPrefs.SetString(SmartMergeRegistratorEditorPrefsKey, VersionKey);
                Debug.Log($"Succesfuly registered UnityYAMLMerge with path {UnityYAMLMergePath}");
            }
            catch (Exception e)
            {
                Debug.Log($"Fail to register UnityYAMLMerge with error: {e}");
            }
        }

        //Unity calls the static constructor when the engine opens
        static SmartMergeRegistrator()
        {
            var instaledVersionKey = EditorPrefs.GetString(SmartMergeRegistratorEditorPrefsKey);
            if (instaledVersionKey != VersionKey)
                SmartMergeRegister();
        }
    }
}
#endif

: , Unity , EditorPrefs «» , ( , Unity, ) git gitconfig .

versión final de .gitattributes
## Unity ##

*.cs diff=csharp text
*.cginc text
*.shader text

*.mat merge=unityyamlmerge
*.anim merge=unityyamlmerge
*.unity merge=unityyamlmerge
*.prefab merge=unityyamlmerge
*.physicsMaterial2D merge=unityyamlmerge
*.physicsMaterial merge=unityyamlmerge
*.asset merge=unityyamlmerge
*.meta merge=unityyamlmerge
*.controller merge=unityyamlmerge


## git-lfs ##

#Image
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.cubemap filter=lfs diff=lfs merge=lfs -text
*.svg filter=lfs diff=lfs merge=lfs -text

#Audio
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text

#Video
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text

#3D Object
*.FBX filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text

#ETC
*.a filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.unitypackage filter=lfs diff=lfs merge=lfs -text
*.aif filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.rns filter=lfs diff=lfs merge=lfs -text
*.reason filter=lfs diff=lfs merge=lfs -text
*.lxo filter=lfs diff=lfs merge=lfs -text


Después de completar estos pasos, recomiendo confirmar el estado actual del repositorio.

Proyecto listo https://github.com/newnon/UnityGitHabr1
una vez más, le recuerdo que trabaje correctamente, git debe estar instalado en el sistema y accesible mediante el comando git.

Si quieres experimentar
github test1 test2 test3
merge test1 test2 test3
test2 test1 test3 m_LocalPosition
E Unity Tools/Git/

All Articles