外观
04 · 查看状态、差异与历史
这一章全是只读(bisect 会在仓库里来回切换提交,但不改写历史)。先查清楚再动手改,是避免误操作的最快方法。
git diff
作用: 比较两个快照之间的差异。
改动范围: 只读。
典型场景:
- 提交前看自己改了什么。
- 比较暂存区和 HEAD,确认这次 commit 的内容。
- 看功能分支相对
main到底改了哪些文件。
常用写法:
bash
git diff # 工作区 vs 暂存区(还没 add 的)
git diff --staged # 暂存区 vs HEAD(即将 commit 的)
git diff HEAD # 工作区+暂存区 vs HEAD(所有未提交)
git diff main # 当前工作区 vs main 尖端
git diff main...HEAD # 两边分叉以来,当前分支的独有改动(看 PR 常用)
git diff main feature/login # 两个分支尖端直接比
git diff -- src/login.ts # 只看某路径A...B(三个点)和 A..B(两个点)不一样:
A..B:从 A 到 B 的对称差,容易把两边都算进去。A...B:从分叉点到 B,适合「这个分支引入了什么」。
不要这样用: 工作区很脏时用 diff 结果去决定 reset --hard。先 stash 或确认没有未跟踪文件。
做错了怎么办: 只读,无。看不懂某个文件为何出现在 diff 里,用 git status 和 git log -- path。
git log
作用: 按时间(默认)浏览提交历史。
改动范围: 只读。
典型场景: 找某次提交的 SHA、看分支分叉、审查某文件是谁改的时间线、给别人贴一段历史。
常用写法:
bash
git log
git log --oneline --graph --decorate --all
git log -20 # 最近 20 条
git log -p # 带补丁
git log -- src/login.ts # 只跟这个文件有关的提交
git log --author="Zhang" --since="2.weeks"
git log main..feature/login # 在 feature 上、不在 main 上的提交
git log --grep="登录" # 提交说明里搜建议配别名(见 01 章):
bash
git config --global alias.lg "log --oneline --graph --decorate --all"不要这样用: 把 log 里的远程分支名当成可以 reset --hard 过去的「回收站」。origin/main 是上次 fetch 的位置,先 fetch 再看。
做错了怎么办: 只读。历史「少了」通常是浅克隆或看的分支不对:git fetch --unshallow 或加 --all。
git show
作用: 展示一个对象:默认是某次提交的说明 + 完整 diff;也可以是 tag、blob。
改动范围: 只读。
典型场景: 打开某次 commit 看它到底改了啥;看某个 tag 指到哪。
bash
git show
git show a1b2c3d
git show a1b2c3d --stat
git show v1.2.0
git show HEAD:src/login.ts # 打印该提交里文件的完整内容做错了怎么办: 只读。
git blame
作用: 逐行标注「当前这行最后是哪次提交、谁、什么时候改的」。
改动范围: 只读。
典型场景: 这行奇怪的判断是谁加的;线上报错定位到源码行,要找上下文提交。
bash
git blame src/login.ts
git blame -L 40,80 src/login.ts
git blame -w src/login.ts # 忽略仅空白变化blame 看的是当前文件内容的谱系,不是「谁写了第一版」。某行如果被格式化工具整行重写,作者会变成格式化那次提交。
从某次 blame 点进完整改动:复制 SHA,git show <sha>。
git grep
作用: 在 Git 跟踪的文件里搜字符串,比在 node_modules 上跑系统 grep 干净。
改动范围: 只读。
bash
git grep -n "TODO"
git grep -n "createUser" main
git grep -n -e "password" -- "*.ts"git shortlog
作用: 按作者汇总提交说明,适合写 changelog 或看一段时间谁提交多。
bash
git shortlog -sn --since="1.month"git bisect
作用: 用二分法在历史里定位「哪一次提交引入了问题」。Git 负责跳到中间提交,你负责告诉它好还是坏。
改动范围: 会切换 HEAD(detached)。不改写提交。结束后应回到原分支。
典型场景: 上周还好、今天坏了,中间几十个提交,不想一个个 checkout。
bash
git bisect start
git bisect bad # 当前就是坏的
git bisect good v1.2.0 # 某个已知好的点(tag 或 sha)
# Git 会 checkout 中间提交。你编译/测试后:
git bisect good # 或 git bisect bad
# 重复,直到它打印出第一颗坏提交
git bisect reset # 回到 bisect 之前的分支自动化(测试命令退出码 0 = good,非 0 = bad):
bash
git bisect start HEAD v1.2.0
git bisect run npm test不要这样用: bisect 到一半工作区有未提交改动还继续 switch。开始前先 commit 或 stash。
做错了怎么办: 任何时候:
bash
git bisect reset若停在 detached HEAD,git switch main 即可。中间产生的临时状态不要拿去 commit --amend。
上一章:03 · 日常提交 · 下一章:05 · 分支切换与合并