Git 常用命令速查:从日常开发到救命操作
不是教你学 Git,是帮你在需要的时候快速找到那条命令。收藏这篇,关键时刻能救命。
用了五六年 Git,我常用的命令可能也就二十来个。但每隔几个月总会碰到一次「完了,代码搞丢了」的场景——要么是错误地 reset 了,要么是 rebase 冲突搞炸了。每次都要现查 Stack Overflow,查到的答案还经常过时。所以我把这些年真正用过的命令整理了一份,按场景分类,以后再遇到直接翻这篇就行。
说真的,Git 的命令行设计是我见过最反直觉的工具之一。checkout 一个命令又能切分支又能恢复文件,reset 的 --soft/--mixed/--hard 三个选项每次都要查一遍。好在 Git 2.23 之后出了 switch 和 restore,终于把职责分清了。但老项目的文档和 CI 脚本里全是 checkout,迁移成本太高,只能继续忍着。
1. 日常开发:每天都在用的命令
分支操作
# 创建并切换到新分支(推荐用 switch)
git switch -c feature/login
# 等价于旧写法:git checkout -b feature/login
# 切换到已有分支
git switch main
# 查看所有分支(含远程)
git branch -a
# 删除已合并的本地分支
git branch -d feature/login
# 强制删除未合并的分支(慎用)
git branch -D feature/experimental
# 重命名当前分支
git branch -m new-name提交与暂存
# 查看工作区状态
git status
# 添加指定文件到暂存区
git add src/login.vue src/auth.ts
# 添加所有修改(不包括新文件和删除)
git add -u
# 交互式选择要暂存的代码块
git add -p
# 提交
git commit -m "feat: add login page"
# 修改最近一次 commit 的信息(未 push 时)
git commit --amend -m "feat: add login page with validation"
# 追加文件到上一次 commit(不改 message)
git add forgotten-file.ts
git commit --amend --no-edit拉取与推送
# 拉取远程更新并合并
git pull
# 拉取但用 rebase 代替 merge(更干净的历史)
git pull --rebase
# 推送当前分支到远程
git push
# 首次推送新分支到远程
git push -u origin feature/login
# 强制推送(覆盖远程历史,团队协作慎用!)
git push --force-with-lease
# 比 --force 安全:如果远程有别人的新提交会拒绝2. Stash:临时保存工作现场
正在写代码,突然被叫去修个紧急 bug。手上的改动还不想提交,又不能丢——这就是 stash 的用武之地。
# 保存当前工作区的修改
git stash
# 带描述信息保存(推荐,方便找回)
git stash push -m "login page WIP - form validation"
# 包括未跟踪的新文件
git stash push -u -m "include new files"
# 查看所有 stash
git stash list
# stash@{0}: On feature/login: login page WIP - form validation
# stash@{1}: On main: hotfix experiment
# 恢复最近的 stash(并删除)
git stash pop
# 恢复指定的 stash(不删除)
git stash apply stash@{1}
# 删除指定 stash
git stash drop stash@{1}
# 清空所有 stash
git stash clear经验之谈:永远给 stash 加描述信息。不然过两天 git stash list 一看,全是 "WIP on main: abc1234",根本分不清哪个是什么。
3. 历史查看:谁改了什么、什么时候改的
# 查看提交历史(简洁模式)
git log --oneline
# 查看某个文件的修改历史
git log --oneline -- src/login.vue
# 漂亮的分支图
git log --oneline --graph --all
# 查看某次提交改了什么
git show abc1234
# 查看某个文件是谁在哪次提交改的(逐行追溯)
git blame src/login.vue
# 只看某几行的修改历史
git blame -L 10,20 src/login.vue
# 搜索 commit message
git log --grep="login"
# 搜索代码变更内容(谁引入/删除了这行代码)
git log -S "localStorage.getItem" --oneline
# 查看两个分支的差异
git diff main..feature/login
# 查看暂存区和最新 commit 的差异
git diff --cached4. 撤销与回退:改错了怎么办
这大概是 Git 最让人困惑的部分了。不同的场景需要不同的撤销方式:
场景 1:修改了文件,还没 add
# 恢复单个文件到最近一次 commit 的状态
git restore src/login.vue
# 恢复所有文件
git restore .场景 2:已经 add,还没 commit
# 从暂存区撤出(文件修改保留)
git restore --staged src/login.vue
# 撤出所有
git restore --staged .场景 3:已经 commit,还没 push
# 撤销 commit,代码改动保留在工作区
git reset --soft HEAD~1
# 撤销 commit,代码改动保留但取消暂存
git reset --mixed HEAD~1 # 默认行为
# 撤销 commit,代码改动也丢弃(危险!)
git reset --hard HEAD~1场景 4:已经 push 到远程
# 创建一个「反向 commit」来撤销(安全,不改历史)
git revert abc1234
# 撤销最近一次 commit
git revert HEAD
# 撤销一段连续的 commits
git revert HEAD~3..HEADreset 三种模式对比:
| 模式 | HEAD | 暂存区 | 工作区 |
|---|---|---|---|
| --soft | 回退 | 保留 | 保留 |
| --mixed | 回退 | 清除 | 保留 |
| --hard | 回退 | 清除 | 清除 |
5. 救命操作:代码「丢了」别慌
在 Git 里,只要 commit 过,数据几乎不可能真正丢失。即使 reset --hard 了,也有办法找回来。
reflog:Git 的「后悔药」
# 查看所有 HEAD 的移动记录(包括被 reset 掉的 commit)
git reflog
# 输出类似:
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: feat: add payment module
# ghi9012 HEAD@{2}: commit: fix: order calculation
# 找到那个被误删的 commit hash,恢复到那里
git reset --hard def5678
# 或者更安全地,把它捡回来创建新分支
git switch -c recover-branch def5678cherry-pick:从别的分支「偷」一个 commit
# 把某个 commit 应用到当前分支
git cherry-pick abc1234
# 一次 pick 多个
git cherry-pick abc1234 def5678
# 只应用改动,不自动 commit
git cherry-pick --no-commit abc1234记住这个原则:在 Git 中,只要你 commit 过,数据在 30 天内(默认 gc 周期)都可以通过 reflog 找回来。所以养成勤 commit 的习惯,哪怕是半成品代码也先 commit,以后再用 rebase squash 合并。
6. 合并与变基:merge vs rebase
git merge
# 将 feature 分支合并到 main
git switch main
git merge feature/login保留完整的分支历史,会产生一个 merge commit。适合公共分支(main/develop)的合并。
git rebase
# 将 feature 的 commit 搬到 main 最新位置上
git switch feature/login
git rebase main重写提交历史,让 commit 看起来像是在最新代码上连续开发的。历史更干净,但不要对已 push 的 commit 做 rebase。
解决冲突
# 冲突时,Git 会在文件中标记冲突区域:
# <<<<<<< HEAD
# 你的改动
# =======
# 别人的改动
# >>>>>>> feature/other
# 手动解决后:
git add resolved-file.ts
git merge --continue # 或 git rebase --continue
# 不想合了,放弃
git merge --abort # 或 git rebase --abort7. 实用小技巧
设置常用别名
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --all"
# 之后 git lg 就能看到漂亮的分支图清理已合并的远程分支
# 清理本地缓存的已删除远程分支
git fetch --prune
# 查看已合并到 main 的本地分支
git branch --merged main
# 批量删除已合并的分支(排除 main 和当前分支)
git branch --merged main | grep -v "main\|*" | xargs git branch -d用 bisect 定位引入 bug 的 commit
# 启动二分查找
git bisect start
git bisect bad # 当前版本有 bug
git bisect good v1.0.0 # 这个版本没有 bug
# Git 会自动切换到中间的 commit
# 你测试后标记好坏:
git bisect good # 或 git bisect bad
# 几轮后 Git 就能定位到第一个引入 bug 的 commit
# 结束
git bisect reset相关阅读
想深入了解 Git 工作流和团队协作规范?推荐阅读我们的另一篇文章:Git 工作流最佳实践:从 commit 规范到分支策略,涵盖 Conventional Commits、分支策略对比和 rebase 实战。