Git原理-探寻日志记录

2024/06/12 | 字数1409 | 阅读3分钟


导读:当我们执行git log --name-status的时候,git都做了些什么?

我们先来看看这个命令的输出内容,然后根据输出内容,探寻对应的数据来源:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
git log --name-status
commit dc91f7f38cdb3c8876a7bfd38020e2a64f33015d (HEAD -> master, origin/master)
Author: ticktechman <ticktechman@gmail.com>
Date:   2024-06-12 19:28:09 +0800

    delete conn.c

D    src/conn.c

commit 0909df98f750118bebab6fb325ede8a836b6b7c1
Author: ticktechman <ticktechman@gmail.com>
Date:   2024-06-12 19:27:38 +0800

    rename demo.c to conn.c

R100 src/demo.c  src/conn.c

commit 1deeef231881649821b6437594293b22bb9183a0
Author: ticktechman <ticktechman@gmail.com>
Date:   2024-06-12 19:26:53 +0800

    second commit

M    README.md

commit 02bc27b851963a71d8b8c80f8d6834db25b716a1
Author: ticktechman <ticktechman@gmail.com>
Date:   2024-06-12 19:26:29 +0800

    init commit

A    README.md
A    src/demo.c
A    src/main.c

可以看到上面有4个版本的历史数据,每个版本中显示了commit对象ID、作者&提交人信息、修改描述以及修改的文件清单。

不带版本参数的情况下,Git默认从HEAD开始追踪历史记录,HEAD位于.git/HEAD,里面的内容为:

bash
1
2
3
4
5
6
7
## 查看HEAD内容,这里是一个符号引用(sym-ref),指向master
cat .git/HEAD
ref: refs/heads/master

## 查看master引用文件内容
cat .git/refs/heads/master
dc91f7f38cdb3c8876a7bfd38020e2a64f33015d

上面master引用文件中存储的内容是一个commit对象的ID,通过下面的命令可以打印它的内容:

bash
1
2
3
4
5
6
7
git cat-file -p dc91f7f38cdb3c8876a7bfd38020e2a64f33015d
tree 9bdf3e7865533385c7718f7e34fbf86d1a727a29
parent 0909df98f750118bebab6fb325ede8a836b6b7c1
author ticktechman <ticktechman@gmail.com> 1718191689 +0800
committer ticktechman <ticktechman@gmail.com> 1718191689 +0800

delete conn.c

通过上面的commit对象的内容,我们可以拿到上面日志中的大部分信息,但是细心的小伙伴可能发现了问题,这里没有和文件相关的信息,例如在第一条日志记录中,我们删除了一个文件src/conn.c,这里看不到,那Git是如何知道的呢?

答案在tree对象里面,但这不是直接获取的,而是要通过对比当前版本与上一个版本的tree对象的内容差异来获取。 可以通过下面的命令查看不同版本tree对象的内容:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
## v4(当前版本)版本的tree对象的内容
git ls-tree HEAD -r
100644 blob d21cf5020db5abcace9348a55fa6d871eaf24eb7	README.md
100644 blob 0c124f091e9fff8e05cd5de11b8058b05beb1f96	src/main.c

## v3 版本的tree对象的内容
git ls-tree HEAD^ -r
100644 blob d21cf5020db5abcace9348a55fa6d871eaf24eb7	README.md
100644 blob 8d8a1a21a7e49591c70f100175279fc0d3a1f711	src/conn.c
100644 blob 0c124f091e9fff8e05cd5de11b8058b05beb1f96	src/main.c

## v2 版本的tree对象的内容
git ls-tree HEAD^^ -r
100644 blob d21cf5020db5abcace9348a55fa6d871eaf24eb7	README.md
100644 blob 8d8a1a21a7e49591c70f100175279fc0d3a1f711	src/demo.c
100644 blob 0c124f091e9fff8e05cd5de11b8058b05beb1f96	src/main.c

## v1 版本的tree对象的内容
git ls-tree HEAD^^^ -r
100644 blob 2e23b77e9d108d265c6205bec72177f5fccec9e4	README.md
100644 blob 8d8a1a21a7e49591c70f100175279fc0d3a1f711	src/demo.c
100644 blob 0c124f091e9fff8e05cd5de11b8058b05beb1f96	src/main.c

Git通过遍历每个commit对象的parent指针,显示所有版本的信息,直到commit对象的parent为空为止,例如:

bash
1
2
3
4
5
6
git cat-file -p 02bc27b851963a71d8b8c80f8d6834db25b716a1
tree 8c34ef7320c2bd6b3b69fa9e64b23ff2cd74de5e
author ticktechman <ticktechman@gmail.com> 1718191589 +0800
committer ticktechman <ticktechman@gmail.com> 1718191589 +0800

init commit

这个版本中,没有parent对象指针,表示这是一个根commit对象,这个版本的tree对象中记录的所有文件都是新增文件。

上一篇:Git原理-代码入库 下一篇:Git原理-探究rename规则

【文章不错,鼓励一下】