git原理探索

概念

GIT是什么?简单来说它就是管理和维护代码的软件,它是由linux之父Linus大神花了两个星期开发的,最初是为了给linux内核开发社区提供源码管理,其实在GIT之前linux开源社区的代码管理都是通过bitkeeper版本控制系统来管理的(bitkeeper是由BitMover公司开发,它是一家商业公司),直到2005年,BitMover公司停止了跟linux开源社区的合作关系,也就是因为这个原因,git诞生了。
 
GITHUB、GITLAB、GITEE是什么?个人理解啊,首先它们是一个托管平台(一个共享仓库),其次它们也是一个跟我们本地一样的git版本库,这个怎么理解?Linus设计初衷就是要做一个分布式版本控制系统,并且去中心化,也就是每个安装GIT的电脑都是一个完整的版本库,可以相互推送。那么这样就会存在一个问题,毕竟我们的PC电脑不是服务器,所以GITHUB、GITEE、GITLAB诞生了,当然这些托管平台针对GIT管理只能说是它们一小部分功能,它们主要还是以论坛社交的方式在服务。
 
GIT工作流程,GIT工作流程三大核心,工作区、暂存区(索引区)、版本库,看图。
 
上图是我自己画的一张简图,大概反映了GIT工作流程以及涉及到的4种文件状态,有两个地方需要注意一下,图里面的渐变箭头和最下面那个箭头,1. 渐变箭头表示该文件已经添加到了暂存区,但是又被修改了,导致了工作区和暂存区状态不一致,2. 最下面那个箭头表示,文件从unmodified状态又回到了untracked状态,一般情况下不会有这两种状态的变更,极端情况下,比如撤销回退操作,这些操作后面都会说,概念就介绍到这吧。
 
准备工作

我这边准备的GIT环境比较简单,三个本地仓库文件夹,也就是三个本地文件夹,一个模拟远程仓库,两个模拟本地仓库,看图。
 
 
server模拟共享仓库,并且初始化一个Test.Service的仓库,user01、user02模拟两个pc客户端,通过git clone 命令从server共享库里面克隆Test.Service服务,就是这么简单干脆。
 
GIT目录结构

所有准备工作已完成,仓库也已完成初始化操作,下面通过tree命令看看GIT目录结构及作用。
 
