01. stash——临时存起来
你正在开发一个功能,代码改了一半还没法 commit,突然要切到另一个分支修紧急 bug——stash 就是干这事的。它把你的改动暂存起来,让工作区变干净,之后随时可以恢复。
git stash——把工作区和暂存区的修改存进 stash 栈,工作区恢复干净。
git stash pop——把最近 stash 的改动恢复到工作区并删除这个 stash。
git stash apply——恢复但不删除 stash(可以反复恢复)。
git stash list——看当前有哪些 stash。
默认 stash 不会保存未跟踪的文件(新文件),加 -u 参数(或 --include-untracked)才保存。加 -a 连被 .gitignore 忽略的文件也保存。
bash
# 临时保存改动
git stash # 快速保存
git stash -u # 包含未跟踪的文件
git stash -m "WIP: login feature" # 起个名
# 查看 stash 列表
git stash list
# 恢复
git stash pop # 恢复最近一个并删除
git stash apply # 恢复但不删除
git stash pop stash@{2} # 恢复指定的 stash
# 删除
git stash drop stash@{0} # 删一个
git stash clear # 删所有stash 是一个栈——后 stash 的在上面。用 git stash list 看编号,stash@{0} 是最新的,stash@{1} 是次新的。
02. reset——撤销 commit
reset 的三个模式区别很大:
--soft——只撤销 commit 本身,改动回到暂存区(就像没 commit 过)。适合「刚才那个 commit 太快了,改一下 message 再 commit」。
--mixed(默认)——撤销 commit + 取消暂存区,改动回到工作区。适合「commit 了不该 commit 的东西,要拆成多个 commit」。
--hard——撤销一切,回到指定状态。工作区和暂存区的改动全丢。适合「这个方向完全错了,从头来过」。但如果你要撤销的 commit 已经 push 了,--hard 之后 push 需要 --force。
git reflog 可以救回误操作的 reset,因为 Git 对 HEAD 的每次移动都有记录(默认保留 90 天)。
bash
# 三种 reset
git reset --soft HEAD~1 # commit 撤回,改动在暂存区
git reset --mixed HEAD~1 # commit 撤回,改动在工作区(未暂存)
git reset --hard HEAD~1 # 全部撤回,改动丢失
# 回到某个特定的 commit
git reset --hard abc1234
# 救回误 reset 的 commit
git reflog # 找到被丢掉的 commit hash
git reset --hard abc1234 # 回到那个状态git reset --hard 之后 push 需要 git push --force。如果别人已经 pull 了你之前的 commit,force push 可能导致他们的仓库出问题。
03. revert——安全的撤销
reset 会改写历史,在共享分支上很危险。revert 是安全的选择——它创建一个新的 commit,这个 commit 的内容是某个旧 commit 的逆操作。历史不改写,只是往前加一个回退 commit。
git revert abc1234 创建一个新 commit,把 abc1234 那次提交的改动全部还原。跟 reset 不同,revert 之后历史上有两条记录:原来的 commit 和还原的 commit。
多人协作的分支上,永远用 revert 而不是 reset。如果你已经 push 了错误 commit,reset + force push 会让别人的仓库出问题,revert 不会。
bash
# 还原某个 commit
git revert abc1234
# 还原但不自动提交(可以先检查或合并)
git revert --no-commit abc1234
# 还原一个 merge commit(需要指定保留哪个父提交)
git revert -m 1 abc1234
# 还原最近几个 commit(从旧到新)
git revert HEAD~3..HEAD在共享分支上(main、develop)出了事用 revert。在自己的 feature 分支上用 reset 没问题,反正只有你一个人在上面。
04. checkout——切换与探索
git checkout 是个多功能命令,能切分支、切 commit、恢复文件(新版 Git 建议用 git switch 切分支,用 git restore 恢复文件,功能拆分更清晰)。
切分支:git checkout feature-branch。切到某个历史 commit:git checkout abc1234(进入 detached HEAD 状态——不挂任何分支上,如果在这里 commit 了容易丢)。
切文件:git checkout -- file.txt 恢复工作区文件到最后一次 commit 的状态。这个操作不可逆,改动的文件直接丢了。
创建并切换到新分支:git checkout -b new-feature。从某个特定 commit 分叉出来:git checkout -b hotfix abc1234。
bash
# 切换分支
git switch main # Git 2.23+ 推荐
# git checkout main # 传统写法
# 创建并切换新分支
git switch -c new-feature # 推荐
git checkout -b new-feature # 传统写法
# 恢复文件
git restore file.txt # 推荐
git checkout -- file.txt # 传统写法
# 切换到某个历史 commit
git checkout abc1234 # detached HEAD
git switch -c repair-branch abc1234 # 基于旧 commit 建新分支Git 2.23+ 引入了 git switch 和 git restore,把 checkout 的多重功能拆分清楚。新手从这两个命令入手更不容易搞混。
05. clean——清除未跟踪的文件
git clean 清除工作区里没被 Git 跟踪的文件和目录(比如编译产物、临时文件)。这个操作非常危险——删掉的文件没经过 Git 管理,没法恢复。
git clean -n——先看看哪些文件会被删(dry run 不真删)。
git clean -f——删除未跟踪的文件(不包括目录)。
git clean -fd——删除未跟踪的文件和目录。
git clean -fdx——连 .gitignore 里忽略的文件也清理。
常见用法:配合 git reset --hard 完全重置工作区——git reset --hard && git clean -fd。把项目恢复到 clone 下来的干净状态。
bash
# 先看看会删什么
git clean -n
# 删除未跟踪的文件
git clean -f
# 删除未跟踪的文件+目录
git clean -fd
# 连 .gitignore 里的文件也删
git clean -fdx
# 完全重置(慎用)
git reset --hard && git clean -fdgit clean -fd 删除的东西永远找不回来。执行前一定先用 -n 看看要删什么,确认没有重要文件。
知识测验
第 1/5 题正确 0
git stash pop 和 git stash apply 的区别?
下一节
下一节 Git 远程协作