git合并时无法靠.gitignore跳过已跟踪文件,因其仅对未跟踪文件生效;真正有效的是.gitattributes配合merge=ours策略,且需全局注册驱动、提交.gitattributes文件,并确保目标分支对该文件有晚于源分支的修改记录。

Git 合并时无法靠 .gitignore 跳过已跟踪文件——它只管“未提交的新文件”,对历史中已存在的 config.yml、yarn.lock 等完全无效。真要跳过,必须用 .gitattributes + merge=ours。
为什么 .gitignore 在合并里不起作用
很多人把 application.properties 加进 .gitignore 后,发现 merge 时它还是被覆盖了。这不是 Git bug,是机制使然:.gitignore 只影响 git add 阶段是否把新文件纳入暂存区;一旦该文件早已被 git commit 过,它就变成“已跟踪文件”,后续所有 diff、merge、rebase 都照常参与。
-
.gitignore对git status中显示为 “modified” 的文件毫无约束力 - 即使你删掉本地
.gitignore里的某行,只要文件还在 Git 历史里,它就永远会被合并 - 想绕开?唯一合法路径是让它“参与合并但自动选当前分支版本”,而不是“假装没这文件”
.gitattributes + merge=ours 怎么配才生效
这不是写完规则就一劳永逸的事。它依赖 Git 三路合并的触发条件,且受文件修改时间顺序影响。
Git Worktree 多需求并行开发助手:在当前 worktree 目录独立开发、修改、提交代码,不跨目录。基于目录命名规范自动识别仓库归属(如 main-repo-feature‑a → main‑repo 仓库)。遵循最小改动原则,从需求分析到 commit 交付全流程负责。触发场景:用户在 ...
- 全局注册驱动:
git config --global merge.ours.driver true(缺这步,.gitattributes里写的merge=ours直接被忽略) -
.gitattributes必须提交到所有相关分支(main、develop、release),不能只放在源分支 - 规则写法要带路径前缀,例如:
config/local.env merge=ours,不是local.env merge=ours - 策略仅在“双方都改了同一文件”时触发:如果
main分支上docker-compose.yml自始至终没动过,而dev改了,git merge dev仍会把dev的版本合进来——merge=ours不起效
为什么有时 merge=ours 像没生效一样
根本原因在于 Git 判定“谁是 ours”的依据是三路合并中的“共同祖先”和“各自最新变更”。它不看分支名,只看文件内容变更链。
- 若
dev分支先改了yarn.lock并提交,main分支之后也提交了一次(哪怕只是加个空行),再执行git merge dev,merge=ours才真正保留main版本 - 反之,如果
main上该文件最后一次提交远早于dev的修改,Git 会认为“dev的版本才是更新的”,直接采用,跳过策略 - CI/CD 流水线里尤其容易踩坑:自动构建生成的
yarn.lock往往没有对应main的“占位提交”,导致保护失效
临时绕过方案:git merge --no-commit + git checkout HEAD
适合单次手动操作或调试,不适合长期维护。
- 先合并但不提交:
git merge --no-commit develop - 恢复指定文件到当前分支状态:
git checkout HEAD -- config/database.yml - 确认暂存区已剔除该文件:
git status应显示它为 “not staged for commit” - 最后
git commit——注意,这个提交里不会包含被恢复的文件变更 - 缺点:无法自动化;每次都要人工干预;
HEAD指向的是合并前的main提交,不是最终合并结果,逻辑上略绕
真正可靠的长期方案只有 .gitattributes + merge=ours,但必须确保目标分支对该文件有独立的、时间上“晚于”源分支的修改记录——这点最容易被忽略,也是多数人配置失败的根源。










