一、提交(Commit)
提交的本质:把暂存区的内容固化为仓库中的一个快照。掌握下面几条即可覆盖 99% 的提交场景。
1.1 暂存与提交
bash
git add hello.py # 暂存单个文件
git add . # 暂存当前目录全部改动
git add -p # 交互式按块暂存(精细控制提交内容)
git commit -m "feat: 添加 hello 示例" # 带信息提交
git commit -a -m "fix: 修复 bug" # 跳过 git add,直接提交所有【已跟踪】文件的改动
注意 :
git commit -a只对已经被 Git 跟踪的文件生效,新建文件仍需先git add。
1.2 修正最近一次提交
bash
# 场景:提交信息写错了,或漏提交了一个文件
git commit --amend -m "feat: 添加 hello 示例(修正版)"
# 只想补文件、不改提交信息
git add 漏掉的文件.py
git commit --amend --no-edit
| 命令 | 作用 | 注意 |
|---|---|---|
git commit -m "msg" |
提交暂存区 | 最常用 |
git commit -a |
跳过暂存直接提交已跟踪文件 | 不含新建文件 |
git commit --amend |
重写最近一次提交 | 已推送后慎用(会改写历史) |
git commit --amend --no-edit |
补文件但保留原提交信息 | 同上 |
二、查看日志(Log)
2.1 日常查看
bash
git log # 完整日志
git log --oneline # 每行一条,只看哈希与标题(最常用)
git log -5 # 只看最近 5 条
git log --graph --all # 图形化展示所有分支的提交网络
2.2 检索与过滤
bash
git log --author="zhang" # 按作者过滤
git log --since="2026-01-01" # 指定时间之后
git log --until="2026-06-30" # 指定时间之前
git log --grep="fix" # 提交信息包含 fix
git log --oneline -- file.py # 只看某个文件的提交历史
2.3 查看提交内容
bash
git log -p # 显示每次提交的代码差异
git log --stat # 显示每次提交改动的文件与行数统计
git show a1b2c3d # 查看某次提交的完整详情
git show HEAD # 查看最近一次提交的详情
2.4 reflog:查看一切操作
bash
git reflog
# 记录了 HEAD 每一次移动的历史,包括被 reset 掉的提交
reflog是找回误删提交的救命稻草,详见第三节。
三、版本回退(Reset & Revert)
3.1 reset 的三种模式
git reset 移动 HEAD 指针并附带不同的"清理"动作,三种模式区别在于动哪一层:
flowchart LR
HEAD -->|"--soft<br/>只动指针"| 暂存区
HEAD -->|"--mixed(默认)<br/>指针 + 清暂存区"| 暂存区
HEAD -->|"--hard<br/>指针 + 清暂存区 + 还原工作区"| 工作区
bash
git reset --soft HEAD~1 # 撤销提交,改动保留在暂存区
git reset --mixed HEAD~1 # 撤销提交并清空暂存区,改动保留在工作区
git reset --hard HEAD~1 # 彻底回退,工作区改动一并丢弃(危险!)
| 模式 | HEAD 移动 | 暂存区 | 工作区 | 适用场景 |
|---|---|---|---|---|
--soft |
是 | 保留 | 保留 | 提交错了但想保留改动重新提交 |
--mixed(默认) |
是 | 清空 | 保留 | 想撤销提交并重新挑选文件 |
--hard |
是 | 清空 | 还原 | 彻底放弃改动(慎用) |
常用位置写法:
bash
git reset --hard HEAD # 丢弃工作区所有未提交改动(回到最近提交)
git reset --hard HEAD~2 # 回退到上上个提交
git reset --hard a1b2c3d # 回退到指定提交
3.2 revert:安全的"反向提交"
reset 会改写历史,若提交已推送到远程,应改用 revert------它生成一个新的提交来抵消旧提交的改动,历史完整保留:
bash
git revert a1b2c3d # 生成一个新提交,撤销 a1b2c3d 的改动
git revert --no-commit a1b2c3d # 先不提交,合并多次撤销后统一提交
| 场景 | 用 reset | 用 revert |
|---|---|---|
| 提交未推送 | ✅ 推荐 | 可用 |
| 提交已推送 | ❌ 会破坏他人历史 | ✅ 唯一安全选择 |
| 撤销多个连续提交 | reset --hard <目标> |
逐个 revert |
3.3 误操作找回
即使执行了 git reset --hard,只要提交还在 reflog 里就能找回:
bash
git reflog
# a1b2c3d HEAD@{2}: commit: feat: 添加 hello 示例
git reset --hard a1b2c3d # 回到误删前的提交
四、文件撤销(Restore)
Git 2.23+ 推荐用 git restore 取代旧式 git checkout --,职责更清晰。
4.1 撤销工作区改动
bash
git restore hello.py # 丢弃工作区改动,还原到暂存区/HEAD 版本
git restore . # 还原当前目录所有文件
4.2 撤销暂存
bash
git restore --staged hello.py # 把文件移出暂存区(内容不变,回到 Modified)
git restore --staged . # 取消全部暂存
4.3 还原到历史版本
bash
git restore --source=a1b2c3d hello.py # 把 hello.py 还原成某次提交时的样子
git restore --source=HEAD~1 hello.py # 还原成上一版
4.4 其他相关命令
bash
git rm hello.py # 删除文件并暂存删除动作
git rm --cached hello.py # 停止跟踪,但保留本地文件(配合 .gitignore 使用)
git clean -fd # 删除所有未跟踪文件(危险,不可找回)
4.5 撤销场景对照表
| 想撤销什么 | 命令 |
|---|---|
| 工作区改动(未暂存) | git restore <file> |
| 暂存区改动(未提交) | git restore --staged <file> |
| 已提交、未推送 | git reset --soft/mixed HEAD~1 |
| 已提交、已推送 | git revert <commit> |
| 文件还原到上一版 | git restore --source=HEAD~1 <file> |
| 误删文件未提交 | git restore <file> |
| 删除后想停止跟踪 | git rm --cached <file> |
| 清理未跟踪垃圾文件 | git clean -fd(危险) |
五、场景速查表
| 场景 | 一条命令搞定 |
|---|---|
| 提交信息写错了 | git commit --amend -m "新信息" |
| 提交后发现漏了文件 | git add 文件 && git commit --amend --no-edit |
| 提交错了,还没推送 | git reset --soft HEAD~1 重新提交 |
| 提交错了,已推送 | git revert <commit> 再推送 |
| 想彻底放弃本地改动 | git reset --hard HEAD |
| 想找回误删的提交 | git reflog + git reset --hard <hash> |
| 某文件被改乱了 | git restore <file> |
| 想取消暂存 | git restore --staged <file> |
| 想对比工作区与暂存区 | git diff |
| 想对比暂存区与仓库 | git diff --cached |
六、危险命令警示
以下命令会丢失改动且难以找回,执行前务必确认:
| 危险命令 | 后果 |
|---|---|
git reset --hard <commit> |
丢弃工作区全部未提交改动 |
git clean -fd |
删除所有未跟踪文件,不可恢复 |
git push --force |
强制覆盖远程历史,可能破坏他人工作 |
git commit --amend(已推送后) |
改写已共享的提交历史 |
安全习惯:执行危险操作前先 git stash 或复制一份目录;用 git status 确认状态后再动手。
七、总结
- 提交 :
add暂存 →commit固化,--amend修最近一次提交; - 日志 :
git log --oneline日常够用,git reflog是后悔药; - 回退 :未推送用
reset(soft/mixed/hard 按需选择),已推送用revert; - 撤销 :工作区
git restore,暂存区git restore --staged,历史版本--source。
记住一条主线:改动越靠后,撤销成本越高------工作区的改动一条命令可还原,已推送的历史则要慎重对待。