乐趣区

关于javascript:从零开始打造私服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 代码治理平台 [随心码]
开源地址 :https://github.com/lzuntalented/lz-git
示例网站:http://git.lzz.show/lz/lz-git

原理刨析

其实这些平台的实质是近程执行 git 命令,咱们在页面的操作或者本地执行 git 的命令,都是向远端服务器发送了申请,并附带申请内容,这些平台帮咱们在服务器执行 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…

  1. 向远端发送一个门路为 /info/refs?service=git-upload-pack 的 GET 申请,以获取远端仓库的援用信息
  2. http 服务承受到这个申请后,在远端仓库下执行命令git upload-pack --stateless-rpc --advertise-refs remote/repository/dir,并把命令输入作为 http 的响应返回给客户端
  3. 客户端发动门路为 /git-upload-pack 的 POST 申请,以获取远端资源
  4. http 服务承受到这个申请后,在远端仓库下执行命令git upload-pack --stateless-rpc remote/repository/dir,并把命令输入作为 http 的响应返回给客户端
  5. 至此命令执行结束

git push 命令执行时与 clone 命令流程相似,只是 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();
    }
};

最初

至此,咱们初步构建了一个基于 Javascript 开发的 git 代码治理平台,后续咱们持续向 Github 看齐并欠缺性能
如果您感觉这篇文章对您有用,欢送留一赞
也欢送给我的项目点⭐开源地址

历史我的项目

  • 【随心秀】开篇 – 开源微场景编辑器介绍
  • 从零开始 - 根底流程图编辑库
退出移动版