Git学习总结
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、Gitlab 系统
1、Gitlab架构
底层存储由三个组件负责:
①PostgreSQL:类似于mysql,存储业务数据,比如有哪些项目组,某个项目组下有哪些项目,某项目下哪些人有权限等等
②redis:用于缓存热点数据以及存储异步任务,sidekiq这组件会定期拉取分发异步任务给worker执行
③gitaly:存储底层代码文件,提供rpc接口对外提供git操作服务,Gitaly 从 gitlab-shell 和 GitLab web 应用程序执行 git 操作,并为 GitLab web 应用程序提供 API 以从 git 获取属性(例如 title,branches,tags,其他元数据)和 blob(例如 diffs,commits ,files)。
接入层由两个组件负责:
gitlab shell和gitlab workhorse,前者负责处理ssh请求,后者负责处理http/https请求
gitlab workhorse对于本地静态文件请求(例如浏览器请求的html、js、css文件)会自己处理掉,对于纯git操作请求会转发给gitaly,对于其他动态请求会转发给unicorn处理
unicorn就是gitlab的主server程序,它会调用其他各个组件完成复杂的动态请求处理
2、Log文件地址定位
Gitlab 系统Log文件位置:
/var/log/gitlab/
页面操作Log:/var/log/gitlab/gitlab-rails/production.log
同步代码Log:/var/log/gitlab/gitlab-rails/production.log
push代码Log:/var/log/gitlab/gitlab-rails/production.log
观察push日志信息,当客户端做出push操作
Started GET "/root/zykj.git/info/refs?service=git-receive-pack" for 192.168.43.1 at 2021-09-17 19:35:15 +0800
Processing by Repositories::GitHttpController#info_refs as */*
Parameters: {"service"=>"git-receive-pack", "namespace_id"=>"root", "repository_id"=>"zykj.git"}
Filter chain halted as :authenticate_user rendered or redirected
Completed 401 Unauthorized in 6ms (Views: 0.7ms | ActiveRecord: 0.9ms | Elasticsearch: 0.0ms | Allocations: 3294)
Started GET "/root/zykj.git/info/refs?service=git-receive-pack" for 192.168.43.1 at 2021-09-17 19:35:15 +0800
Processing by Repositories::GitHttpController#info_refs as */*
Parameters: {"service"=>"git-receive-pack", "namespace_id"=>"root", "repository_id"=>"zykj.git"}
Filter chain halted as :authenticate_user rendered or redirected
Completed 401 Unauthorized in 10ms (Views: 0.7ms | ActiveRecord: 1.3ms | Elasticsearch: 0.0ms | Allocations: 3254)
Started GET "/root/zykj.git/info/refs?service=git-receive-pack" for 192.168.43.1 at 2021-09-17 19:35:15 +0800
Processing by Repositories::GitHttpController#info_refs as */*
Parameters: {"service"=>"git-receive-pack", "namespace_id"=>"root", "repository_id"=>"zykj.git"}
Completed 200 OK in 81ms (Views: 0.2ms | ActiveRecord: 7.0ms | Elasticsearch: 0.0ms | Allocations: 10103)
Started POST "/root/zykj.git/git-receive-pack" for 192.168.43.1 at 2021-09-17 19:35:15 +0800
Processing by Repositories::GitHttpController#git_receive_pack as
Parameters: {"namespace_id"=>"root", "repository_id"=>"zykj.git"}
Completed 200 OK in 75ms (Views: 0.9ms | ActiveRecord: 4.5ms | Elasticsearch: 0.0ms | Allocations: 9414)
Started POST "/api/v4/internal/allowed" for 127.0.0.1 at 2021-09-17 19:35:15 +0800
Started POST "/api/v4/internal/pre_receive" for 127.0.0.1 at 2021-09-17 19:35:15 +0800
Started POST "/api/v4/internal/post_receive" for 127.0.0.1 at 2021-09-17 19:35:15 +0800
Started GET "/-/metrics" for 127.0.0.1 at 2021-09-17 19:35:26 +0800
3、git-receive-pack和传输协议分析(HttpS)
git-receive-pack官方链接
从上可以观察到其对 "/root/zykj.git/info/refs?service=git-receive-pack"发送了get请求
查阅官网可发现。为了上传数据至远端,Git 使用 send-pack 和 receive-pack 进程。 运行在客户端上的 send-pack 进程连接到远端运行的 receive-pack 进程。
客户端会向服务端发送第一次数据交换的请求
由此上图顺序知,git服务器会先通过receive-pack 进程获取到push的信息,
然后再触发钩子函数 Started POST "/api/v4/internal/pre_receive"
上传过程在 HTTP 上几乎是相同的,除了握手阶段有一点小区别。 连接是从下面这个请求开始的:
=> GET http://server/simplegit-progit.git/info/refs?service=git-receive-pack
001f# service=git-receive-pack
00ab6c5f0e45abd7832bf23074a333f739977c9e8188 refs/heads/master report-status \
delete-refs side-band-64k quiet ofs-delta \
agent=git/2:2.1.1~vmg-bitmaps-bugaloo-608-g116744e
0000
这完成了客户端和服务端的第一次数据交换。 接下来客户端发起另一个请求,这次是一个 POST 请求,这个请求中包含了 send-pack 提供的数据。
=> POST http://server/simplegit-progit.git/git-receive-pack
这个 POST 请求的内容是 send-pack 的输出和相应的包文件。 服务端在收到请求后相应地作出成功或失败的 HTTP 响应。
HTTP 协议有可能会进一步用分块传输编码将数据包裹起来。
4、gitlab hook
具体参考git官网
本文只分析服务器的钩子操作
3.1 pre-receive
处理来自客户端的推送操作时,最先被调用的脚本是 pre-receive。 它从标准输入获取一系列被推送的引用。如果它以非零值退出,所有的推送内容都不会被接受。 你可以用这个钩子阻止对引用进行非快进(non-fast-forward)的更新,或者对该推送所修改的所有引用和文件进行访问控制。
3.2 update
update 脚本和 pre-receive 脚本十分类似,不同之处在于它会为每一个准备更新的分支各运行一次。 假如推送者同时向多个分支推送内容,pre-receive 只运行一次,相比之下 update 则会为每一个被推送的分支各运行一次。 它不会从标准输入读取内容,而是接受三个参数:引用的名字(分支),推送前的引用指向的内容的 SHA-1 值,以及用户准备推送的内容的 SHA-1 值。 如果 update 脚本以非零值退出,只有相应的那一个引用会被拒绝;其余的依然会被更新。
3.3 post-receive
post-receive 挂钩在整个过程完结以后运行,可以用来更新其他系统服务或者通知用户。 它接受与 pre-receive 相同的标准输入数据。 它的用途包括给某个邮件列表发信,通知持续集成(continous integration)的服务器, 或者更新问题追踪系统(ticket-tracking system) —— 甚至可以通过分析提交信息来决定某个问题(ticket)是否应该被开启,修改或者关闭。 该脚本无法终止推送进程,不过客户端在它结束运行之前将保持连接状态, 所以如果你想做其他操作需谨慎使用它,因为它将耗费你很长的一段时间。
3.4 服务端Hook使用
配置钩子参考 Server hooks
1:修改配置,并创建一个“全局”的pre-recevie勾子
1: 进入安装目录下
cd /opt/gitlab/embedded/service/gitlab-shell/hooks
#
2: 创建pre-receive.d, post-receive.d, or update.d 子目录。
3: 在子目录中创建脚本文件(如pre-receive)
chmod 777 pre-recevie
# 4: 执行gitlab reconfigure
sudo gitlab-ctl reconfigure
**2:编写脚本此处示例 可以获取到的信息
#!/bin/sh
path="${GIT_ALTERNATE_OBJECT_DIRECTORIES/%'/objects'/}"
read normalInput
ARR=($normalInput)
parentCommitId=${ARR[0]}
currentCommitId=${ARR[1]}
branch=${ARR[2]#refs/heads/}
echo "parentCommitId : $parentCommitId"
echo "branch: $branch"
echo "currentCommitId: $currentCommitId"
echo "$GL_USERNAME"
echo "$GL_REPOSITORY"
echo "$GL_ID"
echo "$GIT_ALTERNATE_OBJECT_DIRECTORIES"
echo "$GIT_OBJECT_DIRECTORY"
echo "GL-HOOK-ERR:???"
exit 1
从事倒下分别对应
远程仓库的最新commitid
远程仓库的分支(不存在则创建)
本地push分支的最新commitid
剩下参考参数
具体参考官方环境变量
之后就可以根据自己的需要编写脚本了!
二、Git底层原理
1.状态模型
图源自网络
上图描述了 git 对象的在不同的生命周期中不同的存储位置,通过不同的 git 命令改变 git 对象的存储生命周期。
工作区 (workspace)
就是我们当前工作空间,也就是我们当前能在本地文件夹下面看到的文件结构。初始化工作空间或者工作空间 clean 的时候,文件内容和 index 暂存区是一致的,随着修改,工作区文件在没有 add 到暂存区时候,工作区将和暂存区是不一致的。
暂存区 (index)
老版本概念也叫 Cache 区,就是文件暂时存放的地方,所有暂时存放在暂存区中的文件将随着一个 commit 一起提交到 local repository 此时 local repository 里面文件将完全被暂存区所取代。暂存区是 git 架构设计中非常重要和难理解的一部分。
本地仓库 (local repository)
git 是分布式版本控制系统,和其他版本控制系统不同的是他可以完全去中心化工作,你可以不用和*服务器 (remote server) 进行通信,在本地即可进行全部离线操作,包括 log,history,commit,diff 等等。完成离线操作最核心是因为 git 有一个几乎和远程一样的本地仓库,所有本地离线操作都可以在本地完成,等需要的时候再和远程服务进行交互。
远程仓库 (remote repository)
中心化仓库,所有人共享,本地仓库会需要和远程仓库进行交互,也就能将其他所有人内容更新到本地仓库把自己内容上传分享给其他人。结构大体和本地仓库一样。
文件在不同的操作下可能处于不同的 git 生命周期
2.仓库结构
图源自https://baijiahao.baidu.com/s?id=1667252872528095554&wfr=spider&for=pc
3.Git对象类型
Git中有四种基本对象类型,组成了Git更高级的数据结构:
1:blobs
每个blob代表一个(版本的)文件,blob只包含文件的数据,而忽略文件的其他元数据,如名字、路径、格式等。
2:trees
每个tree代表了一个目录的信息,包含了此目录下的blobs,子目录(对应于子trees),文件名、路径等元数据。因此,对于有子目录的目录,git相当于存储了嵌套的trees。
3:commits
每个commit记录了提交一个更新的所有元数据,如指向的tree,父commit,作者、提交者、提交日期、提交日志等。每次提交都指向一个tree对象,记录了当次提交时的目录信息。一个commit可以有多个(至少一个)父commits。
4:tags
tag用于给某个上述类型的对象指配一个便于开发者记忆的名字, 通常用于某次commit。
如图对应各对象关系,这就是开始时 Git 存储内容的方式——一个文件对应一条内容, 以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名。 校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名。
详细解释如下:
$ find .git/objects -type f
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
找到其hash地址
一旦你将内容存储在了对象数据库中,那么可以通过 cat-file 命令从 Git 那里取回数据。 为 cat-file 指定 -p 选项可指示该命令自动判断内容的类型,并为我们显示大致的内容:
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content
详细可看Git官网
4.Git常用命令底层原理
1.Git add
在调用git add后多了两个文件夹,一个是index,一个是8d
index目录存放这文件名的信息(如下图所示100644 100代表文件类型 644代表只有拥有者有读写权限)
objects目录存了文件的通过hash算法后得到的hash值
2.Git commit 后原理
如果是第一次提交,会出现root-commit
git commit后 object文件夹出现了一个tree对象和commit对象
3.Git Branch 后原理
当git branch 创建分支后,refs文件夹下的heads会出现以新分支命名的文件。
该文件存储着在某分支下执行该命令的某分支的commit的hash信息。
Head指针永远指向最新的commit hash地址
3.Git Merge 后原理
合并分为fast forward和3 way merge
1:fast forward
合并前状态如上图
合并后状态如下图
merge之后,改变了master指针的位置,master指针指向了C3
并且仓库架构中多了一个ORIG_HEAD文件
5. Git保存版本控制
总结
简单介绍了下Git 和Gitlab