Git 切换分支时本地有未提交修改的处理
git 切换分支时,本地有修改的代码
报错如下 error: Your local changes to the following files would be overwritten by checkout:
解决方法
- 第一种
git add.
git stash
取出的时候使用
git stash pop
- 第二种方式 发起一个
commit存到提交历史
git add.
git commit -m "commit message"
(顺带说,git add. 中间要有空格:git add .,不然会报 git: 'add.' is not a git command。)
什么时候能切、什么时候不能切
有个常被误解的点:本地有改动并不一定妨碍切分支。Git 只在「你改的文件」和「两个分支之间有差异的文件」有交集时才拦你。
具体判断:文件 a.js 你改了没提交,如果目标分支上 a.js 和当前分支完全一样,切过去时 git 会把你的改动一起带过去,不报错。只有目标分支上的 a.js 内容不同,切换必须重写这个文件,才会因为可能覆盖你的改动而拒绝。
所以同一份未提交改动,切到 A 分支能成、切到 B 分支报错,这不是 git 抽风。想提前知道会不会冲突:
# 我改了哪些文件
git diff --name-only
# 当前分支和目标分支之间哪些文件有差异
git diff --name-only HEAD target-branch
# 两者的交集就是会阻塞切换的文件
「改动被带过去」这个行为有时候正是你想要的(在错误的分支上开始改代码了,想挪到正确的分支继续),有时候会造成困扰(本来只想切过去看一眼,结果工作区脏了)。
stash 之前不需要先 add
原文写的 git add . + git stash 能用,但 add 这一步是多余的——git stash 默认会把已暂存和未暂存的改动都收走。多做一步 add 的唯一后果是,stash pop 回来时改动会保持「已暂存」状态(因为 stash 记录了 index 的状态),而不是回到「未暂存」。
想精确控制的话:
# 直接 stash 全部改动(不需要 add)
git stash
# 带上未跟踪的新文件
git stash -u
# 只 stash 未暂存的,保留已暂存的内容在 index 里
git stash --keep-index
# pop 时恢复原本的暂存状态
git stash pop --index
--keep-index 有个实用场景:想只提交一部分改动,先 git add 要提交的部分,然后 git stash --keep-index 把其余的收走,跑测试确认这部分单独能过,提交完再 git stash pop。
三条更省事的路子
1. 用 git switch 代替 git checkout。 Git 2.23 引入了 switch(切分支)和 restore(恢复文件),把 checkout 那个身兼两职、语义混乱的命令拆开了:
git switch feature # 切分支
git switch -c feature # 创建并切换(等于 checkout -b)
git switch - # 切回上一个分支
git restore src/a.ts # 丢弃文件改动(等于 checkout -- )
报错信息和行为是一样的,但语义清楚多了,不会出现「本想丢弃文件改动,结果切了分支」这种误操作。
2. 带着改动强行切过去。 确定要把改动一起挪到目标分支,用 -m(merge):
git switch -m feature
# 或
git checkout -m feature
它会做一次三方合并,把你的改动合到目标分支的内容上。有冲突就出冲突标记让你解决。这比「stash → 切 → pop」少一步,效果基本相同。
3. 用 worktree 彻底避开切换。 需要同时看两个分支时,别在一个目录里来回切,直接开第二个工作树:
# 在同级目录创建一个检出 master 的工作树
git worktree add ../project-master master
# 基于当前分支新建分支并检出到新目录
git worktree add -b hotfix/urgent ../project-hotfix
# 看有哪些工作树
git worktree list
# 用完删掉
git worktree remove ../project-hotfix
多个工作树共享同一份 .git 对象库(不占额外磁盘),但各自有独立的工作区和 index。改一半的代码留在原目录不动,去新目录处理紧急 bug,回来接着写。这是我现在处理「写着 feature 突然要修线上 bug」的默认方式,比 stash 可靠——stash 攒多了很容易忘记哪条是哪条。
唯一的代价是新工作树需要单独装 node_modules(不同分支的依赖可能不同,这其实也是好事)。
确定要丢弃改动
# 丢弃指定文件
git restore src/a.ts
# 丢弃全部已跟踪文件的改动
git restore .
# 连暂存区一起回到 HEAD
git reset --hard HEAD
# 强制切换,丢弃当前分支的所有本地改动
git switch -f feature
git checkout -f feature
这几条都不可恢复,跑之前确认一遍 git status。特别是 -f,它会静默丢弃改动,没有任何二次确认。
stash 用久了的管理问题
stash 是个栈,攒到十几条之后基本就分不清了。几个习惯能缓解:
# 一律带描述
git stash push -m "登录页表单校验,写到一半"
# 定期检查
git stash list
git stash show -p stash@{2} # 看具体 diff
git stash show --stat stash@{2} # 只看改了哪些文件
# 把某条 stash 变成分支(适合放太久、基底已经变了的)
git stash branch feature/from-stash stash@{2}
# 清理
git stash drop stash@{2}
git stash clear # 全清,慎用且不可恢复
git stash branch 解决的是「stash 太久,pop 回来一堆冲突」的问题——它会基于 stash 创建时的那个提交新建分支再恢复,冲突自然消失,之后再正常 merge/rebase。
顺带提醒,git stash clear 之后想找回来只能靠 git fsck --unreachable | grep commit 翻孤立对象,很麻烦而且不保证成功。所以别把 stash 当长期存储用——超过一天没处理的改动,要么提交到临时分支,要么就是不需要了。

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