前置知识: Git

GitHub 历史与日志

4 min入门

以侦探查案驱动方式讲解 git log 的各类查看姿势与 git diff、git show、git blame、git reflog 的取证技巧,覆盖历史筛选、差异对比与引用日志,适合零基础学习者。

开篇:像侦探查案一样翻阅历史

想象你是一名侦探,接手一桩”代码失踪案”:昨晚还能运行的程序,今天早上突然崩溃了。你需要回答三个问题:

  1. 什么时候改的?(哪一次提交让程序变坏的)
  2. 谁改的?(哪个同事的哪次操作)
  3. 改成什么样了?(具体是哪几行代码出了问题)

Git 的提交历史就是你的”案卷库”,而 git log 就是你的”查档系统”。Git 官方甚至把仓库描述为”内容寻址文件系统”——每次提交都是一个不可变的快照,你可以像翻档案一样回到任何一天。

本篇采用侦探驱动的叙事方式:以”破案”为线索,依次学习看总览(log)、筛线索(filter)、对现场(diff)、看单份案卷(show)、追查每行来源(blame)、翻查活动记录(reflog) 六种取证姿势。


一、第一招:看总览——git log 基础

1.1 完整案卷

# 查看完整提交历史(按时间倒序)
git log

输出示例:

commit 8f4b2c1e2d3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c
Author: 张三 <zhangsan@example.com>
Date:   Sat Aug 2 09:30:00 2026 +0800

    feat: 添加加法函数

每条提交包含:提交 ID(完整 SHA-1 哈希)、作者、日期、提交信息。

1.2 精简案卷

# 每条提交一行(最常用,一眼扫过全部历史)
git log --oneline
# 输出示例:
# 8f4b2c1 (HEAD -> main) feat: 添加加法函数
# a1b2c3d docs: 更新 README

# 只看最近 N 条
git log -5

# 单行 + 数量
git log -5 --oneline

1.3 画关系图

# 图形化显示分支合并历史(能看到 merge 的分叉与交汇)
git log --graph

# 最常用的组合:单行 + 图形 + 所有分支
git log --oneline --graph --all

# 只看合并提交
git log --merges

# 排除合并提交
git log --no-merges

git log --oneline --graph --all 输出示例:

* 8f4b2c1 (HEAD -> main) feat: 添加加法函数
* a1b2c3d docs: 更新 README
|\
| * e4f5g6h (feature) feat: 登录功能
|/
* 7a3f9c1 chore: 项目初始化

二、第二招:筛线索——git log 过滤参数

2.1 按作者筛选

# 查看指定作者的提交
git log --author="zhangsan"

# 模糊匹配(支持正则)
git log --author="zhang"

2.2 按提交信息搜索

# 搜索提交信息中包含"登录"的提交
git log --grep="登录"

# 不区分大小写
git log --grep="login" -i

2.3 按日期筛选

# 指定日期范围
git log --since="2026-01-01" --until="2026-07-31"

# 相对时间(最近 2 周)
git log --since="2 weeks ago"

# 等价写法:--after / --before
git log --after="2026-06-01" --before="2026-06-30"

2.4 按文件筛选

# 查看指定文件的提交历史(注意 -- 分隔)
git log -- src/index.js

# 查看指定目录的历史
git log -- src/

# 跟踪文件重命名前的历史
git log --follow src/index.js

2.5 按代码内容筛选(Pickaxe 挖掘)

# 找出"添加或删除过某段代码"的提交(-S 是次数变化)
git log -S "console.log"

# 按正则匹配行变化(-G 是行匹配)
git log -G "function\s+login"

2.6 提交范围筛选(双点语法)

# 在 feature 但不在 main 的提交(feature 独有提交)
git log main..feature

# 本地比远程多的提交(push 前检查)
git log origin/main..HEAD

三、第三招:对现场——git diff 差异对比

diff 是”案发现场对比”:同一个文件在提交前后差了什么。

# 工作区与暂存区的差异(还没 add 的改动)
git diff

# 暂存区与上次提交的差异(已 add 未 commit 的改动)
git diff --staged

# 工作区与上次提交的所有差异(add 没 add 都算)
git diff HEAD

# 指定文件
git diff src/index.js

# 两个提交之间
git diff abc1234 def5678

# 两个分支之间
git diff main..feature

# 三点比较:feature 相对两分支共同祖先的差异(更聚焦)
git diff main...feature

# 只看文件名
git diff --name-only

# 看改动统计
git diff --stat

git diff --stat 输出示例:

 src/index.js | 10 +++++-----
 README.md    |  2 +-
 2 files changed, 8 insertions(+), 4 deletions(-)

四、第四招:看单份案卷——git show

# 查看指定提交的详情和改动
git show abc1234

