深入理解Git内部原理
前言
当我们执行git init命令,或者clone网上某个代码仓库后,会看到有一个.git目录,git所有版本控制信息就是放在目录里面,下面对这个.git目录进行分析。
.git目录
-
hooks:钩子目录,存放执行指定git命令前或者后触发的脚本,可以看到默认会有几个sample文件,如果要开启某个钩子脚本,就把脚本文件名的后缀simple去掉就可以,这些钩子会在特定的时机被触发执行,比如post-commit在整个提交过程完成后执行,可以用于发送提交通知等,另外也有服务端钩子,在推送前或者后执行,比如post-receive在推送结束后会被执行,可以用于通知打包平台启动打包任务。关于git钩子更详细的信息可以参考:自定义 Git - Git 钩子。
-
info:保存git的相关信息
-
logs
-
refs:暂存记录,本地分支记录,远程分支记录
-
HEAD:记录每次的变更操作
-
-
objects:存放真实数据,以Git对象形式存放
-
refs
-
heads:存放所有本地分支最新的commit哈希值
-
stash:存放stash对应的哈希值
-
tags:存放tags相关的
-
-
config:配置文件
-
HEAD:当前分支,并不存放SHA1值,类似/refs/heads/master,这个指向的文件里会有最新commit的SHA1值
-
index:二进制文件,暂存区
Git中的几种对象
-
数据对象
数据对象就是用于存储真实的文件数据,其创建过程如下:
-
计算内容大小,构造header
-
将header添加到内容前面,构造数据对象
-
使用sha1算法计算Git对象的160位hash码,表示成16进制就是40位
-
使用zlib的deflate算法压缩数据对象
-
存储到.git/objectes/目录下,文件夹名为hash码的前两位,文件名为hash码的后38位
-
-
tree对象
保存目录信息,也就是目录树的非叶子节点的版本控制信息,需要从暂存区中创建。
-
commit对象
保存某次提交的详细信息,包括时间、提交人等。
-
tag对象
跟commit对象类似,包含了一个指针,该指针指向一个commit对象,而且永远不会改变。
Git提交过程原理
-
添加到暂存区:git add xxx
-
创建数据对象
-
更新index文件
-
-
提交:git commit -m "xxxx"
-
如果存在目录,就创建tree对象
-
创建commit对象
-
-
将上面创建的对象保存为目录和文件
可以看到,git提交的整个过程,其实就是创建数据对象、tree对象和commit对象的过程,最终这些对象都会保存到objects目录下。
Git数据存储原理
Git默认采用的是松散对象格式,也就是每次保存一份完整数据,比如有个大文件10MB,第一次提交被保存起来了,后面修改了一点东西又提交,这时Git会保存两个10Mb的对象数据,这样看起来就会比较浪费,最好是能够只保存文件的差异部分。
实际上Git就是这样做的,如果存在太多的松散对象,或者执行了push命令,或者git gc命令,Git就会将松散对象进行打包到一个pack文件中,该文件保存文件不同版本之间的差异内容,减少了存储占用,而且是该pack文件是二进制文件,需要采用命令git verify-pack查看。
注意这里pack会将最新版本保存为完整对象,而之前的版本保存差异信息,因为大部分情况下访问的都会是最新版本。
Git传输协议
Git有四种传输协议,包括本地协议、HTTP协议,SSH协议,GIT协议。
-
本地协议
远程仓库就存放在硬盘中,这里的硬盘,可以是远程挂载的网络硬盘,远程仓库的地址直接指定为目录路径,也可以加上file前缀。不过共享文件系统配置起来比较麻烦,速度也比较慢。
-
HTTP协议
采用http/https协议进行传输,这里细分有两种协议:哑协议和智能协议,哑协议是Git 1.6.6版本之前使用的协议,Git 1.6.6引入了智能协议。
-
哑协议
-
获取info/refs文件,确定所有分支的最新commit的SHA1值
-
获取HEAD文件,确定当前分支,检出到工作目录
-
获取第一个commit对象的数据
-
往上追溯,获取所有对象数据
-
-
智能协议(大部分使用)
不管是上传(比如push等)还是下载(比如pull等),都是客户端开一个进程,服务端开一个进程,然后协商需要传输的数据,确认好哪些数据需要传输,进程端口是http或者https端口。
HTTP协议的优点:1.就是使用方便,只需要一个远程地址即可,2.认证方便,直接输用户名密码,不需要像SSH首次配置那么麻烦。
-
-
SSH协议
使用ssh协议做为传输协议,使用时需要配置ssh信息,配置后就不用每次都输入用户名和密码了。
-
Git协议
与http智能协议原理类似,但它监听的端口是9418,Git协议没有授权机制,也就是不能实现控制一部分人能push,另一部分不能push,因此大部分情况的做法是让Git协议只开放读取,禁止推送。
git flow协作流程
稳定分支
-
develop:开发分支
-
master:发布分支
临时分支
-
feature:特性分支,用于临时开发新功能,从develop拉,最终合入到develop。
-
release:预发布分支,当develop分支开发完本版本需求后,就拉release分支,用于修bug,配置发布信息等,这时develop分支继续开发下一版本的需求。当release分支修改结束后,就合入develop和master。注意合入到master时要打tag做标记,比如master_8.1之类的命名。
-
hotfix:修复分支,用于修复线上紧急bug,从master拉,最终合入到develop和master。注意合入到master时要打tag做标记,比如master-8.1.1之类的命名。
转载自:https://juejin.cn/post/6844904015495430151