0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Node.jsで“それっぽいGitサーバ”を自作してみた(※動くとは言ってない)

0
Posted at

はじめに

Gitサーバを理解しようとして、気づいたら「それっぽいHTTPサーバ」を作っていた話です。
完全なGit互換ではありませんが、Gitの通信の雰囲気を掴む目的ではかなり学びがありました。


作ったもの

Node.jsのhttpモジュールを使って、以下のようなGitっぽいエンドポイントを再現しています:

  • /info/refs
  • /HEAD
  • /refs
  • /objects
  • /git-upload-pack

実装コード

const http = require("http");

const PORT = 8000;

function send(res, status, headers, body) {
  res.writeHead(status, headers);
  res.end(body);
}

function gitInfoRefs(service) {
  return (
    "001e# service=git-upload-pack\n" +
    "0000"
  );
}

function fakePack() {
  return Buffer.from("PACKfakepackfiledata");
}

const server = http.createServer((req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);
  const path = url.pathname;

  if (path === "/user/repo.git/info/refs") {
    const service = url.searchParams.get("service") || "git-upload-pack";
    return send(res, 200, {
      "Content-Type": `application/x-${service}-advertisement`,
      "Cache-Control": "no-cache",
    }, gitInfoRefs(service));
  }

  if (path === "/user/repo.git/HEAD") {
    return send(res, 200, {
      "Content-Type": "text/plain",
    }, "ref: refs/heads/main\n");
  }

  if (path.startsWith("/user/repo.git/refs")) {
    return send(res, 200, {
      "Content-Type": "text/plain",
    }, "deadbeefdeadbeefdeadbeef\n");
  }

  if (path.startsWith("/user/repo.git/objects")) {
    return send(res, 200, {
      "Content-Type": "application/octet-stream",
    }, Buffer.from("fake-object"));
  }

  if (path === "/user/repo.git/git-upload-pack") {
    return send(res, 200, {
      "Content-Type": "application/x-git-upload-pack-result",
    }, "0008NAK\n" + "0032fake-pack-response\n" + "0000");
  }

  if (path.includes(".pack")) {
    return send(res, 200, {
      "Content-Type": "application/octet-stream",
    }, fakePack());
  }

  return send(res, 200, {
    "Content-Type": "text/plain",
  }, "ok (fake git server)");
});

server.listen(PORT, () => {
  console.log(`Fake Git server running on http://localhost:${PORT}`);
});

これで何ができるか

  • Gitクライアントっぽいリクエストを受ける
  • それっぽいレスポンスを返す
  • ただし実際のGitとしては動かない

ハマりポイント

  • Gitプロトコルは思ったより複雑
  • packfileやオブジェクト管理が完全に別世界
  • HTTPだけでは全然足りない

まとめ

  • Gitサーバ「っぽいもの」は作れた
  • Gitサーバ「そのもの」は別次元
  • でも内部構造の理解にはかなり役立つ

おわりに

次はちゃんとしたGitサーバ実装に挑戦したい(たぶん地獄)。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?