Git 报错 local changes would be overwritten by merge 解决
error: Your local changes to the following files would be overwritten by merge
本地修改了代码后,执行 git pull or git merge wfd_test 命令时,无法更新代码, 并报错提示:Your local changes to the following files would be overwritten by merge
- 方法一
git stash
git pull origin master
git stash pop
- 方法二
git commit -m '本地提交的信息'
为什么 git 要拦住这次合并
Git 的原则是永远不会让你丢掉未提交的改动。合并需要把远端的新内容写进工作区,如果某个文件你本地改过但没提交,写入就会覆盖掉那份改动,而它没有任何记录可以恢复——不像已提交的内容,最差也能从 reflog 找回来。所以 git 宁可整个操作失败也不写。
关键是它只拦冲突的那部分文件:远端改了 a.js,你本地改了 b.js,合并照样能进行。报错列出的一定是「远端要改 + 你也改了 + 你没提交」三个条件同时满足的文件。
这也说明报错本身是保护而不是障碍。解法的本质就一句话:给本地改动找个安身之处(提交或暂存),或者明确表示不要它。
方法一:stash 的细节
git stash 把改动挪到一个独立的栈里,工作区回到干净状态,合并完再取回来。这是最常用的路子,但有几个点要留意。
git stash pop 可能冲突。 因为取回时远端的新内容已经在了,你的改动和它可能撞上。这时会出现冲突标记,需要手工解决。解决完注意 pop 会失败,stash 条目仍然留在栈里(这是好事,防止改动丢失),处理完手动清掉:
git stash pop
# 有冲突 → 手工解决 → git add
git stash drop # 确认无误后再删掉栈里那条
想更安全就用 git stash apply 代替 pop:apply 不会自动删除栈里的记录,确认没问题再 git stash drop。
默认不 stash 未跟踪文件。 新建但没 git add 过的文件不会被 stash 带走,也就不会影响合并(因为 git 不认识它们)。但如果远端新增了同路径的文件,会报另一个错 untracked working tree file would be overwritten。这时要用:
git stash -u # 带上未跟踪文件
git stash -a # 连 .gitignore 忽略的文件也带上(慎用,可能把 node_modules 塞进去)
给 stash 起名字。 栈里攒了好几条之后 WIP on master: xxx 这种默认描述完全分不清:
git stash push -m "登录页表单校验改到一半"
git stash list
# stash@{0}: On feature/login: 登录页表单校验改到一半
git stash show -p stash@{0} # 看这条具体改了什么
git stash apply stash@{0}
只 stash 部分文件:
git stash push -m "只存这两个" src/a.ts src/b.ts
# 交互式挑选要 stash 的片段
git stash push -p
方法二:commit 的取舍
直接提交最简单,但会在历史里留下一个「为了 pull 而做的半成品提交」。改动确实完整的话没问题;只是改到一半,我倾向先提交、pull 完再用 --amend 或者 reset --soft 整理:
git commit -m "wip: 临时提交以便 pull"
git pull --rebase origin master
# 继续写完
git add . && git commit --amend -m "feat: 完整的提交信息"
或者压根不产生这个提交:
git commit -m "wip"
git pull --rebase origin master
git reset --soft HEAD~1 # 撤销提交,改动回到暂存区
reset --soft 只挪 HEAD 指针,暂存区和工作区都不动,正好用来「取消提交但保留内容」。
第三种:确定不要本地改动
想直接丢掉本地改动接受远端版本,注意这几条都是不可恢复的:
# 丢弃指定文件的改动(Git 2.23+ 的写法,语义更清楚)
git restore src/a.ts
# 老写法
git checkout -- src/a.ts
# 丢弃全部已跟踪文件的改动
git restore .
# 连暂存区一起重置,回到 HEAD 的状态
git reset --hard HEAD
# 再清掉未跟踪文件(-n 先预演,看清要删什么再去掉 -n)
git clean -nd
git clean -fd
git clean -fd 是我见过最容易造成实际损失的命令,它会删掉所有未跟踪文件。跑之前一定先用 -n 预演,特别是仓库里有本地配置文件(.env.local 之类)且没进 .gitignore 的时候。
第四种:让 merge 自己带上改动
Git 2.27 之后 git merge 和 git pull 支持 --autostash,把「stash → 合并 → pop」三步合成一步:
git pull --rebase --autostash
觉得好用可以设成默认:
git config --global rebase.autoStash true
git config --global merge.autoStash true
配了之后基本就不会再遇到这个报错了——git 自动帮你 stash,合并完自动恢复。冲突时的处理和手动 stash 一样。这是我现在的默认配置,省掉了大量重复的 stash/pop 操作。
顺带区分两个相似的报错
Your local changes to the following files would be overwritten by checkout:切分支时的同类报错,原因和解法完全一致。
The following untracked working tree files would be overwritten by merge:这个不是已跟踪文件被改,而是远端新增了一个文件,你本地恰好也有个同名的未跟踪文件。stash 默认带不走它(要 -u),最直接的办法是先把本地那个文件改名或挪走:
mv src/newfile.ts src/newfile.ts.bak
git pull
# 然后自己比对两份内容
error: cannot pull with rebase: You have unstaged changes:pull --rebase 特有的措辞,本质同一件事,--autostash 同样能解决。

还没有留言,来发表第一条吧~