从零开始打造私服GitHub
文章图片
背景
你是否好奇类github平台式代码管理平台背后的运作原理,下面我们一起探究并着手开发属于自己的GitHub市面上可供我们部署私人git服务的开源项目有以下几种
项目 | 开发语言 | 地址 |
---|---|---|
gitlab | ruby | https://gitlab.com/gitlab-org... |
gogs | go | https://github.com/gogs/gogs |
gitea | go | https://github.com/go-gitea/g... |
下面是我在使用这些项目搭建私人git服务时遇到的问题项目
- gitlab对机器性能有一定要求,像树莓派(
我的4b[4G]
)这种系统安装后,经常会卡死机,安装要求详见:https://docs.gitlab.cn/jh/ins...- gogs运行对机器性能要求不高,但是基于go语言开发的,作为前端开发者不利于二次功能扩展
- gitea是基于gogs的开发的
本着对技术的探究精神和重复造轮子的热情,于是着手打造一个对前端开发者友好的git代码管理平台原理刨析 其实这些平台的本质是远程执行git命令,我们在页面的操作或者本地执行git的命令,都是向远端服务器发送了请求,并附带请求内容,这些平台帮我们在服务器执行git命令[随心码]
开源地址:https://github.com/lzuntalented/lz-git
示例网站:http://git.lzz.show/lz/lz-git
例如:当我们在页面上创建一个项目时,实际就是在服务器上执行了
git init
命令如果你安装了git,通过命令
git clone dir
(dir指本地任意git项目的目录路径)克隆一个仓库,在dir
目录下中可以进行git
的所有命令操作实现 技术
项目结构:lerna
前端:Typescript + react + antd
后端:Nestjs + mysql
项目架构
文章图片
创建项目
我们可以通过命令
git init --bare [repositories]
创建一个空仓库,在多人协作时,当作仓库中心 例如创建一个
blog
仓库,执行命令git init --bare blog.git
在服务器上不需要存储工作目录,通过
--bare
参数创建一个空的仓库(如下图上方的红色框内容) 我们平时在克隆项目时,本地目录下会多一个
.git
隐藏目录,通过--bare
参数创建的仓库没有.git
目录,而是直接把.git
目录下的内容展开在当前仓库目录下,同时不会有工作文件文章图片
可以观察到我们在仓库名后面加了
.git
,这个其实没太多含义,只是表示是git仓库而已,像我们从GitHub上克隆项目时可以发现,他们提供的克隆地址也是带.git,为了相同而已拉取和推送代码
因为要部署在远端服务器,无法通过克隆dir的方式,所以我们使用http模式的克隆方式
# 体验示例站点克隆项目功能
git clone http://git.lzz.show/lz/lz-git.git
那我们在执行
git clone
命令时发生了什么事情呐,参见:https://git-scm.com/docs/http...git push命令执行时与clone命令流程类似,只是
- 向远端发送一个路径为
/info/refs?service=git-upload-pack
的GET请求,以获取远端仓库的引用信息- http服务接受到这个请求后,在远端仓库下执行命令
git upload-pack --stateless-rpc --advertise-refs remote/repository/dir
,并把命令输出作为http的响应返回给客户端- 客户端发起路径为
/git-upload-pack
的POST请求,以获取远端资源- http服务接受到这个请求后,在远端仓库下执行命令
git upload-pack --stateless-rpc remote/repository/dir
,并把命令输出作为http的响应返回给客户端- 至此命令执行完毕
service
参数由git-upload-pack
变成git-receive-pack
,git命令参数由upload-pack
变为receive-pack
问题记录
由于git发起的http请求header中Content-Type为非规范头,express无法自动解析请求体里的body,需要我们自定义中间件以解析body
export function header(req: Request, res: Response, next: NextFunction) {
if (req.header('Content-Type'.toLowerCase()) === 'application/x-git-upload-pack-request'
|| req.header('Content-Type'.toLowerCase()) === 'application/x-git-receive-pack-request'
) {
const body = [];
req.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
// body转换成buffer格式利于将body内容作为输入传入git命令中
req.body = Buffer.concat(body);
next();
});
} else {
next();
}
};
最后 【从零开始打造私服GitHub】至此,我们初步构建了一个基于Javascript开发的git代码管理平台,后续我们继续向Github看齐并完善功能
如果您觉得这篇文章对您有用,欢迎留一赞
也欢迎给项目点?开源地址
历史项目
- 【随心秀】开篇 - 开源微场景编辑器介绍
- 从零开始-基础流程图编辑库
推荐阅读
- 腾讯|从“优化”、“向社会输送人才”到“毕业”!互联网的高情商裁员
- c语言|《伏C录》破劫篇-零基础无境界限制极速领悟指针与数组
- java如何从linux服务器下载文件
- 技术分享|字节8年测试经验,从功能测试到自动化测试,我整理了这一份2000字进阶学习指南
- MySQL实现配置主从复制项目实践
- 数据结构与java集合|java集合图解源码系列【4】(从HashMap讲到红黑树和哈希表)
- java|spring boot报错org.springframework.context.ApplicationContextException:Unable to start Embedded
- 数据库|MySQL 配置主从复制实践
- 数据库|MySQL 主从复制原理
- IT去中心化背后的低代码平台