Git 内部工作原理

Git 本质上是一个内容寻址文件系统,最初是一套面向版本控制系统的工具集,而不是一个完整的用户友好的版本控制系统。因此它还包含了一些用于完成底层工作的命令,这些命令被称为“底层命令”,而那些更友好的命令则被当作“高层命令”来使用。

Git 目录

当执行 git init 操作时会生成一个 .git 目录


这是一个全新的 git init 目录,这个目录后续可能还会添加其他文件。其中description文件仅供 GitWeb 程序使用,我们无需关心,info 包含全局性排除文件,用来放置那些不希望被记录在 .ignore中的忽略模式。hooks 放置钩子脚本。

config

Git 自带一个 git config工具来控制设置 git 外观和行为的配置变量,这些变量存储在三个不同的位置。

1. ./etc/git config 包含系统上每个用户及其仓库的通用配置。

git  config --system 命令会从此位置读取配置变量。

2. ~/.gitconfig 或 ~/.config/git/config:只针对当前用户

git config --global 命令会从此位置读取配置变量

3. 当前使用仓库的 .git 目录中的 config 文件:只针对该仓库,一些分支的信息和远端仓库的信息以及 fetch,push操作的信息都有保存。

Objects(对象):保存所有数据内容

刚刚我们提到,git 是一个内容寻址文件系统,那么什么是内容寻址文件系统呢?其实 git 的核心部分是一个键值对数据库,它的值可以存储任何数据类型的内容,这个值对应返回一个键,通过这个键可以检索对应的内容。

接下来我们通过实验,来看看 git 在 add 和 commit 的过程中都做了什么

1.创建一个全新的 git 仓库

2.在仓库中添加一个文件,并执行 add 操作

此时我们可以在 objects 目录下看到多了一个文件夹

文件夹里面的东西是很么呢?

其实这就是执行 git add 命令后生成的一个对象,git将对象的 hash 值的前两位 8d 作为文件夹名,其余38位作为文件名保存。

我们可以通过 git cat-file 命令可以从对象中取出数据:

git cat-file -p 8d0e41234f24b6da002d962a26c2495ea16a425f

控制台输出了 hello git,而文件 test.txt 中的内容正是 "hello git"

这个对象就是 git objects 中的数据对象 (blob object) ,我们可以用:

git cat-file -t 8d0e41234f24b6da002d962a26c2495ea16a425f 命令查看对象类型

接下来我们继续 git commit 操作,

可以看到提交后又生成了两个对象。

我们分别来看一下这两个对象的内容,

里面保存的是 blob 对象 hash 值,文件名称。

查看它的类型可以看到控制台返回了 tree,这就是 git 对象中的树对象 (tree object)

如果我们多提交几次,大致就可以看到里面的内容其实是一个树形结构,

再来看看另一个对象,

这个对象中的格式也很简单,它首先指定顶层树对象,代表当前项目快照,然后是作者信息和提交者信息,留一行空,接着是提交描述信息。

查看他的类型是 commit,这个对象其实就是提交对象 (commit object)。

如果我们多进行几次提交,将看到 .git/logs/HEAD 文件保存这样的内容

这个 HEAD 文件保存的是当前分支下的快照,里面记录了当前分支中的提交记录,我们可以发现每一行代表一个提交记录,后一个 commit 持有前一个 commit 的 hash 值,以此形成了一个链表结构。

以上我们所看到的就是 git 执行 add 和 commit 的实质工作,将被改写的文件保存为数据对象,更新暂存区,记录树对象,最后创建一个指明了顶层树对象和父提交的提交对象。

Refs(引用):保存指向分支的提交对象的指针

Refs 相当于最后一个提交的 commit hash 的一个别名,因为我们可以执行类似 git log 8d0e412来查看完整的提交历史,但是遍历那段历史从而找到相关对象,我们需要记住最后一个提交的 hash 值,git将这个 hash 值用文件保存起来,并给文件取一个简单的名字,用这个名字指针指向原始的 hash 值。

