LoginSignup
9
9

More than 5 years have passed since last update.

Git HTTP サーバの作り方

Posted at

JVM系言語でGitサーバを作ろうとしたら、JGitのGitServerを使うと簡単ですが、Clojureの場合ringで動かしたいので、Servletだとちょっと扱いづらいところがあります。

そこで、GitServletを使わずにGit http サーバを作ってみます。

Gitの内側 - トランスファープロトコル にあるとおりのプロトコルを実装すればよいわけですが
、JGitを使えば簡単です。

例えば、git cloneを実行した時には、サーバへは以下の2回のHTTPリクエストがとびます。

GET /hoge.git/info/refs?service=git-upload-pack
POST /hoge.git/git-upload-pack

最初の info/refs はブランチの一覧を返します。
昔のgitクライアントからはservice=git-upload-packのパラメータが付いてきません。これはdumbクライアントと呼ばれています。現在のgitクライアントはsmartクライアントと呼ばれていて、dumbクライアントがリポジトリ下のinfo/refsファイルの内容をそのまま送信するのに対し、多少のヘッダ情報がついたりします。

そんな調子で、gitコマンドでやりとりされるURLを実装します。基本的にはJGitのメソッドを呼ぶだけです。

(defroutes git-routes
  (compojure/context ["/:name.git", :name #"[0-9A-Za-z\-\.]+"] {{repo-name :name} :params}
    (GET "/info/refs" {:as request}
      (get-info-refs (open-repo repo-name) request))
    (POST "/git-upload-pack" {:as request}
      (service-upload (open-repo repo-name) request))
    (POST "/git-receive-pack" {:as request}
      (service-receive (open-repo repo-name) request))
    (GET "/HEAD" {params :params}
      (get-text-file (open-repo repo-name) "HEAD"))
    (GET "/objects/info/alternates" []
      (get-text-file (open-repo repo-name) "objects/info/alternates"))
    (GET "/objects/info/http-alternates" []
      (get-text-file (open-repo repo-name) "objects/info/http-alternates"))
    (GET "/objects/info/packs" []
      (get-info-packs (open-repo repo-name)))
    (GET "/objects/info/*" {params :params}
      (get-text-file (open-repo repo-name) (str "objects/info/" (params :*))))
    (GET ["/objects/:hash2/:hash38", :hash2 #"[0-9a-f]{2}" :hash38 #"[0-9a-f]{38}"] [hash2 hash38]
      (get-loose-object (open-repo repo-name) (str "objects/" hash2 hash38)))
    (GET ["/objects/pack/:pack-file", :pack-file #"[0-9a-f]\.(pack|idx)"] [pack-file]
      (cond
        (. pack-file endsWith ".pack")
        (get-pack-file (open-repo repo-name) (str "objects/pack/" pack-file))
        (. pack-file endsWith ".idx")
        (get-idx-file  (open-repo repo-name) (str "objects/pack/" pack-file))))))

僅か171行で、GitServerが完成しました。
https://github.com/kawasima/gring/blob/master/src/gring/core.clj

簡単ですね。

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9