Unidade + git = amizade: parte 1 conjunto de cavalheiros

imagem
O sistema de controle de versão git há muito se tornou o padrão de fato no mundo do desenvolvimento, mas para a maioria dos desenvolvedores do Unity, não é segredo que existem várias dificuldades associadas aos recursos do Unity que impedem que ele seja usado efetivamente com o git.

Aqui está uma lista de problemas comuns:

  1. arquivos desnecessários entram no repositório ou vice-versa, não os adequados
  2. muitos arquivos grandes aumentam o tamanho do repositório
  3. problema com arquivos de mesclagem yaml Unity
  4. somente o arquivo em si ou apenas a meta são adicionados ao repositório
  5. existem pastas vazias no projeto
  6. complexidade da numeração automática de versões e compilações
  7. inconveniência de usar código entre vários projetos

Você pode ler sobre a solução para esses problemas relacionados ao uso conjunto de git e Unity em minha série de artigos.

Este artigo descreve a solução para os três primeiros problemas.

Vamos tentar descrever em etapas os métodos para resolver cada um dos problemas.

A primeira coisa que precisamos fazer após a criação do repositório para o seu projeto é configurar exceções, não vou me debruçar sobre isso em detalhes, aqui está um bom exemplo .

A única observação é que você provavelmente deve adicionar algumas exceções ao final
! * .Dll - porque se você usar plug-ins ou recursos de terceiros, precisará armazenar a dll no repositório e, no Windows, o git ignora a dll por padrão;
! *. obj - se você usa modelos nesse formato, novamente nos arquivos obj do Windows podem ser ignorados por padrão

minha versão é .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


A segunda etapa, tentaremos resolver o problema do crescimento do repositório a partir de arquivos grandes. Esta solução é LFS

mais sobre o LFS
LFS — git, git , key-value .

, git LFS checkout .

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

Para configurar os tipos de arquivo lfs para o nosso repositório, adicione .gitattributesalgumas linhas ao arquivo na raiz do projeto (talvez seja necessário criá-lo e o Windows não permita que você crie um arquivo com isso no Explorer)

## 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

a maioria dos arquivos que são binários e podem ser bastante grandes estão listados aqui. Vou explicar um pouco: as

linhas que começam com # são comentários;
filter=lfs diff=lfs merge=lfs- são palavras mágicas que fazem o git usar lfs para esses tipos de arquivos; -text significa que o arquivo é binário e você não precisa mesclá-lo.

Se o seu projeto usa outros arquivos binários grandes, adicione-os aqui mais tarde, alterar o tipo de armazenamento de arquivos (transferir para lfs ou removê-lo de lá) será bastante difícil.

O próximo passo é tentar melhorar um pouco a situação com mesclagens complexas.
O Unity inclui o utilitário UnityYAMLMerge , que permite mesclar efetivamente arquivos yaml. Adicione .gitattributesalgumas linhas ao arquivo :

*.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

Deixe-me explicar o que fizemos:
para arquivos .cs, eles sugeriram que haveria texto sendo código C #;
para arquivos cginc e shader, eles também escolheram uma representação textual
para a maioria dos arquivos yaml do Unity, escolheram um driver de mesclagem personalizado unityyamlmerge

Você também precisa configurá-lo: adicione o seguinte código a qualquer .gitconfig, mais simplesmente ao local localizado no caminho .git / config de raiz do repositório:

[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

O sinalizador -p força o UnityYamlMerge a alterar o conteúdo dos arquivos, mesmo que o conflito não possa ser completamente resolvido, e simplifica muito sua resolução adicional manualmente. Por exemplo, ao mesclar duas ramificações onde a mesma cena foi alterada, usando o mecanismo padrão de mesclagem git, veremos muitas mudanças. Ao usar um driver personalizado, mesmo que o mesmo campo do mesmo componente tenha sido alterado, haverá exatamente 1 linha no conflito.

Por conveniência, criei um pequeno script que permitirá que o unityyamlmerge seja instalado automaticamente na primeira vez que um projeto for aberto pelo Unity. Ele pode ser colocado em qualquer lugar da pasta Assets (requer que o git seja instalado no sistema e esteja registrado na variável PATH, ou seja, seja acessível pelo comando git);

esta aula
#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 .

versão 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


Depois de concluir essas etapas, eu recomendo confirmar o estado atual do repositório.

Projeto pronto https://github.com/newnon/UnityGitHabr1
mais uma vez, lembro que você deve funcionar corretamente, o git deve estar instalado no sistema e acessível pelo comando git.

Se você quiser experimentar
github test1 test2 test3
merge test1 test2 test3
test2 test1 test3 m_LocalPosition
E Unity Tools/Git/

All Articles