git 分支的本质其实基本上就是一个指向某一系列提交之首的指针或引用。

我们通过 git log --pretty=oneline master 命令查看到 master 分支下的提交记录

现在你若想在第二个提交上创建一个分支可这么做:

当我们用类似于 git branch <branchname> 的命令时,git 底层执行的是 update-ref 命令,取得当前所在分支最新提交的 hash 值,然后将其加入到我们创建的新引用中。这也是 git 创建分支比 svn 快得多的原因,git 创建一个分支只需要创建一个引用的时间。

refs 目录下包含 heads,tags,remotes 目录;

heads 目录:定义所有的本地引用;

tags 目录:标签引用;

remotes 目录:远程引用;

远程分支引用和本地分支引用最大的区别在于远程分支引用是只读的,虽然可以用 git checkout 到某个远程引用,但是 head 指针并不会指到远程引用上去,git 只是将这些远程引用作为指向远程仓库中最后一次提交的书签来管理。

Index:保存暂存区信息

HEAD:指向当前被检出的分支

我们发现这个引用和别的引用不一样,实际上他是指向其他引用的一个指针。当我们执行 git checkout  <branchName> 命令时,实际上是将 HEAD 文件中的引用改为了需要检出分支的引用。

总结

以上就是我所学习的 Git 进阶全部内容,因为 Git 还有很多其他操作,此处无法穷举。如果真的要完全理解 Git 的原理还是要在实际工作中多操作练习。

Git 内部工作原理

Git 本质上是一个内容寻址文件系统,最初是一套面向版本控制系统的工具集,而不是一个完整的用户友好的版本控制系统。因此它还包含了一些用于完成底层工作的命令,这些命令被称为“底层命令”,而那些更友好的命令则被当作“高层命令”来使用。

Git 目录

当执行 git init 操作时会生成一个 .git 目录


这是一个全新的 git init 目录,这个目录后续可能还会添加其他文件。其中description文件仅供 GitWeb 程序使用,我们无需关心,info 包含全局性排除文件,用来放置那些不希望被记录在 .ignore中的忽略模式。hooks 放置钩子脚本。

config

Git 自带一个 git config工具来控制设置 git 外观和行为的配置变量,这些变量存储在三个不同的位置。

1. ./etc/git config 包含系统上每个用户及其仓库的通用配置。

git  config --system 命令会从此位置读取配置变量。

2. ~/.gitconfig 或 ~/.config/git/config:只针对当前用户

git config --global 命令会从此位置读取配置变量

3. 当前使用仓库的 .git 目录中的 config 文件:只针对该仓库,一些分支的信息和远端仓库的信息以及 fetch,push操作的信息都有保存。

Objects(对象):保存所有数据内容

刚刚我们提到,git 是一个内容寻址文件系统,那么什么是内容寻址文件系统呢?其实 git 的核心部分是一个键值对数据库,它的值可以存储任何数据类型的内容,这个值对应返回一个键,通过这个键可以检索对应的内容。

接下来我们通过实验,来看看 git 在 add 和 commit 的过程中都做了什么

1.创建一个全新的 git 仓库

2.在仓库中添加一个文件,并执行 add 操作

此时我们可以在 objects 目录下看到多了一个文件夹

文件夹里面的东西是很么呢?

其实这就是执行 git add 命令后生成的一个对象,git将对象的 hash 值的前两位 8d 作为文件夹名,其余38位作为文件名保存。

我们可以通过 git cat-file 命令可以从对象中取出数据:

git cat-file -p 8d0e41234f24b6da002d962a26c2495ea16a425f

控制台输出了 hello git,而文件 test.txt 中的内容正是 "hello git"

这个对象就是 git objects 中的数据对象 (blob object) ,我们可以用:

git cat-file -t 8d0e41234f24b6da002d962a26c2495ea16a425f 命令查看对象类型

接下来我们继续 git commit 操作,

可以看到提交后又生成了两个对象。

我们分别来看一下这两个对象的内容,

