git 实现
关于git
git 本质上是一个分布式内容寻址文件系统。最初由 Linus Torvalds 开发用于管理 Linux 系统源码。
Torvalds wanted a distributed system that he could use like BitKeeper, but none of the available free systems met his needs. He cited an example of a source-control management system needing 30 seconds to apply a patch and update all associated metadata, and noted that this would not scale to the needs of Linux kernel development, where synchronizing with fellow maintainers could require 250 such actions at once. For his design criterion, he specified that patching should take no more than three seconds, and added three more goals:
- Take the Concurrent Versions System (CVS) as an example of what not to do; if in doubt, make the exact opposite decision.
- Support a distributed, BitKeeper-like workflow.
- Include very strong safeguards against corruption, either accidental or malicious.
Linus 最初的目标是要构建一个高性能、分布式、强壮的类 BitKeeper 的版本管理系统(CVS被作为反例列出,可见Linus也是CVS受害者)。从 Linus 设计目标可以大致看到现在的 git 的雏形。分布式,每个人本地存有仓库的备份,不易丢失或被篡改。几万行或者几十万行的中大型仓库提交等操作耗时都很短。超大型项目也有 VFS for Git 这种插件可以支持。
概念
工作区:电脑里能看到的目录。
暂存区:英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。
分支、tag
实现
使用 git init 命令初始化一个 git 项目,查看 .git 目录文件,结果如下图:
通过操作git的底层命令来直接生成一个commit,以此看下其运行机制。
objects目录
objects目录存储着git的4个核心对象:blob、tree、commit和tag。
- blob:文件内容:存储源码、文本或者二进制格式文件。
- tree:文件信息:目录信息、文件名、文件权限属性信息以及文件名对应的blob对象的hash。
- commit:提交信息:parent commit、committer、auther、time、commit message以及tree对象的hash等信息。
- tag:标签信息:tagger、time tag message以及commit对象的hash。
blob object
首先使用git hash-object2手动生成一个blob对象,代表我们要保存的文件内容,这个命令会返回根据文件内容+附加信息生成的SHA1。
1 | echo 'Test create blob object' | git hash-object -w -t blob --stdin |
需要注意的是git hash-object并不是直接对内容计算SHA1,而是会添加一个blob 24\0的前缀,其中24是文件内容的byte长度。等效于:
1 | echo 'blob 24\0Test create blob object' | shasum -a 1 |
当你用cat尝试去读取文件内容时,你会发现无法读取,这是因为它本身是一个采用deflate压缩算法的zlib stream4,而非文本文件。
可以使用git cat-file5来读取它。
1 | git cat-file -p 7d6be813a625383b03464a4867fd9ac9e35ed61b |
tree object