$ tree .git/
.git/
|-- COMMIT_EDITMSG
|-- FETCH_HEAD
|-- HEAD
|-- config
|-- description
|-- hooks
|-- index
|-- info
|   `-- exclude
|-- logs
|   |-- HEAD
|   `-- refs
|       |-- heads
|       |   `-- master
|       `-- remotes
|           `-- origin
|               `-- master
|-- objects
|   |-- 44
|   |   `-- de11e3e3bbe90467ce478b79e821014c87aecd
|   |-- 6a
|   |   `-- bc29053633bce78260d5ac85a7f44b63b5d44e
|   |-- 86
|   |   `-- b5874bc0612638b63e760d5b47bcf43a529bb1
|   |-- info
|   `-- pack
`-- refs
    |-- heads
    |   `-- master
    |-- remotes
    |   `-- origin
    |       `-- master
    `-- tags
18 directories, 15 files
 
如上图,这是user02GIT仓库的目录结构,在调用tree命令之前,我用user02提交了一个文件,所以有些目录里面也就有了内容,初始化状态这些目录结构里面是没有内容的,hooks文件夹里面本来是有一些sample文件,今天暂时不会涉及到hook内容,所以全部删掉了,接下来我们一起看看这些目录文件的作用。
 
HEAD:它是一个文件,存储我们当前的工作分支,以及当前分支指向的最新commit提交,我们直接通过cat命令看看里面的内容,看代码,
 
$ cat .git/HEAD; 
cat .git/refs/heads/master; 
git cat-file -p 6abc
 
ref: refs/heads/master
6abc29053633bce78260d5ac85a7f44b63b5d44e
tree 44de11e3e3bbe90467ce478b79e821014c87aecd
author xxx <Administrator@JDF546R4F5WFBZD> 1648389719 +0800
committer xxx <Administrator@JDF546R4F5WFBZD> 1648389719 +0800
user02 1st
 
以上代码我是三个命令一起执行了,cat .git/HEAD; 输出了ref: refs/heads/master,表示当前工作分支是master,cat .git/refs/heads/master; 输出了内容为6abc2,这是一串sha1的hash值,表示当前master的最新提交索引在6abc这个文件里面,git cat-file -p 6abc命令查看最新提交内容,这里面涉及到了几个文件对象,稍后再说。
 
FETCH_HEAD:这个文件在仓库初始化状态是没有的,当我们执行git fetch或者git pull命令之后产生的,它里面存储了远程库所有分支最新提交的sha1索引,并且当前工作分支排在最前面,它有什么作用呢?这里有个小细节,git pull命令实际是两个命令的组合,当我们执行git pull的时候,会先执行git fetch,fetch之后也就产生了这个文件或者说更新了这个文件,并且把远程信息拉取到了本地,此时还没有合并,接着执行git merge合并,其实就是给merge提供对象。
 
$ cat .git/FETCH_HEAD
6abc29053633bce78260d5ac85a7f44b63b5d44e                branch 'master' of  file:///h:/git/server/Test.Service/
 
$ git cat-file -p 6abc
tree 44de11e3e3bbe90467ce478b79e821014c87aecd
author xxx <Administrator@JDF546R4F5WFBZD> 1648389719 +0800
committer xxx <Administrator@JDF546R4F5WFBZD> 1648389719 +0800
user02 1st
 
命令一,查看fetch head内容,当前只有一个master分支,所以只有一行输出,如果有多个分支会有多条记录,61bc表示远程master的最新提交,命令二查看远程master最新提交对象,它同样是个索引,它是个tree对象,对象这部分在objects目录的时候再说。
 
config:配置文件,主要存储的是本地配置信息,最只管的就是,我们在公司提交代码到服务器,显示的作者信息就是来自于这个配置文件,如果本地配置文件我们没有设置信息,如用户邮箱啥的,git会从全局配置信息获取,全局配置信息我就不贴了,命令很简单,$ git config --global -l
 
$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = false
        bare = false
        logallrefupdates = true
        symlinks = false
        ignorecase = true
[user]
        name = xxx
[remote "origin"]
        url = file:///h:/git/server/Test.Service/.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master 
 
index:暂存区的索引文件,它里面存储了文件名、目录以及它们的内容索引地址,它关联了工作区和仓库区,这个怎么理解?我现在工作区新添加了一个文件,执行git status,git终端输出文件未跟踪,当我执行git add命令之后再次执行status,它又提示我staged,所有这些都是通过索引区的这个index文件完成,我们通过命令ls-files -s看下它内容
 
$ git ls-files -s
100644 86b5874bc0612638b63e760d5b47bcf43a529bb1 0       user02.txt
 
$ git cat-file -p 86b5874
user02
 
这里我只做了一个简单的文件提交,所以里面只有一条数据,user02.txt表示文件名,那串hash表示内容索引,我也通过cat-file把它数出来了。
 
objects:这个目录表示对象集合,这个里面的对象一般有三种,blob、commit、tree这三种类型,我们前面提到的所有sha1索引指向的内容都在这objects目录里面能找到,我们这里有3个objects,我们通过命令cat-file命令看看,
 
$ git cat-file -t 44de;git cat-file -t 6abc;git cat-file -t 86b5
tree
commit
blob
 
git cat-file -t 查看的是对象类型,接着我们通过cat-file -p查看这三个索引对应的内容
 
$ git cat-file -p 44de;git cat-file -p 6abc;git cat-file -p 86b5
 
100644 blob 86b5874bc0612638b63e760d5b47bcf43a529bb1    user02.txt // tree对象的内容
 
tree 44de11e3e3bbe90467ce478b79e821014c87aecd // commit对象的内容
author yukang.wu <Administrator@JDF546R4F5WFBZD> 1648389719 +0800
committer yukang.wu <Administrator@JDF546R4F5WFBZD> 1648389719 +0800
user02 1st
 
user02 // blob对象的内容
 
以上内容我简单做了一些注释,这里再补充一下,blob对象产生是在 git add命令之后,这个对象只会记录文件内容(注意如果两份或者以上文件里面的内容完全一样,只会有一个blob对象产生,空文件夹不跟踪),commit对象产生是在 git commit命令之后,这个对象一般会包含一个tree对象以及其他辅助信息,如作者、时间戳、时区、提交说明、父对象(因为我这边是首次提交),tree对象的产生同样是在commit命令之后,tree对象里面主要记录的是文件内容指针,目录结构,文件名,整个设计确实很巧妙。
 
refs目录:前面有提到过,主要记录的是本地、远程、以及标签的内容索引地址,可以回到上面看一下。
 
pack: objects对象打包目录,一般情况下,我们第一次从远程拉取文件,我们的所有对象都是压缩打包的,包括index,还有一种情况,我们执行git gc命令,git也会帮我们打包所有objects对象,我们可以通过git verify-pack -v 命令查看里面的内容
|-- objects
|   |-- info
|   |   |-- commit-graph
|   |   `-- packs
|   `-- pack
|       |-- pack-872cbb392373e21735af47cb261f9fe3886ea31c.idx
|       `-- pack-872cbb392373e21735af47cb261f9fe3886ea31c.pack
 
$ git verify-pack -v  .git/objects/pack/pack-872cbb392373e21735af47cb261f9fe3886ea31c.pack
c4ca5ee2c3162610f2d218ebf61e22f153875def commit 222 155 12
6abc29053633bce78260d5ac85a7f44b63b5d44e commit 193 136 167
fcd15acf93cad34ac127b658f4e16be63a12e915 blob   3 12 303
0fe633e30c461e9e5e08d545fe06d909243955dd blob   3 12 315
98d03acc98edaf728a186256b5cc25de43447055 blob   4 13 327
86b5874bc0612638b63e760d5b47bcf43a529bb1 blob   7 16 340
a5ecf8da194ea4dbe5b59e9156e45aba1246cb54 tree   36 45 356
64229d6afd42a9d26082572a8d11f9b529a12fa3 tree   103 108 401
44de11e3e3bbe90467ce478b79e821014c87aecd tree   38 49 509
non delta: 9 objects
.git/objects/pack/pack-872cbb392373e21735af47cb261f9fe3886ea31c.pack: ok
 
结尾

GIT计划分两次写,今天主要是以概念为主,以静态方式解析git背后的逻辑原理,由于时间问题,明天还要上班,可能有些地方写的不够详细,或者理解不对,包含吧,下次以操作为主,当然不是讲命令操作,主要是挑一些工作中碰到的问题,比如回退、撤销、变基、合并等背后的一些逻辑。
posted @ 2022-03-28 00:18  小菜 。  阅读(98)  评论(0编辑  收藏  举报