里面保存的是 blob 对象 hash 值,文件名称。

查看它的类型可以看到控制台返回了 tree,这就是 git 对象中的树对象 (tree object)

如果我们多提交几次,大致就可以看到里面的内容其实是一个树形结构,

再来看看另一个对象,

这个对象中的格式也很简单,它首先指定顶层树对象,代表当前项目快照,然后是作者信息和提交者信息,留一行空,接着是提交描述信息。

查看他的类型是 commit,这个对象其实就是提交对象 (commit object)。

如果我们多进行几次提交,将看到 .git/logs/HEAD 文件保存这样的内容

这个 HEAD 文件保存的是当前分支下的快照,里面记录了当前分支中的提交记录,我们可以发现每一行代表一个提交记录,后一个 commit 持有前一个 commit 的 hash 值,以此形成了一个链表结构。

以上我们所看到的就是 git 执行 add 和 commit 的实质工作,将被改写的文件保存为数据对象,更新暂存区,记录树对象,最后创建一个指明了顶层树对象和父提交的提交对象。

Refs(引用):保存指向分支的提交对象的指针

Refs 相当于最后一个提交的 commit hash 的一个别名,因为我们可以执行类似 git log 8d0e412来查看完整的提交历史,但是遍历那段历史从而找到相关对象,我们需要记住最后一个提交的 hash 值,git将这个 hash 值用文件保存起来,并给文件取一个简单的名字,用这个名字指针指向原始的 hash 值。

git 分支的本质其实基本上就是一个指向某一系列提交之首的指针或引用。

我们通过 git log --pretty=oneline master 命令查看到 master 分支下的提交记录

现在你若想在第二个提交上创建一个分支可这么做:

当我们用类似于 git branch <branchname> 的命令时,git 底层执行的是 update-ref 命令,取得当前所在分支最新提交的 hash 值,然后将其加入到我们创建的新引用中。这也是 git 创建分支比 svn 快得多的原因,git 创建一个分支只需要创建一个引用的时间。

refs 目录下包含 heads,tags,remotes 目录;

heads 目录:定义所有的本地引用;

tags 目录:标签引用;

remotes 目录:远程引用;

远程分支引用和本地分支引用最大的区别在于远程分支引用是只读的,虽然可以用 git checkout 到某个远程引用,但是 head 指针并不会指到远程引用上去,git 只是将这些远程引用作为指向远程仓库中最后一次提交的书签来管理。

Index:保存暂存区信息

HEAD:指向当前被检出的分支

我们发现这个引用和别的引用不一样,实际上他是指向其他引用的一个指针。当我们执行 git checkout  <branchName> 命令时,实际上是将 HEAD 文件中的引用改为了需要检出分支的引用。

总结

以上就是我所学习的 Git 进阶全部内容,因为 Git 还有很多其他操作,此处无法穷举。如果真的要完全理解 Git 的原理还是要在实际工作中多操作练习。

