注意 Gitサーバとの距離によって結果はまちまちだ。time
コマンドを使った全く科学的とは言えないベンチマークでは、以下の手順を実行した後はgit pull
が、GitHubとシンガポールAWSのEC2で5秒以下から0.1秒以下になった。
なぜ?
$ time git pull
Already up-to-date.
real 0m5.075s
Gitリポジトリが最新だってことを表示するだけで5秒かかるって?あり得ない。
SSHコネクションの共有と永続化
シンガポールでは、github.comへの往復時間は250msほどだ。GitのオペレーションをするたびにSSHコネクションを張るのは、たくさんのやり取りが発生してしまう。しかし、~/.ssh/config
に以下の行を書けば、コネクションを保持して使いまわすことができる。
ControlMaster auto
ControlPath /tmp/%r@%h:%p
ControlPersist yes
ControlMaster auth
は、1つのネットワークコネクションを複数のSSHセッションで使いまわす設定で、マスタコネクションがない場合はそれを張るようになる。
ControlPath /tmp/%r@%h:%p
は、コネクションの共有のための制御ソケットへのパスを指定する。%r
はリモートログインのユーザ名に、%h
はターゲットのホスト名に、%p
はポート番号に置き換えられる。
ControlPersist yes
は、マスタコネクションをバックグラウンドで永続的に張り続けるという意味。
GitHubを自動ミラーリングするGitミラーを設定
秒単位でのGitリモート操作をするには、低レイテンシのサーバが必要だ。(物理的に一緒に働いていて、誰かが「プッシュした!」と言ったちょうどその時にgit pull
できることを想像してみよう)
と言っても、あなたのサーバから自動的にGitHubへプッシュするようにすれば、GitHubの提供する色々なよい点を使い続けることはできる。GitHubを常に最新に保つ方法には、cronジョブを使ったり、複数のリモートサーバを持つといったいくつかの方法があるが、post-receiveフックを使うのが一番エレガントなやり方だと思う。
サーバ上で、GitHubのデプロイキーをセットアップする。
$ ssh-keygen -t rsa -C "your_email@example.com"
$ cat .ssh/id_rsa.pub
ターゲットにするリポジトリで、Settings → Deploy Keys → Add deploy keyを選び公開鍵を貼り付けて登録しよう。リポジトリをミラーすることができるようになる。
$ git clone --mirror git@github.com:ahbeng/example.git
プッシュすると自動的にGitHubにミラーするようにするには、hooks/post-receive
でGitフックを設定する。
#!/bin/bash
nohup git push --mirror &>/dev/null &
スクリプトが終わるまで、Gitクライアントはコネクションを切らないので、単純にgit push --mirror
と書くだけだと、プッシュするたびにGitHubのレイテンシが影響してしまうので、これを設定する意味がなくなってしまう。そのため、nohupコマンドを使ってプロセスをバックグラウンドで動かし、ログアウトしても動き続けるようにしている。そして、ログアウト時にSSHが停止してしまうのを防ぐために、全ての出力を/dev/null
にリダイレクトしている。
フックを実行可能にしておこう。
$ chmod +x hooks/post-receive
これで新しいGitミラーをローカルで使えるようになった。サーバの秘密鍵をssh-agentに登録しておこう。
$ ssh-add ec2.pem
これでクローンもできる。
$ git clone user@hostname:example
あるいは、既にあるリポジトリのリモートリポジトリを変更しよう。
$ git remote set-url origin user@hostname:example
結果
Gitミラーを使うだけでgit pull
は1.2秒まで短くなった。SSHコネクションの共有を合わせて使うと、
$ time git pull
Already up-to-date.
real 0m0.111s
Gitのリモート操作が0.1秒。素晴らしい。