# 只看提交改动的文件列表
git show --stat abc1234

# 查看指定提交中某文件的内容(取证"这个版本里这个文件长什么样")
git show abc1234:src/index.js

# 查看最近一次提交
git show HEAD

# 查看倒数第二次提交
git show HEAD~1

git show HEAD 输出结构:提交元信息 + 改动 diff。


五、第五招:追查每行来源——git blame

“这行代码到底是谁写的?“——git blame 就是干这个的,它能告诉你文件每一行最后一次被谁、在哪个提交、什么时候修改:

# 显示文件每行的最后修改者
git blame src/index.js

# 只看 10 到 20 行(定位嫌疑区间)
git blame -L 10,20 src/index.js

# 忽略纯空格改动(避免把格式化也算作"修改者")
git blame -w src/index.js

git blame 输出示例:

8f4b2c1 (张三 2026-08-02 09:30:00 +0800  1) function add(a, b) {
a1b2c3d (李四 2026-07-25 14:20:00 +0800  2)   return a + b;

六、第六招:翻活动记录——git reflog(时光机)

git log 只记录提交历史,而 git reflog 记录你所有的操作足迹——包括 reset、checkout、rebase、merge 这些”移动指针”的动作。它是找回”丢失提交”的最后防线:

# 查看 HEAD 的所有操作历史
git reflog

输出示例:

8f4b2c1 (HEAD -> main) HEAD@{0}: commit: feat: 添加加法函数
7a3f9c1 HEAD@{1}: reset: moving to HEAD~1
a1b2c3d HEAD@{2}: commit: docs: 更新 README
9fceb02 HEAD@{3}: checkout: moving from feature to main
# 查看指定分支的引用日志
git reflog feature

# 查看所有引用日志
git reflog --all

# 用 reflog 找回误删的提交(reset 之后救命的操作)
git reset --hard HEAD@{2}

# 查看 reflog 中第 N 个状态的提交内容
git show HEAD@{3}

原理与警告:reflog 是 Git 的”本地保险丝”——只要操作发生在本地,它就留有足迹。但 reflog 不会推送到远程,且仓库 GC(垃圾回收)后会过期清理(默认 90 天)。所以”误删提交后的急救”要趁早。

6.1 自定义输出格式(让案卷按你的口味排版)

git log 支持用 --pretty=format: 自定义每条提交的排版,适合写进别名长期使用:

# 自定义格式:哈希 + 分支标记 + 作者 + 相对时间 + 提交信息
git log --pretty=format:'%h %d %an %ar %s'

# 美化版(带颜色):
git log --pretty=format:'%Cred%h%Creset - %C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --graph

# 配置成别名(一劳永逸)
git config --global alias.lg "log --oneline --graph --all --decorate"
git lg

常用格式占位符速查:%h 短哈希、%an 作者名、%ae 作者邮箱、%ar 相对时间、%s 提交信息、%d 引用名(分支/标签)、%Cred/%Cgreen 颜色控制。

6.2 提交范围语法补充(双点与三点)

# 双点 A..B:在 B 但不在 A 的提交(B 独有)
git log main..feature

# 三点 A...B:A 和 B 各自独有的提交(对称差)
git log main...feature

# 结合 --left-right 显示每行属于哪一边
git log --left-right --oneline main...feature

--left-right 输出中 < 表示属于左边分支(main),> 表示属于右边分支(feature),方便一眼看清两边的分叉内容。


七、常见错误与对策表

错误现象报错信息(节选)原因分析解决办法
查文件历史没结果git log <文件> 输出为空路径写错,或未用 -- 分隔(与分支名歧义)用 git log -- <路径> 明确是路径
log 输出太长刷屏看不到重点默认输出全部历史用 --oneline、-10 等参数限制
diff 无输出git diff 什么都没显示改动已全部暂存(diff 默认只看工作区)改用 git diff --staged 或 git diff HEAD
blame 显示不了fatal: no such path文件路径不在当前提交中确认文件存在;旧文件用 git blame <提交ID> -- <路径>
误 reset 后提交”消失”git log 找不到那个提交指针移走了,但提交对象还在用 git reflog 找到原 ID,git reset --hard <ID> 找回
reflog 里找不到记录想找的记录不在了超过 90 天或仓库 GC 过无解;养成”危险操作前先备份分支”的习惯
想查删除文件的历史git log -- <删除文件> 没反应默认不追踪删除用 git log --all --diff-filter=D -- <路径> 或先定位删除提交

九、一句话记忆

查历史像破案:git log 看总览(—oneline 精简、—graph 画图),--author/--since/-S 筛线索,git diff 对现场,git show 看单份案卷,git blame 追每行来源,git reflog 是最后保险丝——误删别慌,reflog 里找回来。