zoukankan      html  css  js  c++  java
  • git设计哲学

    刚开始使用git的时候,总想拿git来和cvs或者svn来作对比,但不久后发现这个想法本身就是错的,git完全就是另外一种物种,一种本属于未来的物种。它的对象存储方式,快照,分支等,都是完全不同的。
     
    相信每个使用git的人,都想了解git内存文件的存储对象,快照,提交在历史和分支等内部的原理。都想知道它是否有传说中的那么强大?
     
     
    Git 对象
    先从本地创建一个空git仓库开始
     
    $ mkdir test
    $ cd test
    $ git init
    Initialized empty Git repository in /Users/lyc/Desktop/test/.git/
    这时会发现目录下只有一个.git文件夹,进去后长这样
     
    .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
    • description文件仅供GitWeb使用,不用关心它。
    • config文件包含了项目特有的配置选项,如最常用的用户名和邮箱。
    • info目录保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件。这个用得比较少,也不用太关心。
    • hooks目录保存了客户端或服务端钩子脚本,一般我们都是用默认的,很少改,也不用太关心。

    因此,我们需要重点关心另外四个重要的文件或目录:HEAD和index文件,objects和refs目录,因为它们是Git的核心:

    • objects 目录存储所有数据内容。
    • refs 目录存储指向数据 (分支) 的提交对象的指针。
    • HEAD 文件指向当前分支。
    • index 文件保存了暂存区域信息。
     
    刚初使化的一个 Git 仓库, objects 目录是空的:
    $ find .git/objects
    .git/objects
    .git/objects/info
    .git/objects/pack
    Git 初始化了 objects 目录,同时在该目录下创建了 pack 和 info 子目录,但是该目录下没有其他常规文件
     
    接下来,我们新建一个文件test1.txt,内容为test1,并把它加入暂存区
     
    $ echo test1 > test1.txt
    $ git add test1.txt
    发现.git目录下多了2个文件,且内容都为字节码:
    .git/
    |--index
    |--objects
    |   |--a5
    |   |   |-- bce3fd2565d8f458555a0c6f42d0504a848bd5
     
    $  find .git/objects
    .git/objects
    .git/objects/a5
    .git/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5
    .git/objects/info
    .git/objects/pack

    在.git目录下多了一个index文件
    在objects下面多了一个a5文件夹,文件夹下有一个文件名为bce3fd2565d8f458555a0c6f42d0504a848bd5的文件
     
    使用如下命令查看test1.txt的hash值
     
    $ git hash-object test1.txt
    a5bce3fd2565d8f458555a0c6f42d0504a848bd5
    发现结果的前2位是文件夹的名字,后38位是文件的名字。
     
    a5bce3fd2565d8f458555a0c6f42d0504a848bd5这个文件是用zlib压缩的
    通过git cat-file 命令可取出文件存储的内容
     
    $ git cat-file -p a5bce3fd2565d8f458555a0c6f42d0504a848bd5
    test1
    内容就是test1.txt的文件内容
     
    看看index文件,刚刚了解了index 文件保存了暂存区域信息, 用git ls-files —stage命令可查看index内容
     
    $ git ls-files --stage
    100644 a5bce3fd2565d8f458555a0c6f42d0504a848bd5 0    test1.txt
    此时index保存的就是新加入暂存区的文件快照
     
    gitt使用'blob ' + len(content) + '' + content作为文件内容,其sha1值的前2位作为文件夹名,后38位作为文件名
     
     
    Tree(树)对象
    接下去来看 tree 对象,tree 对象可以存储文件名,同时也允许存储一组文件。Git 以一种类似 UNIX 文件系统但更简单的方式来存储内容。所有内容以 tree 或 blob 对象存储,其中 tree 对象对应于 UNIX 中的目录,blob 对象则大致对应于 inodes 或文件内容。一个单独的 tree 对象包含一条或多条 tree 记录,每一条记录含有一个指向 blob 或子 tree 对象的 SHA-1 指针,并附有该对象的权限模式 (mode)、类型和文件名信息。
     
    现在把test1.tst提交,作为仓库的第一次提交
    $ git commit -m "first commit"
    [master (root-commit) a3951d5] first commit
     1 file changed, 1 insertion(+)
     create mode 100644 test1.txt
     
    发现在objects目录下多了两个文件夹,文件夹下面是对面的sha1文件
     
    $  find .git/objects
    .git/objects
    .git/objects/a3
    .git/objects/a3/951d57b1413275b171d967fa67fd90eecff648
    .git/objects/a5
    .git/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5
    .git/objects/c0
    .git/objects/c0/da834e42dcbf7b2b1c4a97925bef105d3863a3
    .git/objects/info
    .git/objects/pack
     
    分别查看一下内容
    $ git cat-file -p a3951d57b1413275b171d967fa67fd90eecff648
    tree c0da834e42dcbf7b2b1c4a97925bef105d3863a3
    author lyc <yechenli2009@gmail.com> 1444534714 +0800
    committer lyc <yechenli2009@gmail.com> 1444534714 +0800
     
    first commit
     
    $ git cat-file -p c0da834e42dcbf7b2b1c4a97925bef105d3863a3
    100644 blob a5bce3fd2565d8f458555a0c6f42d0504a848bd5    test1.txt
     
    其中第一个是commit对象,第二个是tree对象
     
    这个tree对象可以认为是git仓库的根目录,类似unix文件系统中的"/"。
     
    Commit(提交)对象
    我们在根目录新建一个文件夹temp,在temp下面添加一个文件test2.txt,文件内容为test2,并提交
    $ mkdir temp
    $ cd temp/
    $ echo "test2" > test2.txt
    $ git add temp
    $ git commit -am “second commit"
     
    发现objects下面又多了4个文件夹,以及文件夹下对面的sha-1文件
    $ find .git/objects
    .git/objects
    .git/objects/18
    .git/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827
    .git/objects/35
    .git/objects/35/592c587f70cf6ec1b99bb382bec2ef92f83396
    .git/objects/9e
    .git/objects/9e/7b8054ac3ca530d8e69556dff5903cdcbdc4d3
    .git/objects/a3
    .git/objects/a3/951d57b1413275b171d967fa67fd90eecff648
    .git/objects/a5
    .git/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5
    .git/objects/c0
    .git/objects/c0/da834e42dcbf7b2b1c4a97925bef105d3863a3
    .git/objects/d2
    .git/objects/d2/5d2289339c751ff3f7e1ef1865a58c71d0f51c
    .git/objects/info
    .git/objects/pack
     
    通过git log命令来查看提交历史
    $ git log
    commit d25d2289339c751ff3f7e1ef1865a58c71d0f51c
    Author: lyc <yechenli2009@gmail.com>
    Date:   Sun Oct 11 13:54:00 2015 +0800
     
        second commit
     
    commit a3951d57b1413275b171d967fa67fd90eecff648
    Author: lyc <yechenli2009@gmail.com>
    Date:   Sun Oct 11 11:38:34 2015 +0800
     
        first commit
     
    发现最后一次提交的sha-1文件是d25d2289339c751ff3f7e1ef1865a58c71d0f51c,对应文件是
     
    .git/objects/d2/5d2289339c751ff3f7e1ef1865a58c71d0f51c
     
    我们查看d25d2289339c751ff3f7e1ef1865a58c71d0f51c里的内容
     
    $ git cat-file -p d25d2289339c751ff3f7e1ef1865a58c71d0f51c
    tree 35592c587f70cf6ec1b99bb382bec2ef92f83396
    parent a3951d57b1413275b171d967fa67fd90eecff648
    author lyc <yechenli2009@gmail.com> 1444542840 +0800
    committer lyc <yechenli2009@gmail.com> 1444542840 +0800
     
    second commit
     
    发现其中;
    tree 35592c587f70cf6ec1b99bb382bec2ef92f83396 是本次提交指向的tree对象(即根目录)对应文件是
    .git/objects/35/592c587f70cf6ec1b99bb382bec2ef92f83396
     
    parent a3951d57b1413275b171d967fa67fd90eecff648是第二次提交指向第一次提交对象的指针
    author和committer分别是作者是提交者
     
    再来看 35592c587f70cf6ec1b99bb382bec2ef92f83396文件的内容
    $ git cat-file -p 35592c587f70cf6ec1b99bb382bec2ef92f83396
    040000 tree 9e7b8054ac3ca530d8e69556dff5903cdcbdc4d3    temp
    100644 blob a5bce3fd2565d8f458555a0c6f42d0504a848bd5    test1.txt
    这个tree对象也指向一个tree对象和一个blod对象,分别代表temp目录和test1.txt文件的sha1文件
    这一行 040000 tree 9e7b8054ac3ca530d8e69556dff5903cdcbdc4d3    temp 的对应文件是
    .git/objects/9e/7b8054ac3ca530d8e69556dff5903cdcbdc4d3
     
    再继续看tree对象9e7b8054ac3ca530d8e69556dff5903cdcbdc4d3里面的内容
    $ git cat-file -p 9e7b8054ac3ca530d8e69556dff5903cdcbdc4d3
    100644 blob 180cf8328022becee9aaa2577a8f84ea2b9f3827    test2.txt
    文件内容中只有一个指向blob对象的指针(即test1.txt对象的sha1文件),对应的文件为
    .git/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827
    至此,新增加的4个文件的关系已找到。
     
    两次提交的关系如图:
     
     
    这就是git的对象系统,本质上是一个key-value的内容寻址文件系统。
    当用git add命令把一个文件或者目录添加到git跟踪的时候,会生成一个blob对象或者tree对象
    当用git commit 来提交的时候,会创建一个commit对象,commit包含了提交者信息,还包含一个指向仓库根目录的tree对象。
    然后tree对象再包含指向文件的blob对象或者子目录tree对象
     
     
  • 相关阅读:
    SpringBoot配置默认日志logback
    SpringBoot静态资源映射、拦截器、过滤器使用
    windows系统安装两个Mysql服务
    SpringBoot使用Jsp开发Web项目
    SpringBoot使用Thymeleaf开发Web项目
    SpringBoot启动原理
    javascript Date
    UDP发送数据测试
    自动迁移
    EF 自测例子
  • 原文地址:https://www.cnblogs.com/lycokcc/p/4869288.html
Copyright © 2011-2022 走看看