用 log、show 和 diff 查看 Git 历史记录


假设你周一早上打开 weather-app,却完全想不起来周五到底提交了什么。或者同事问你上周为什么改了温度换算逻辑,而你想给出真实的答案,而不是猜测。The commit loop 讲过一次提交是怎么保存下来的。这一章讲的是如何反过来读取这些历史:发生了什么、是谁做的、什么时候做的。用来做这件事的命令是 git log,下面是它在一个小项目上打印出的全部内容:
$ git log
commit 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c
Author: Priya Nair <[email protected]m>
Date: Tue Jul 14 09:12:03 2026 +0100
Fix temperature conversion in Celsius-to-Fahrenheit formula
commit 5f3d8b21a90e7c6d5b4a3f2e1d0c9b8a7f6e5d4c
Author: Kwame Boateng <[email protected]m>
Date: Mon Jul 13 16:45:22 2026 +0100
Add five-day forecast to the dashboard
commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
Author: Kwame Boateng <[email protected]m>
Date: Mon Jul 13 11:03:47 2026 +0100
Set up project structure只用一个命令,项目的整段故事就摆在你面前了:三次提交,最新的排在最前面,每一条都写清了作者、时间和改动原因。
用 git log 读历史
git log 会从你当前所在的位置开始,沿着能追溯到的每一次提交往回走,最新的排在最前面。每一条记录都展示四样东西:哈希值(标识这次提交的一长串字母和数字)、作者、日期,以及作者写的提交信息。
commit(提交) 就是把这四样东西打包在一起:那一刻所有被跟踪文件的快照、描述改动的信息、改动者是谁,以及指向上一次提交的链接,也就是这次提交的父提交(parent commit)。正是这个指向父提交的链接,把一堆孤立的快照串成了一条真正的时间线。从上往下读 git log,其实就是在倒着读这条时间线,从现在读到最初。
哈希值乍一看挺吓人,但你几乎用不到完整的那一长串。4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c 和 4f2a1c9 指向的是同一次提交。Git 只需要哈希值中足够区分它和仓库里其他提交的那一部分,通常前七八个字符就够了。你会在各处见到这种短格式,本章后面的命令也都会用它。
git log 会列出每一次提交,最新的在最前面,附带哈希值、作者、日期和提交信息。一次提交就是那个快照,加上提交信息,再加上一条指向上一次提交的链接。你几乎用不到完整的哈希值,前面几个字符就足够让 Git 准确知道你说的是哪次提交了。 用 git show 查看单个提交
git log 告诉你有一次提交发生了。git show <hash> 告诉你它到底做了什么:
$ git show 4f2a1c9
commit 4f2a1c9d8e7b6a5c4d3e2f1a0b9c8d7e6f5a4b3c
Author: Priya Nair <[email protected]m>
Date: Tue Jul 14 09:12:03 2026 +0100
Fix temperature conversion in Celsius-to-Fahrenheit formula
diff --git a/src/index.js b/src/index.js
index 3f2c1a9..7b8e2d4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,7 +12,7 @@ function celsiusToFahrenheit(celsius) {
- return celsius * (9 / 5 + 32)
+ return (celsius * 9) / 5 + 32上半部分和 git log 展示的元信息一样。下面才是真正的改动:以 - 开头的行是这次提交删掉的行,以 + 开头的行是新增的行,没有标记的行是保持不变的上下文。这里能看得很清楚:旧的那一行把 32 也算在括号里,导致 32 在乘法运算之前就被加进去了。修复的方式是把括号重新围在 celsius * 9 外面,让 32 最后才被加上,这正是 Priya 提交信息里说的运算符优先级问题。
git show <hash> 完整展示一次提交:谁做的、什么时候做的,以及具体改动了哪些行。删除的行以减号开头,新增的行以加号开头。这是回答"这次提交到底做了什么"最快的方式。 git diff 展示的内容,以及几乎所有人都会踩的坑
git log 和 git show 读取的是已经提交的历史。git diff 读取的是还没提交的内容:也就是当前工作目录里的改动,和你上一次提交相比的结果。
$ git diff
diff --git a/README.md b/README.md
index 1c2d3e4..9f8a7b6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
# weather-app
+A five-day weather dashboard built with vanilla JavaScript.这就是你对 README.md 做的改动,在你还没有 stage 或提交之前展示出来。接下来这部分几乎会让每个人在入门第一周就踩坑:运行 git add . 把这个改动 stage 起来,再运行一次 git diff,结果什么都没显示。
$ git add .
$ git diff什么都没打印出来。改动并没有消失,也没有出什么问题。普通的 git diff 比较的是你的工作目录和暂存区,一旦你把所有改动都 stage 了,这两者就一致了,自然也就没有差异可以显示。要查看暂存区里等待提交的改动,应该用 git diff --staged。
$ git diff --staged
diff --git a/README.md b/README.md
index 1c2d3e4..9f8a7b6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
# weather-app
+A five-day weather dashboard built with vanilla JavaScript.同一个改动,现在显示出来了,因为 --staged 比较的是暂存区和你上一次提交。
git diff 显示的是你工作目录里还没被 stage 的改动。一旦你用 git add 把所有改动都 stage 了,普通的 git diff 就会什么都不显示。这是正常的,你的改动仍然在那里。想看等待提交的内容,用 git diff --staged。 为什么 Git 的历史是一张图
到目前为止你见到的每一次提交都只指向唯一一个父提交,从上往下读 git log 一直感觉像在读一条直线。这在一个人独自开发、只有一条工作线的项目里确实如此。但一旦分支和合并登场,这条直线就不成立了,这部分内容会在下一章 Branches 里讲到,因为一个项目真实的历史可以分叉成不同的线,再重新汇合到一起。

