git无法自动合并二进制文件,冲突时仅保留双方版本;需用.gitattributes声明binary禁用合并,或改用git lfs管理以支持指针级合并与sha变更追踪。

Git 无法自动合并二进制文件,冲突时只保留双方版本
Git 默认把所有未声明类型的文件都当作文本处理,但一旦文件被识别为二进制(比如 .png、.pdf、.exe、.docx),它就放弃逐行比对,转而直接标记为“冲突”——不是报错,而是静默跳过合并,把两个版本都留在工作区,等着你手动选一个或另作处理。
常见错误现象:git status 显示文件为 both modified,但 git diff 几乎不输出内容;用 git checkout --ours 或 --theirs 能切出对应版本,但没提示、没备份、也没中间状态记录。
- Git 判断二进制的依据是文件头前 800 字节是否含空字节(
\0),不是后缀名——所以某些 UTF-16 编码的文本文件也可能被误判 - 如果项目里混有大量二进制资产(如 Unity 的
.asset、Figma 导出的.sketch),不提前配置,每次 merge 都得人工核对 - 没有 .gitattributes 声明时,
git merge-file、git checkout -m等工具对二进制完全无效
用 .gitattributes 强制声明二进制并禁用合并
这是最稳定、最轻量的解法:告诉 Git “这个类型永远不要尝试合并”,避免它在冲突时做无意义的猜测。
在仓库根目录建 .gitattributes,写入:
*.png binary *.psd binary *.zip binary *.unitypackage binary
这样 Git 就会在检测到这些后缀的文件发生冲突时,直接拒绝自动合并,并在 git status 中明确标为 unmerged,而不是假装能处理。
-
binary是关键字,等价于-merge -diff,既禁用合并逻辑,也禁用 diff 输出 - 别用
merge=ours这类策略——它只影响合并算法,对二进制文件不生效;Git 在判定为 binary 后根本不会调用 merge driver - 路径匹配支持通配符,但不支持正则;优先级按文件从上到下匹配,越靠后越优先
需要保留历史 diff?改用 git lfs 管理大二进制文件
如果团队常要对比二进制文件的版本差异(比如设计稿迭代、模型权重更新),光靠 binary 声明不够——Git 本身不存二进制 diff,git diff 永远为空。
这时候该上 git lfs:它把真实文件替换成指针,把大文件存在远程 LFS 服务器,本地只留元数据。好处是:
- 克隆/拉取变快(不下载完整二进制)
-
git diff能显示 LFS 指针变化(如sha256:abc123... → sha256:def456...),间接反映内容变更 - 冲突时 Git 仍按指针处理,而指针是纯文本,可自动合并;最终只需人工确认哪个 SHA 对应正确版本
- 需提前安装
git-lfs并运行git lfs install,再用git lfs track "*.psd"注册类型
注意:git lfs 不解决“怎么选版本”的问题,只让 Git 不再卡在二进制上;实际决策仍需人来比对预览图、哈希值或业务上下文。
临时救急:用 checkout --ours/--theirs + 手动校验
没配 .gitattributes 也没上 LFS?遇到冲突先别硬 commit。最安全的做法是显式取出一方版本,再人工验证。
例如冲突文件是 logo.png:
git checkout --ours logo.png # 取当前分支版本 # 或 git checkout --theirs logo.png # 取被合并分支版本
然后立刻用图像查看器打开确认是否正确——别依赖文件名或提交信息,二进制文件的“正确性”只能靠内容判断。
-
--ours和--theirs在 rebase 场景下含义会翻转,容易搞反;建议只在 merge 中使用,并先跑git log --oneline --graph --all确认分支关系 - 别用
git add logo.png直接加冲突文件——Git 会报错error: path 'logo.png' is unmerged - 如果两边都要保留,重命名再
git add,比如logo_v1.png和logo_v2.png,后续靠文档或注释说明区别
真正麻烦的从来不是 Git 怎么选,而是没人知道哪一版才是对的——二进制文件没上下文,冲突时缺的是判断依据,不是操作命令。











