Unity项目spriteatlas文件在git中显示修改,但又无法提交的问题

最近,团队的Unity客户端工程开始使用图集后就经常出现在Git客户端中显示图集文件 (*.spriteatlas) 发生了修改(Modified) ,但在Stage时却又无法生效的情况。作为团队的Git布道师,我今天开始协助解决问题,然后把问题原因形成博文做个记录。

基础知识

首先,我们需要对什么是文本文件和二进制文件有个了解。可以这么理解,所有文件都是以二进制数据,这里说的文本文件只是一种特殊的与通常人类使用的文本语言相关的文件,可以通过文本编辑器像平时纸币书写类似的方式进行编辑。关于这个话题,知乎上有个讨论,此处只希望有个概念,不做严谨分析。而对于文本文件,它的格式又是与操作系统相关的。在Unix系统上,以\n (0x0A) 作为换行符(即表示新的一行的开始),而在Windows系统上,则是以\r\n (0x0D 0x0A) 作为换行符。其次,我们需要明确,Git是根据文件的SHA1值来判断文件是否有修改(是否是同一个文件)。由此,我们可以得出一个结论:如果两个文本文件“看起来” 是一样的,但是换行符不同,他们的SHA1一定不同。

Git对文本文件的处理

对于团队协作的开发项目来说,团队成员很有可能使用不同的操作系统,那就会面临同一份代码文件在不同的系统上实际会因为换行符不同而产生不同的SHA1值,那么是不是这些文件即是不变更,只要在不同的系统打开再保存就会显示修改呢?显示不能这样,那Git是如何处理的呢?Git在Windows系统上默认将识别的文本文件在commit到Git仓库时自动将换行符\r\n 替换为 \n, 而在checkout到本地工作区时,自动\n 替换为 \r\n 。当然,默认行为可以修改,可以设置提交时默认替换为 \r\n 。这样在Git仓库中有一种确定的换行符格式,而在不同的工作区中根据系统又使用不同的换行符,很好的解决了这个跨平台问题。

图集文件的换行符

在Windows系统中,关闭Unity,使Git工作区处于干净状态(没有任何修改)时,此时用可以查看换行符或者可以以十六进制格式打开文件的编辑器,例如Nodepad++,VisualStudioCode打开一个Unity项目中使用的*.spriteatlas 会发现换行符为 \r\n 。然后启动Unity打开客户端项目,触发重新保存图集文件,此时虽然没有做任何修改,会发现Git工作区中出现了 Modified 状态的图集文件,再在编辑器中打开对应的*.spriteatlas 会发现,换行符变为了 \n 。这说明即使在Windows系统上,Unity保存 *.spriteatlas 文件时也是使用 \n 作为换行符。因为换行符发生了变化,Git提示文件有修改,但是当重新提交修改文件时,因为Git自动转行换行符后发现转换后的文件与仓库中HEAD指向的当前文件相比没有发生变化,于是提交失败

解决办法

因为 *.spriteatlas 文件只会在Unity中修改,不会手动通过其它编辑器去修改,所以应该以 \n 作为这种类型文件的换行符,而不需要根据不同的系统进行转换。那我们只要告诉Git不要把 spriteatlas 文件当作文本文件处理即可,这样也不会影响对代码文件换行符的正确的默认处理。这可以通过在Git项目中增加 .gitattributes 文件进行设置。

# Set the default behavior, in case people don't have core.autocrlf set.
 * text=auto

 # Explicitly declare text files you want to always be normalized and converted
 # to native line endings on checkout.
 *.c text
 *.h text

 # Declare files that will always have CRLF line endings on checkout.
 *.sln text eol=crlf

 # Denote all files that are truly binary and should not be modified.
 *.png binary
 *.jpg binary
 *.spriteatlas binary
 *.prefab binary
 *.meta binary

同理,对于那些只会通过Unity进行修改的文件,我们应该都将它们作为binary处理,例如prefab, meta文件。

Contents