Unity 场景在 Git 里合并不了,该怎么修?

这是一个有文档记载的常见 Unity 工作流问题,不是一次点名的上线游戏事故:两位开发者改同一个场景,Git 冲突,而纯文本合并读不懂场景结构。Unity 6000.6 文档把 UnityYAMLMerge 描述为场景、prefab 与 meta 文件的语义合并工具,Game Developer 的 Unity 与 Git 指南也走过同样的冲突与 git mergetool 流程。

Unity 场景在 Git 里合并不了,该怎么修?
本篇导航5 个章节

两位开发者改同一个 Unity 场景,Git 一合并,场景打不开了;更糟的是能打开,但有东西悄悄没了。这不是某家工作室的灾难故事,而是 Unity 开发里最常见的版本控制失败,而且它有文档、有解释、大多可以预防。

Game Developer 指南里的一张旧版 Unity 编辑器截图,红色标注圈出 Editor Settings 面板:Version Control 模式为 Visible Meta Files,Asset Serialization 模式为 Force Text,路径是 Edit、Project Settings、Editor。这是旧版 Unity 界面,不是当前 Unity 6 的样子,也不是合并冲突截图。

快速信息

  • 来源:Unity 6000.6 官方文档 Smart merge;Unity 6000.3 官方文档 Editor project settings reference;Game Developer《The complete guide to Unity and Git》(2026 年 8 月 17 日更新)。

  • 定性:有文档记载的常见工作流问题,不是一次点名的上线游戏事故。本文没有点名任何工作室或游戏说它们因此丢过东西。

  • 根因一句话:场景文件是一份描述所有对象的 YAML 文档,而纯 Git 合并的是行,不是对象。

  • 修复一句话:Force Text 序列化、Visible Meta Files,再把 UnityYAMLMerge 设为 Git 合并工具,合并后的场景提交前先在 Unity 里打开验证。

  • 版本说明:工具路径已于 2026 年 10 月 29 日对照 Unity 6000.6 文档核对。旧指南里的工具路径已经过时,不要照搬。

  • 最后核实:2026年10月29日。

每个 Unity 团队迟早都会遇到的冲突

Game Developer 指南走了一遍每个 Unity 开发者都认得的场景:你合并一个功能分支,Git 先打印正在自动合并某个场景文件,接着报冲突、自动合并失败,让你修好冲突再提交。指南例子里的文件叫 GameOver.unity,但名字不重要;重要的是失败的形态:两个分支改了同一个场景,而擅长合并代码的 Git 突然力不从心了。指南接着运行 git mergetool,接手的是 Unity 自带的 Smart Merge,也就是 UnityYAMLMerge。Git 放弃、Smart Merge 接手,这个两步形态就是本文的全部故事。

根因在冲突提示的下一层。Unity 场景文件是一份 YAML 文档,列出每个 GameObject、每个组件、以及它们之间的每个引用。两个人改同一个场景里的不同对象时,Git 看到的仍是一份在重叠或相邻行里有改动的文件,于是哪怕没人改过同一个对象,它也会报冲突。更糟的是,纯文本合并根本不知道场景是什么:它能把 YAML 块拼成看起来合好了的样子,却破坏对象引用,因为它从不检查结果是不是合法场景。而如果项目从没设为 Force Text,情况还要糟:Game Developer 指南说得很直白,二进制文件的改动永远无法自动合并、一定会冲突。所以修复要从合并之前开始,从项目设置开始,而不是在冲突界面上临时想办法。

Smart Merge 到底理解什么

Unity 6000.6 文档把 UnityYAMLMerge 描述为以语义正确的方式合并场景、prefab 与 meta 文件的工具。“语义正确”是关键词:Git 看到的是行,这个工具看到的是对象,所以同一个场景里不同对象的改动可以合并而不是冲突。文档对它的上限也说得很清楚:它不处理的文件、以及它解决不了的冲突,会交给 mergespecfile.txt 里列出的兜底合并工具;用 premerge 选项时,它先合并所有能合并的部分,再把只剩冲突的文件交给兜底工具。默认它不合并 material、asset、controller 这类其他 YAML 文件,那些会走兜底工具,除非你用 force 选项强制。所以 Smart Merge 不是终结合并冲突的魔法,它是一个理解场景结构的工具,解决容易的大多数,剩下的交给人工。

配置分两半,文档里都有。第一,项目本身:在 Edit、Project Settings、Editor 里,把 Version Control 模式设为 Visible Meta Files,让 meta 文件以普通文件形式写入;把 Asset Serialization 模式设为 Force Text,让场景和 prefab 以 YAML 文本存储。Unity 6000.3 编辑器设置参考说 Force Text 是默认值,还提供一个减少版本控制噪音的选项,把 YAML 引用写在一行——这个选项的存在正是因为场景保存时可能改写比你动过的更多的行。Game Developer 指南补了团队层面的理由:这些设置存在 ProjectSettings 里、跟着仓库走,所以队友会直接继承。第二,Git 一侧:在仓库配置或全局 gitconfig 里把 UnityYAMLMerge 加为合并工具,trustExitCode 设为 false,合并命令传入 base、remote、local 与 merged 四个文件。核对文档时发现一个警告:Game Developer 指南里的旧工具路径(Contents Tools 文件夹下)已经过时。Unity 6000.6 文档说,工具在 Unity Hub 编辑器安装目录下,Windows 与 Linux 在 Editor Data Tools 里,macOS 在 Unity 应用的 Helpers 文件夹里。请从你自己装的编辑器版本里复制路径,不要抄旧博客。

能复用的部分

下面所有步骤只适用于你自己的项目和你自己的仓库,不碰线上服务、共享服务器或别人的工作。最重要的一步也是最不起眼的一步:合并后、提交前,先在 Unity 里打开场景。Game Developer 指南警告,Git 有时会在冲突实际已解决时仍报告文件未变,它给的检验方法正是这一条:在 Unity 里打开冲突文件,如果里面还残留冲突标记,它会打不开;如果能打开,就在 Inspector 里检查两侧的新值都在。合并好的场景不是 Git 说了算,而是编辑器能打开、两侧改动都看得见才算。

周一早上照着做

  • 只在你自己的项目里操作:打开 Edit、Project Settings、Editor,把 Version Control 模式设为 Visible Meta Files,Asset Serialization 模式设为 Force Text;保存项目并提交这次设置改动,让全队继承。

  • 把 Git 指向你自己装的编辑器版本里的 UnityYAMLMerge,用 Unity 6000.6 文档里的路径,不要抄旧文章的路径。在仓库配置里加入合并工具段,trustExitCode 设为 false,合并命令传入 base、remote、local 与 merged 文件。

  • 在你自己仓库的一个临时分支上演练:两个分支各改同一个场景里的不同对象,合并,运行 git mergetool,确认两侧改动都在结果里。

  • 每次场景合并后、提交前,先在 Unity 里打开场景。在 Inspector 里检查两侧的新值都在,再跑一次简短的 Play Mode 冒烟测试。

  • 如果 mergetool 之后 Git 报告文件未变,不要只信这一句。还残留冲突标记的文件在 Unity 里打不开,所以说了算的是在 Unity 里打开这一步,不是 Git 状态。

  • 从源头缩小未来的冲突:场景保持小巧,共享内容拆成 prefab,能避免两个人同时改同一个场景就尽量避免。