Skip to content

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 statusgit 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 · 分支切换与合并