git内部原理

Git 是什么

从根本上来讲 Git 是一套内容寻址 (content-addressable) 文件系统,在此之上提供了一个 VCS 用户界面。

git 目录

当你在项目文件夹下执行 git init后,Git 会创建一个 .git 目录,几乎所有 Git 存储和操作的内容都位于该目录下

1
2
3
4
5
6
7
8
9
10
目录结构
HEAD
branches/
config
description
hooks/
index
info/
objects/
refs/

新版本的 Git 不再使用 branches 目录,description 文件仅供 GitWeb 程序使用,所以不用关心这些内容。config 文件包含了项目特有的配置选项,info 目录保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件。hooks 客户端或服务端钩子脚本。

最关键的是以下四个目录:

objects 目录存储所有数据内容,refs 目录存储指向数据 (分支) 的提交对象的指针,HEAD 文件指向当前分支,index 文件保存了暂存区域信息。马上你将详细了解 Git 是如何操纵这些内容的

git 中的对象

Git 中有四种对象类型,分别为 blob、tree、commit 和 tag 对象类型,每个对象都有一个 SHA-1 值(指针)指向自身实例,SHA-1 是在创建对象时生成,通过这个 SHA-1 来访问对象实例,对象内容存储在.git/objects 目录。

类型 说明
blob 数据对象 可存储较大内容的文本,可看作是操作系统中文件的内容
tree 树对象 可存储多个 tree 和 blob 对象,可看作是操作系统中的目录
commit 提交对象 可存储一个 tree 对象和其它信息(提交人、提交日期、父 commit 对象和提交说明等)
tag 标签对象 tag 对象存储一个 SHA-1(SHA-1 可以指向任意对象,不仅仅是 commit 对象)和 tag 创建人、创建时间、tag 说明等信息,创建 annotated(附注标签)类型标签就是在创建一个 tag 对象

git add 和 git commit 命令时 Git 进行的工作包括保存修改了的文件的 blob,更新索引,创建 tree 对象,最后创建 commit 对象,这些 commit 对象指向了顶层 tree 对象以及先前的 commit 对象。这三类 Git 对象 ── blob,tree 以及 commit ── 都各自以文件的方式保存在 .git/objects 目录下。

Git References

你可以执行像 git log 1a410e 这样的命令来查看完整的历史,但必须要记住最后一次提交的 sha1 值,这样才能在提交历史中找到这些对象。你需要一个文件来用一个简单的名字来,

在 Git 中,“引用”(references 或者 refs,译者注)可以记录这些 SHA-1 值。你可以在 .git/refs 目录下面找到这些包含 SHA-1 值的文件。这样你就可以用这些指针而不是原来的 SHA-1 值去检索了。

branch

branch 是一类引用。HEAD 除了直接指向 commit,也可以通过指向某个 branch 来间接指向 commit。当 HEAD 指向一个 branch 时,commit 发生时,HEAD 会带着它所指向的 branch 一起移动。

push

实质上,push 做的事是:把当前 branch 的位置(即它指向哪个 commit)上传到远端仓库,并把它的路径上的 commits 一并上传。
push 的时候,如果当前分支是一个本地创建的分支,需要指定远程仓库名和分支名,用 git push origin branch_name 的格式.

rebase

rebase 命令与 merge 相似都可以用来合并代码。区别就在于 rebase 可以提供更线性的提交历史。
rebase 的意思是,给你的 commit 序列重新设置基础点(也就是父 commit)。也就是说在合并代码时,远端会设立新的起点,把本地的提交历史复制到起始点之后,这样两个分支的提交历史就不再分叉了