Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What is going on with this article?
@kawasima

Git HTTP サーバの作り方

More than 5 years have passed since last update.

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

簡単ですね。

10
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kawasima
Clojure関連のことをブログがわりに書き綴ります。 ※ここでの発言はシステムエンジニアを代表するものであって、所属する組織は二の次です。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
10
Help us understand the problem. What is going on with this article?