zoukankan      html  css  js  c++  java
  • git原理-本地仓库认识

    项目人员使用git,几乎70%的工作都是在本地仓库完成的。由此可见本地仓库的重要性。

    下面我们就通过一些基本的命令讲下git的本地仓库的结构,存储流程,数据类型,如何存储......

    仓库结构

    大家都晓得提交文件需要先git add 再Git commit。为了晓得add到哪里了,commit到哪里了。需要知道git仓库结构:工作区+暂存区+版本库。

    工作区:就是你在电脑里能看到的项目目录。你所有本地的改动都是在工作区改动的。工作区是对项目的某个版本独立提取出来的内容。 是从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。

    暂存区:暂存区是一个文件,一般在 Git 仓库目录中的index文件(.git/index)中,保存了下次将要提交的文件列表信息。 git ls-files --stage可查看暂存区内容。保存了所有文件对应的索引,即SHA1值。所以 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。

    版本库:.git目录是 Git 用来保存项目的元数据,版本,分支的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据。其中 .git/objects目录,被称为对象数据库。具体的目录详情看下图。

    项目文件的状态

    项目文件有四种状态,git可以管理的有三种状态: 已提交(committed)已修改(modified) 和 已暂存(staged)

    第4个状态:未跟踪

    • 已修改:表示修改了文件(该文件曾经添加过版本库),但还没保存到数据库中。

    • 已暂存:表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。

    • 已提交:表示数据已经安全地保存在本地数据库中(所以也可称为未修改状态)。

    • 未跟踪:新创建的文件如果没有添加到暂存区,那git没办法对其跟踪,故而是‘未跟踪’状态。

    项目文件状态与迁移:

    当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。

    当执行提交操作git commit时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。

    当执行 git reset HEAD命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

    当执行 git rm --cached <file> 命令时,会直接从暂存区删除文件,工作区则不做出改变。

    当执行git checkout . 或者 git checkout -- <file> 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。

    当执行 git checkout HEAD ." 或者 "git checkout HEAD <file> 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

    项目文件迁移过程拆解

    概念了解后,我们实际操作看下git文件管理流程~

    一 创建一个git仓库

    1. 创建一个目录,进入目录
    2. 过git init 命令把这个目录变成Git可以管理的仓库

      (在/deploy/script/.git/下初始化了一个空的git版本库)
    3.  ls -a 可发现多了一个.git目录。这个目录就是Git用来跟踪管理版本库的,所谓的git版本库
      平平无奇的目录/deploy/script/ 摇身一变成了一个git仓库了~~~

    或者Git clone一个已有的远程仓库。拷贝的是.git目录。然后解压默认指定的master版本数据到工作区。

    二 git add 过程拆解

    提交文件到暂存区。这一步其实主要包含两个步骤:

    1. git hash --object <file>

    工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中

    1. 生成SHA-1值,并在版本库的objects目录下生成目录跟文件。用SHA-1[0:2]命名目录,SHA[2:40]命名文件名。

    2. 存储文件压缩后的数据。可通过git cat-file -p SHA-1查看object文件内容

    2. git update-index <file>

    更新index文件中提交文件的SHA-1值,也就是文件指向的objects地址。git ls-files --stage 可查看暂存区(index文件)的内容

    三 git commit 过程拆解

    git commit提交过程也可分为两个步骤:

    1. 计算每一个子目录(项目根目录)的校验和,然后在Git 仓库中将这些目录保存为树(tree)对象。子目录中包含的是blob对象。
    2. 相关提交信息+指向顶层树对象(项目根目录)的指针 合并生成一个commit 对象。如此它就可以在将来需要的时候,重现此次快照的内容了。
    3. 当前 分支会做相应的更新(.git/refs/heads 下文会详细说明)

    git cat-file -p SHA-1 可查看objects文件下存储的内容,包括commit对象,和tree对象。

    git cat-file -t SHA-1 可查看文件类型

    例如:一个项目里假如有三个文件ReadME,LICENSE,test.rb,commit后仓库里会保存五个对象。(如果项目不只三个文件,还有子目录的话,那每个目录都会生成一个tree对象。)

     

    对象模型

    块-blob

    也叫数据对象,文件的每一个版本表示为一个块(blob)。一个blob保存一个文件的数据,但不包含任何关于这个文件的元数据,甚至连文件名也没有。

    目录树-tree

    树对象,一个目录树对象代表一层目录信息,它记录blob标识符、路径名和在一个目录里所有文件的一些元数据。

    提交-commit

    提交对象,一个提交对象保存版本库中一次变化的元数据

    格式很简单:它先指定一个顶层树对象,代表当前项目快照; 然后是可能存在的父提交(前面描述的提交对象并不存在任何父提交); 之后是作者/提交者信息(依据你的 user.name 和 user.email 配置来设定,外加一个时间戳); 留空一行,最后是提交注释。

    标签-tag

    标签对象,一个标签对象分配一个任意的且人类可读的名字给一个特定对象,通常是一个提交对象。

    对象存储

     

    你向 Git 仓库提交的所有对象都会有个头部信息一并被保存 git hash --object <file>
    Git 首先会以识别出的对象的类型作为开头来构造一个头部信息。 接着 Git 会在头部的第一部分添加一个空格,随后是数据内容的字节数,最后是一个空字节(null byte):
    比如数据对象 content = "hello world" 类型是‘blob’
    头部存储方式:类型+空格+字节数+空字节
    头部信息是:"blob 11u0000"
    Git 会将上述头部信息和原始数据拼接起来
    存储的对象是:"blob 11u0000hello world",并计算出这条新内容的 SHA-1 校验和

    压缩新的数据对像:

    SHA-1用来做存储对象的指针,指向的是.git/objects下的存储对象。
    目录跟文件名对应SHA-1前2个字符和后38个字符。
    存储的文件内容是压缩后的数据。

    (commit,tree对象存储同理blob对象。)

    本地分支

    一 分支存储目录

    .git/refs/heads/

    在我们初始化一个git仓库的时候,会分配一个指针HEAD(.git/HEAD)表示当前分支的意思。且HEAD默认指向master分支 .git/refs/heads/master

    如果切换分支为dev,HEAD就指向.git/refs/heads/dev了。由此可见,所有的分支都是存储在 .git/refs/heads/目录下的。同样也解释了,为何git切换分支如此迅速,因为知识更改了一个指针。

    二 分支存储的内容

    存储内容是分支最新一次的commit对象。

    比如我们从master切换一个分支dev出来,可以看到master的commit对象跟dev的commit对象是完全一样的。

    那如果修改下dev分支的文件内容提交,会发生什么呢?没错,dev分支的内容发生变更了,变成提交对象4b39a了。而master的内容没变还是之前的。可以git cat-files -p 4b39af8 查看版本快照

    三 分支合并机制

    我们切到master,合并dev分支。看到提示的内容,从f3c68...变成了4b39a....。也就是说简单的合并分支,只是把master的提交对象换成了dev的提交对象了。其他什么也没动。

    这个‘快速合并’称为fast-forward合并策略。如果不希望直接合并可以:git merge --no-ff。

    下面这种情况:master分支跟new分支都有改动,就不能快速合并。合并会会生成一个新的commit对象,父对象指向base跟new。 

  • 相关阅读:
    谷歌地图地理解析和反解析geocode.geocoder详解(转)
    Html5 Geolocation获取地理位置信息(转)
    利用单片机快速实现家庭智能控制平台
    邪恶改装:TPYBoard制作廉价WIFI干扰器
    [TPYBoard
    [TPYBoard
    [TPYBoard
    python中的subprocess.Popen()使用
    KVM虚拟机的xml配置文件
    Linux LVM 总结
  • 原文地址:https://www.cnblogs.com/lixiaoxuan/p/14049859.html
Copyright © 2011-2022 走看看