git使用下的更多相关文章

  1. Git bash下中文乱码问题

    Git bash下中文乱码--解决方案 解决办法1: 在git bash下,右键 出现下图,选择options: 选择"Text" 将Character set设置为 UTF-8 ...

  2. 记一次小团队Git实践(下)

    在上篇中,我们已经能基本使用git了,接下来继续更深入的挖掘一下git. 更多的配置自定义信息 除了前面讲的用户名和邮箱的配置,还可以自定义其他配置: # 自定义你喜欢的编辑器,可选 git conf ...

  3. gradle 及 git 环境下利用hook及gradle脚本自动添加versioncode和versionname的方法

    在 app/build.gradle 文件里添加几行代码: def gitCommitShortHash = 'git log -1 --pretty=%h'.execute([], project. ...

  4. 【前端工具】 git windows下搭建全过程

    1. Git,Windows下的Git,地址:http://msysgit.googlecode.com/files/Git-1.7.9-preview20120201.exe(方便下载) 2 .SS ...

  5. git clone下代码window与unix换行问题

    项目中避免不了会写一些shell脚本,使用ln软连接到一个目录.当git clone到windows中,ln连接显示无比怪异(如../xx),打开.sh文件后(仅仅是打开了),git status会看 ...

  6. K8S 如何实现将git代码下拉到指定的容器路径中

    gitRepo 是 kubernetes Volume类型中的一种,gitRepo volume可以实现将git代码下拉到指定的容器路径中. 备注:实现此功能,Pod运行的节点都必需要安装git.换句 ...

  7. 初学者在ubuntu下安装使用git(下)

    4.将代码传到oschina上去 之前已经将git配置完成了,现在通过ssh的方式访问资源库,先要用命令 ssh-keygen –C '你的邮箱' –t rsa .这样就会在ssh文件夹下建一相应的密 ...

  8. Android Studio开发第四篇版本管理Git(下)

    前面一片介绍了在as下如何关联远程仓库,这篇就介绍在开发过程中怎么应用. 提交+Push 如果本地开发代码有改动了或者你觉得某功能做完了,你打算把改动代码提交到远程仓库,这个时候很简单, 还是在工具栏 ...

  9. Git Bash下实现复制粘贴等快速编辑功能

    在windows下使用Git Bash会经常用到选中.复制.粘贴等功能,但是一般用的方法会很复杂,笔者经过查阅一些资料,特整理一些常见编辑功能的实现方法. (1)默认方法: 单击左上角的logo ic ...

  10. Git 使用问题 - win7 git bash下git pull失败

    win7 旗舰版,从github上pull代码时,git bash命令出现错误 Administrator@rust-PC /g/rust_proj/cardslib (master) $ git - ...

随机推荐

  1. C#中From窗体判断提示框是否

    int ret(变量名1) = command.ExecuteNonQuery(); if (ret(变量名1) > 0)//判断变量名是否大于0 { DialogResult dr(变量名2) ...

  2. XOR性质

    异或XOR的性质: 1. 交换律 2. 结合律 3. x^x = 0 -> 偶数个异或为0 4. x^0 = x -> 奇数个异或为本身 5. 自反性:a^b^b = a^0 =a

  3. JZOJ【NOIP2012模拟8.9】2020.10.5 T1

    逐个击破 题目 Description 三大战役的平津战场上,傅作义集团在以北平.天津为中心,东起唐山西至张家口的铁路线上摆起子一字长蛇阵,并企图在溃败时从海上南逃或向西逃窜.为了就地歼敌不让其逃走, ...

  4. 欢迎使用CSDN-markdown编辑器(这个只能看到一次保存一下)

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接 ...

  5. springsecurity实现前后端分离之jwt-资料收集

    https://www.jianshu.com/p/5b9f1f4de88d https://www.jianshu.com/p/725d32ab92f8 https://blog.csdn.net/ ...

  6. moviepy用VideoFileClip加载视频时报UnicodeDecodeError: codec cant decode ,No mapping character 错误

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 昨天处理视频时出现了解码错误,通过修改ffmpeg ...

  7. 第7.22节 Python中使用super调用父类的方法

    第7.22节 Python中使用super调用父类的方法 前面章节很多地方都引入了super方法,这个方法就是访问超类这个类对象的.由于super方法的特殊性,本节单独谈一谈super方法. 一.su ...

  8. PyQt(Python+Qt)学习随笔:QDockWidget停靠窗相关的信号

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 QDockWidget的信号包括与属性变更相关的allowedArea ...

  9. 第15.1节 PyCharm安装及使用

    一. 引言 在本章以前,所有老猿实现的代码都是基于Python自带的解释器IDLE来开发和执行的,很方便.消耗少,但进入PyQt图形界面开发以后,IDLE不能实现和PyQt的集成,且不能支持断点调试, ...

  10. PyQt(Python+Qt)学习随笔:键盘焦点和逻辑焦点(Logic Focus与Keyboard Focus )

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 Qt中的焦点有键盘焦点和逻辑焦点(Logic Focus与Keyboard Focus )的区分,键 ...