JGit实现Git Http服务器

/ Java / 没有评论 / 2783浏览

JGit实现Git Http服务器

使用过git的同学应该特别清楚github的http服务,今天就让我们学习一下如何通过JGit自己搭建一个自己的Git Http服务器吧。

Git协议

在使用Git的过程中,往往需要与其他人进行协作——也就是需要为本地的仓库设置远程(Remote)仓库。我们经常使用的pull/push/fetch操作,实际上都是与远程仓库进行的数据交互。Git支持4种传输协议:

GitHub是世界上最大的Git仓库托管系统,它支持后三种协议,通常我们如果想要从GitHub上获取代码,可以这样操作:

$ git clone https://github.com/jquery/jquery.git
Cloning into 'jquery'...
remote: Counting objects: 37065, done.
remote: Compressing objects: 100% (48/48), done.
remote: Total 37065 (delta 28), reused 0 (delta 0), pack-reused 37017
Receiving objects: 100% (37065/37065), 22.58 MiB | 709.00 KiB/s, done.
Resolving deltas: 100% (26132/26132), done.
Checking connectivity... done.

上例就是通过HTTP协议获取了GitHub服务器上的一个仓库,如果拥有仓库写权限,那么可以在本地修改提交后,push到GitHub服务器,push过程也是通过HTTP协议完成的。

Git HTTP服务器

为了支持客户端Git程序pull/push操作,GitHub服务器上运行着能够处理响应HTTP请求的应用程序。Git本身自带的应用程序git-http-backend可以处理这些HTTP请求,通过HTTP服务器(例如Nginx, Apache)我们可以很容易的架设一个Git HTTP服务器,详细方法可以参考

但是这样做的方法也有一定的局限性:

在本文中我们将以Git的一个纯Java实现为例,介绍如何在应用中嵌入JGit并实现一个Git HTTP服务器。

使用JGit实现Git HTTP服务器

JGit是Git的Java实现,它即提供了类似Git命令行工具的操作接口:

$ jgit clone https://github.com/jquery/jquery.git

也提供了非常友好的API,Java应用程序能够非常容易的引入它。同时它还提供一个HTTP Server模块能够方便的帮助我们建立HTTP服务器来提供Git仓库托管服务。

引入Maven依赖

<dependencies>
  <dependency>
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit.http.server</artifactId>
    <version>4.0.1.201506240215-r</version>
  </dependency>
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

实现处理HTTP请求的Servlet

org.eclipse.jgit.http.server模块提供的GitServlet类,实现了Git Smart HTTP Protocol

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

@WebServlet(name = "gitServlet", urlPatterns = {"/*"},
        loadOnStartup = 1,
        initParams = {
                @WebInitParam(name = "base-path", value = "/Users/luoruici/tmy-data/users/"),
                @WebInitParam(name = "export-all", value = "true")
        })
public class GitServlet extends org.eclipse.jgit.http.server.GitServlet {

}

这里扩展了org.eclipse.jgit.http.server.GitServlet实现一个最简单的Git HTTP服务器,无需配置。只需要指定两个参数:

另外,这里使用的是Servlet 3.0规范中的注解@WebServelt,并设置好urlPatterns

运行Git HTTP服务器

在编写完Servlet后,我们需要将它放在Servlet Container中运行。这里为了测试方便,引入(Maven Jetty Plugin):

<build>
  <plugins>
    <plugin>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-maven-plugin</artifactId>
      <version>9.3.1.v20150714</version>
    </plugin>
  </plugins>
</build>

在命令行中运行:

$ mvn jetty:run

过一会Jetty就启动起来了,假设现在在base-path参数对应的目录中包含一个仓库jquery.git,那么可以通过git clone http://localhost:8080/jquery.git来获取仓库了。

自定义仓库获取方式

在上例中使用的是GitServlet的默认行为来根据url获取仓库——将base-path与url中的path部分连接在一起,作为本地文件系统的访问路径获取一个Repository对象。但是业务系统很多时候并没有这么简单。以GitHub为例,url模式/{owner}/{repo}.git中的owner可能是一个个人用户,也可能是一个组织(organization),那么他们的仓库路径便不在文件系统的同一个目录中(仅仅是假设,并非GitHub的内部实现方式),那么这个时候我们需要扩展RepositoryResolver这个接口:

public class GitHttpResolver implements RepositoryResolver<HttpServletRequest> {
    Repository open(HttpServletRequest req, String name) 
        throws RepositoryNotFoundException,ServiceNotAuthorizedException,ServiceNotEnabledException,
    ServiceMayNotContinueException {
        //TODO: implement this method
    }
}

open方法描述了如何通过Request以及仓库的名字来获取一个需要serve出去的仓库对象Repository。同时还需要在GitServlet初始化时配置它使用改Resolver:

public class GitServlet extends org.eclipse.jgit.http.server.GitServlet {

    @Override
    public void init(ServletConfig config) throws ServletException {
        setRepositoryResolver(new GitHttpResolver());
    }
}

要获取本文的参考代码,请访问:< https://www.tianmaying.com/tutorial/jgit-http-server-guides/repo>