还是绪个言吧
今天整理 GitHub 仓库,无意间翻到了几年前自学 Git 的笔记。要论知识的稳定性,
Git
应该能挤进前三——只要仓库还在,理论上当时的所有开发细节都可以追溯出来。正好过段时间会用到 Git,现在整理出来就当温故知新了。
当时找的学习资料是 Packt 出版社于 2018 年出版的一本电子书 Git Version Control Cookbook, Second Edition,直译过来就是《Git 版本控制手册》,作者有两位,一位来自丹麦,另一位来自意大利。选这本书来啃的原因也很简单:重实操,上手快,最关键还免费(同事转发的)。反正比看 Git 文档强多了。需要本书电子版的朋友可以在评论区给我留言。
P.S. 示例仓库点这里:GitHub
第一章 浏览 Git
相关主题:
- Git 对象模型
- Git 的三个阶段(stages)
- 查看有序无环图 (DAG)
- 提炼已修复事项
- 获取变动文件列表
- 使用
gitk
查看提交历史 - 在历史记录中查找提交版本
- 在历史代码中搜索信息
1.1 简介
传统版本管理系统:记录初始文件,以及后续变更。
Git:记录所有文件的快照。
Git 的数据模型:
commit
对象指向 根节点树 root tree
,根节点树又指向各子树(subtrees
)与文件(files
)
分支和标签指向 commit
对象,而 HEAD
对象指向当前签出的分支 branch
。因此对于每一个版本,其指向的根节点树 都是相同的。
1.2 Git 对象
Git 对象是按键值对的形式存储。这个 键,用的是该对象的 SHA-1 哈希值,外加一些额外属性(如大小)。
Git 共有四种对象类型:
- 文件
Files
(在 Git 语境下也称 二进制大对象 blob) - 目录
Directories
(在 Git 语境下也称 树) - 版本
Commits
- 标签
Tags
而 HEAD
是一个特殊的指针,指向当前签出的 branch
分支。
查看并打印 HEAD
标签指向的 commit
对象:
$ git cat-file -p HEAD
由于 HEAD
指向 master
(现在叫 main
)分支,master
分支又指向最近一次提交的版本 commit
。
1.2.1. tree
对象
用同样的方式查看 tree
:(SHA-1
)
$ git cat-file -p 34fa038544bcd9aed660c08320214bafff94150b
或使用 <rev>^<type>
式引用:
# on Linux
$ git cat-file -p HEAD^{tree}
# on Windows
PS> git cat-file -p 'HEAD^{tree}'
注:<rev>^<type>
返回从 rev
递归查找到的第一个 type
型对象。
1.2.2. blob
对象
用该命令继续查看 blob
对象:(使用 SHA-1
)
$ git cat-file -p 92f046f17079aa82c924a9acf28d623fcb6ca727
这里的 -p
即 pretty print
,格式化输出。常用的选项还有:
-s
: 显示对象大小(size)-t
: 显示对象类型(type)-e
: 检查是否存在(exist),不存在则报错,否则返回状态0(无返回)
1.2.3. branch
对象
该命令也可以作用于 master
分支:(现在默认为 main
分支)
$ git cat-file -p master
此外,在 .git
文件夹内也能查看 master
分支指向的 commit
的 ID,使用 cat
命令:
$ cat .git/refs/heads/master
# 2aa0ed57af1e4e35596616e7beee758e96b5e88c
要验证该结果是否为最新的版本,使用 git log -1
:
查看 HEAD
:(现在默认叫 main
分支)
$ cat .git/HEAD
# ref: refs/heads/master
由此可见,branch
分支只是一个指向 commit
对象的指针。
1.2.4. tag
对象
标签有三类:
- 轻量标签
- 注解标签
- 签名标签
查看注解标签,使用 git tag
:
$ git tag
v0.1
v1.0
进一步查看标签 v1.0
:
$ git cat-file -p v1.0
可见,标签由以下部分组成:
- 对象(object):此处即
master
分支的最新commit
- 类型(type):为
commit
型(commits
、blobs
与trees
都可以添加标签) - 标签名(tag name):
v1.0
- 贴标签人(tagger)及时间戳(timestamp):
John Doe <john.doe@example.com> 1526017989 +0200
- 标签注释内容(tag message):
We got the hello world C program merged, let's call that a release 1.0
还可以通过使用命令 git hash-object
重散列(rehashing)来验证 git cat-file
的结果;例如,验证 HEAD
指向的 commit
:
$ git cat-file -p HEAD | git hash-object -t commit --stdin
# 2aa0ed57af1e4e35596616e7beee758e96b5e88c
该结果可以用 git log
作对比:
$ git log -1 | grep commit
# commit 2aa0ed57af1e4e35596616e7beee758e96b5e88c
命令 git cat-file -p
虽然少见,但查看对象信息、了解各对象的构成情况却很方便。除了这个命令外,查看一个 tree 对象也可以使用 git ls-tree
或 git show
,只是结果显示的方式不同罢了:
$ git cat-file -p HEAD^{tree}
100644 blob f21dc2804e888fee6014d7e5b1ceee533b222c15 README.md
040000 tree abc267d04fb803760b75be7e665d3d69eeed32f8 a_sub_directory
100644 blob b50f80ac4d0a36780f9c0636f43472962154a11a another-file.txt
100644 blob 92f046f17079aa82c924a9acf28d623fcb6ca727 cat-me.txt
100644 blob bb2fe940924c65b4a1cefcbdbe88c74d39eb23cd hello_world.c
$ git ls-tree HEAD^{tree}
100644 blob f21dc2804e888fee6014d7e5b1ceee533b222c15 README.md
040000 tree abc267d04fb803760b75be7e665d3d69eeed32f8 a_sub_directory
100644 blob b50f80ac4d0a36780f9c0636f43472962154a11a another-file.txt
100644 blob 92f046f17079aa82c924a9acf28d623fcb6ca727 cat-me.txt
100644 blob bb2fe940924c65b4a1cefcbdbe88c74d39eb23cd hello_world.c
$ git show HEAD^{tree}
tree HEAD^{tree}README.md
a_sub_directory/
another-file.txt
cat-me.txt
hello_world.c