← 全部笔记

Git 里那些每次都要现查的命令

2026-10-09 工具与效率 约 5 分钟

不是速查表,是我自己每周都会用错一遍的那几个。每条后面附一句「什么时候不该用」, 因为大部分事故不是不会用,而是用错了场合。

撤销:先搞清楚要撤哪一层

三层要分清:工作区(改过的文件)、暂存区(add 过的)、提交历史。撤错了层,就变成另一种事故。

# 撤工作区:放弃某个文件的修改,恢复成上次提交的样子
git restore path/to/file

# 撤暂存区:取消 add,但保留改动
git restore --staged path/to/file

# 两者一起来:取消 add 并丢弃修改
git restore --staged --worktree path/to/file

老版本 Git 里对应的是 git checkout -- <file> 和 git reset HEAD <file>,还能用,但 restore 语义更清楚,不容易手滑。

git restore 丢弃的改动找不回来。如果那个文件只是还没提交,先用 git stash,别直接 restore。

reset 的三个档位

这是最容易记混的一组,区别只在「动到哪一层」:

命令 HEAD 暂存区 工作区
--soft 回退 保留 保留
--mixed(默认) 回退 清空 保留
--hard 回退 清空 清空

想把最近两个提交合成一个重写:git reset --soft HEAD~2,改动会全留在暂存区,重新 commit 一次即可。 这是最安全的「改写历史」方式。

--hard 只在确认没有未推送的价值时用。已经推到远端的提交不要 reset 后强推——别人拉到之后再 rebase 会一团乱,那种情况应该用 revert。

revert:公开分支上唯一正确的撤销方式

# 生成一个反向提交,历史不变,安全
git revert <commit>

# 撤销一个合并提交,必须指定保留哪一边
git revert -m 1 <merge-commit>

-m 1 的意思是「以第一父提交为主线」,也就是保留合并进来的分支内容、撤销这次合并本身。这个参数不写会直接报错,很多人卡在这。

reflog:救命的那个

误 reset、误删分支、rebase 搞砸——只要提交过,就还在 reflog 里。默认保留 90 天。

git reflog
# 找到那个 SHA,然后
git reset --hard <sha>
# 或者把删掉的分支捡回来
git branch recover-branch <sha>

注意:从没 commit 过的改动 reflog 里没有。这也是为什么我习惯先在草稿分支上 commit 一次,哪怕是很丑的 WIP。

stash:不止是暂存

git stash -u              # 连未跟踪的新文件一起存
git stash list
git stash show -p stash@{0}
git stash pop             # 取出并删除记录
git stash apply stash@{0} # 取出但保留记录(更安全)

-u 很关键。默认 stash 不含新建文件,切分支后发现「新写的文件不见了」,多半就是漏了这个参数。

cherry-pick:把某个提交搬到当前分支

git cherry-pick <sha>
git cherry-pick <sha1>^..<sha2>   # 一段连续提交

适合「修 bug 的提交要同时进两个分支」。不适合拿它做常规合并——用得多了,说明分支策略有问题。

三个我定下的使用纪律

  1. 共享分支只用 revert,私有分支随便 reset。判断标准是有没有别人拉过。
  2. 强推前先看远端有没有新提交:git fetch && git log --oneline HEAD..@{u},非空就别推。
  3. rebase 只在自己分支上做,做之前先 git branch backup-xxx 留个后路,出问题直接 reset 回去。

这份笔记的目的不是背命令,是减少「手比脑子快」造成的损失。真正救命的其实只有两个: git reflog 和 git stash -u。