git 学习简记 1

(这篇简记源自阅读 The Architecture of Open Source Applicationsgit 一文)

git 简介

git 通过使用基于 P2P 网络的源码库,使得多人维护数字化工作变得可能。git 支持分布式工作流,允许一部分工作被分发出去,或是合并回来。

git 的由来

git 项目源于 Linux 内核社区。

Linux 内核的贡献者分布世界各地,对代码库的理解程度也不相同。Linux 内核在相当长一段时间曾使用 tarball 和 patch 的形式进行版本管理。

git 源于 2005 年,当时 BitKeeper 收回了部分 Linux 内核开发者的使用权,促使 Linus 编写了当今的 git。

Git 的设计理念是 反 CVS 的:

  • 支持分布式工作流
  • 保证内容完整性
  • 高性能

分布式版本管理系统提供了极高的灵活性,但也牺牲了易用性。

分布式版本管理的优点包含:

  • 允许协作者离线工作并渐进的提交更改
  • 允许协作者来决定他的工作是否可以提交
  • 允许协作者离线访问代码库的历史记录
  • 允许协作者将其工作发布到不同的代码库中(可能是不同的分支)

版本管理系统设计

版本管理系统通常包含 3 个核心需求:

  • 存储内容
  • 跟踪内容更改
  • 向协作者分发内容和历史记录

内容存储

VCS 一般使用 delta-based changeset 或 DAG 来存储内容:

  • delta-based changeset 保存了版本之间的变更,以及一些元数据
  • DAG 则将内容的文件系统树视为一个快照,并尽可能复用树中未修改的对象

git 使用 DAG 存储内容

提交和合并历史

管理历史和跟踪变更,VCS 一般使用 线性 历史或 DAG 历史。git 使用 DAG 存储变更历史。

每个 git 提交都包含其祖先的元数据。一个 git 提交可以有 0 个或多个父提交。

git commit

git 和 subversion 的另一个区别在于 git 支持带历史合并记录的分支。

分发

VCS 的内容分发方式不外三种:本地,中央服务器,分布式。

例子:假设开发者 Alex 要提交一个 1MB 的文件:

  • subversion: Alex 在本地保存变更,再将变更提交到服务器,服务器会生成一个变更记录,然后将其保存至代码库
  • git: Alex 在本地 提交 变更,然后将本地提交 推送 至服务器代码库,服务器会检查是否可以使用这个提交,然后拒绝或保存该提交至代码库

git 工具

git 包含命令行工具以及 UI 工具

git toolkit 分为两类:底层(plumbing)命令,用于直接操纵内容 DAG;高层(procelain)命令,为一系列操纵 git 代码库的命令集合。

git 由于其设计,使得难以被作为一个库使用

代码库,索引,以及工作区

这里用实例展示 git 的基础概念。

首先初始化 git 代码库:

1
2
3
mkdir testgit
cd testgit
git init

git init 命令同时会创建 .git 子目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.git/
|-- HEAD
|-- config
|-- description
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-commit.sample
| |-- post-receive.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- pre-rebase.sample
| |-- prepare-commit-msg.sample
| |-- update.sample
|-- info
| |-- exclude
|-- objects
| |-- info
| |-- pack
|-- refs
|-- heads
|-- tags

.git 包含以下文件和目录:

  • 配置:.git/config, .git/description, .git/info/exclude 用来配置本地代码库
  • 钩子:.git/hooks 包含在代码库各个周期时会被执行的脚本
  • 临时区域:.git/index 提供当前工作目录的临时区
  • 对象数据库:.git/objects 是默认的 git 对象数据库,它包含本地内容或指向本地内容的指针。这些对象均为只读
  • 引用:.git/refs 用来存储本地/远程的分支,标签,以及 head 的引用。引用是指向对象的指针,一般为 tagcommit

.git 是实际的代码库。而保存当前文件的目录被称为 工作目录

使用 git init --bare 创建不包含工作目录的代码库。

.git/index 是另一个重要的文件:它提供了一个当前工作目录和当前代码库之间的缓冲区,用来存储当前未提交的一个或多个文件。

git checkout [branch]HEAD 引用移到指定分支,然后通过索引文件见当前工作目录中的文件恢复至该分支的状态。

git add [files] 会交叉引用索引文件中的校验和来检查当前未提交文件是否需要更新工作目录的版本,git 目录不受影响。

(未完待续)