项目人员使用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 11\u0000"
Git 会将上述头部信息和原始数据拼接起来
存储的对象是:"blob 11\u0000hello 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。

git原理-本地仓库认识的更多相关文章

  1. github仓库主页介绍、用git管理本地仓库和github仓库、搭建网站

    github仓库主页介绍 名词解释: 工作区: 添加.编辑.修改文件等动作 暂存区: 暂存已经修改的文件,最后统一提交到git中 git(仓库): 最终确定的文件保存到仓库,成为一个新的版本,并且对他 ...

  2. Git单人本地仓库操作

    本地仓库是个.git隐藏文件 以下为演示Git单人本地仓库操作 1.安装git sudo apt-get install git 密码:skylark 2.查看git安装结果 git 3.创建项目 在 ...

  3. 和同事合作开发,使用局域网 git创建本地仓库

    转自原文 和同事合作开发,使用局域网 git创建本地仓库 1.仓库 建一个空文件夹来做仓库,例如建为 cangku 1.1 cd 到 cangku目录下 创建远程仓库容器 mkdir  mycangk ...

  4. 使用Git初始化本地仓库并首次提交代码

    本文介绍使用Git初始化本地仓库,并首次提交代码到远程仓库GitLab上面. 首先,登录GitLab,创建一个新项目的私人仓库: 然后,在本地仓库(就是你写代码文件夹),右键,Git Bash Her ...

  5. 使用 Git 删除本地仓库和远端仓库文件

    使用 git bash 来删除 一.将文件(夹)添加到暂存区 这里假设本地和远端都有一个 test.txt 文件先在本地删除,通过 ·git status 查看通过git add test.txt 添 ...

  6. Git创建本地仓库&把pycharm项目添加GitHub仓库上

    一.创建本地仓库 1.1.下载Git地址:https://git-scm.com/downloads 下载完,一路next就可以 1.2.打开Git Bash输入: #创建一个learngit目录 $ ...

  7. 如何使用Git建立本地仓库并上传代码到GitHub

    使用Git建立本地仓库并上传代码到GitHub 工具/原料   电脑安装git客户端.注册github账号并登陆 方法/步骤     到本地项目文件夹右键选择git bash here   输入个人信 ...

  8. Git创建本地仓库

    使用Git创建本地仓库, 可以记录文本文件变化, 这里以自己的文章为例, 利用TortoiseGit工具创建一个本地Git仓库. 1. 切换到需要创建仓库的目录下, 比如:D:\MyDoc\Devel ...

  9. Git 创建本地仓库

    前面已经搭好环境了,现在我们缺的是一个管理版本控制的仓库.这次的实验是在电脑本地创建本地仓库.指定路径 默认的位置是在你所安装Git的目录下.Git的仓库你可以建在你电脑的任何目录下(最好不要包含有中 ...

随机推荐

  1. java关键字之super

    1.在子类的构造方法的第一条语句处调用其父类的构造方法: 如果父类提供了构造方法,并且父类不拥有无参构造方法,则要求子类拥有相同结构的构造方法.即,子类构造方法的参数个数和类型必须和父类的构造方法一致 ...

  2. MONGODB02 - MongoSocketWriteException 异常会迟到,但从不缺席

    接上一个<MONGODB01 - Prematurely reached end of stream 错误定位及修复>处理完成之后,又报错了,场景也是一段时间不访问MongoDB,突然访问 ...

  3. 完美解决CentOS8 yum安装AppStream报错,更新yum后无法makecache的问题

    问题 CentOS 8 yum安装软件时,提示无法从AppStream下载 [root@C8-3 ~]# yum -y install httpd mariadb-server mariadb php ...

  4. xlwt模块,(Excel表格)

    1. 安装模块 #pip install xlwt 2. 简单例子打印excel import xlwt # 创建一个workbook 设置编码 workbook = xlwt.Workbook(en ...

  5. xshell连接windows10子系统ubuntu

    修改端口 cd /etc/ssh#备份sudo cp sshd_config sshd_config.baksudo vim sshd_config修改sshd_config Port 2233 #修 ...

  6. python开发初识(一)

    python开发 机器码和字节码 机器码 :计算机可以直接认识的语言 字节码 :高级语言转换成机器码去执行 语言之间的对比: C,汇编 :C语言是根语言 python Java :既能写前端,又能写后 ...

  7. 力扣 - 142. 环形链表 II

    目录 题目 思路1 代码实现 思路2 代码实现 题目 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链 ...

  8. JS--遍历对象属性的五种方式

    ES6 一共有 5 种方法可以遍历对象的属性. (1)for...in for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性). (2)Object.keys(obj) Ob ...

  9. .net core中的哪些过滤器

    前言 书承接上文,咱们上回说到,.net core中各种日志框架, 今天我讲讲.net core中的内置过滤器吧! 1.什么是过滤器? ASP.NET Core中的筛选器允许代码在请求处理管道中的特定 ...

  10. WPF应用中一种比较完美的权限控制设计方式

    如题近段时间 需要在wpf应用中设计一个权限控制 , 简而言之的说 你懂的 对于IT人员来说都知道的 常见的软件功能 首先要有用户 用户,然后用户属于哪个角色 ,然后各个角色都有自己的可供操作的一堆功 ...