.gitattributes 是唯一能在 merge 时按文件粒度控制合并行为的机制,.gitignore 仅影响未跟踪文件,对已提交文件的合并完全无效;merge=ours 策略通过三路合并生效,需目标分支文件有先于源分支的修改记录,且 .gitattributes 必须提交到仓库。

.gitattributes 是唯一能在 merge 时按文件粒度控制合并行为的机制,.gitignore 完全无效——它只影响未跟踪文件,对已提交文件的合并毫无作用。
为什么 .gitignore 在合并时不起作用
很多人误以为把文件加进 .gitignore 就能跳过合并,这是根本性误解。.gitignore 只决定“哪些文件不被 Git 跟踪”,一旦文件已被提交(git add && git commit),它就彻底脱离 .gitignore 的管辖范围。合并时 Git 仍会尝试合并该文件的变更,忽略规则完全不触发。
.gitattributes + merge=ours 是标准解法
核心逻辑:为特定文件指定合并策略为 ours,即“无论对方分支怎么改,都保留当前分支(目标分支)的版本”。这不是跳过文件,而是让 Git 主动选择保留当前内容。
- 在仓库根目录创建或编辑
.gitattributes - 写入规则,例如:
yarn.lock merge=ours config/local.env merge=ours docker-compose.yml merge=ours
- 必须提前全局注册
ours驱动:git config --global merge.ours.driver true -
.gitattributes文件本身需提交:git add .gitattributes && git commit -m "setup merge=ours for critical files"
注意:merge=ours 不是“无条件覆盖”,它依赖 Git 的三路合并基础:只有当该文件在共同祖先、当前分支、待合并分支中都有变更时,策略才生效;若目标分支该文件从未修改过,Git 仍可能直接采用对方版本。
常见陷阱:文件修改时间顺序决定策略是否触发
这个细节极容易被忽略,但直接影响结果:
-
merge=ours策略生效的前提是:目标分支(如master)上该文件的最后提交时间 早于 源分支(如dev)上该文件的最后提交时间 - 换句话说:你得先在
master上“占位”修改一次要保留的文件(哪怕只加个空行),再在dev上改,最后执行git merge dev,ours才真正起效 - 如果
dev分支的yarn.lock是新生成的,而master上的仍是旧版且未动过,Git 可能直接采用dev版本,merge=ours形同虚设
验证方式:用 git log -p --oneline yarn.lock 查看各分支上该文件的最近修改提交哈希和时间戳。
替代方案对比:哪些场景不该用 merge=ours
不是所有“忽略”需求都适合 merge=ours:
-
git update-index --assume-unchanged <file>:仅对工作区有效,切换分支或克隆新仓库后失效,适合临时跳过本地调试文件,不适合协作流程 -
git rm --cached <file>+.gitignore:适用于彻底移出版本控制的文件(如本地配置),但会从所有分支删除该文件历史,不可逆 - 手动
git checkout HEAD -- <file>后再git commit:合并后人工还原,适合一次性操作,无法自动化
真正需要跨团队、跨分支稳定生效的“保留某分支版本”场景,.gitattributes 是唯一可维护、可审查、可提交的方案。其他方法要么作用域太窄,要么破坏历史一致性。


















