昨日,Jenkinsプロジェクトの開発者が誤って,JenkinsコードベースのGitリポジトリをストアしているGitHubレポジトリに強制的なプッシュを実行してしまい,数ヶ月間のコミットを紛失した。理解あるコミュニティによって問題はすぐに解決されたものの,この件は,GitHubの備えるオープン性 (Jenkins CIの機構と組み合わせれば,誰でも任意のリポジトリにコミットできる) が,問題を拡大する可能性のあることを浮き彫りにした。
Gitの強制プッシュ(force push) – git push -force
で実行する – は,サーバに指定したコンテントをプッシュして,リファレンス(ブランチあるいはタグ)の内容を置き換えるように指示するものだ。通常,Gitのリポジトリに許されているのは,ファーストフォワードプッシュに限定されている - すなわち,プッシュするリファレンスは,その先祖として現行のリファレンスを持っていなければならない。強制プッシュはこの制限を取り除いて,現行のコンテントを置き換えることができる。
Gitリポジトリの設定では,git configの値 "receive.denyNonFastForwards true
" を使って,この動作の許可あるいは禁止を指定することができる。強制的な操作の防止にはこれを利用する。
強制的なプッシュが便利な場合もある。例えば git filter-branch
のようなリファクタあるいはフィルタ操作が実行されると,コミットが現行ブランチの先祖ではなくなるため,通常の操作は不可能になる。別の利用ケースとして,ミラーリングが有効な場合に,2つのリポジトリの内容を同期させることで,エラーを発生させずに変更内容をパスすることができる。
今回のケースで起きたのは次のようなものだ - Gerritミラーリングプラグインをテスト中だったLucaは,Jenkinsリポジトリ用として,リポジトリセットをローカルにチェックアウトしていた。Gerritのミラーはこのローカルリポジトリからコンテントを取得するようにセットアップされていた。結果的にすべてのリポジトリが,彼の手元にあるチェックアウトからミラーするようになっていたのだ。不運なことに,そのレポジトリはしばらく更新されていなかったため,すべてのリポジトリを以前の状態にリセットすることになってしまった。
幸運なことに,現在はすべてのリポジトリが元に戻されている - Gitバージョン管理システム(あるいはどのDVCSでも)のメリットのひとつとして,任意のクローンからリポジトリを再生可能なことがあり,これを実行するのは簡単だった。GitHubのサポートも非常に効果的だった。コンテントを再取得するために,サーバ側のreflog (ブランチ内の変更を識別するために使用)を提供してくれたのだ。しかし,将来的にこの問題を緩和するためには,2つの重要な疑問に答を出さなければならない:
- ユーザが複数のリポジトリにコミットするのは妥当なことだろうか,あるいはレビュー/プルリクエストのように,管理されたチャネルを通じて変更を伝えるべきだろうか?
- GitHubにおいて,
denyNonFastForwards
設定オプションを提供することは適切だろうか?
GitHubの有力なライバルであるBitBucketでは,nonFastForwardsを無効にするオプションを提供している。BitBuckerはAtlassianによって継続され,現在はDVCSのひとつであるMercurialの公式サイトとして使用されている。しかしながら,BitBucketが有名になったのはGitのホスティングソリューションとしてであり,そのGit管理ソリューションであるAtlassian StashはGitリポジトリに特化したものだ。
皮肉にもLucaは,Gerritをベースとするリポジトリを提供するGerritForgeという会社を持っている。先日著した Learning Gerrit Code Review という本は,InfoQでもレビューしたばかりだ。JenkinsのリポジトリがGerritのようなレビューベースのツールを使っていれば,今回のことは起きなかったかも知れない。
GitHubがnonFastForwardsの設定機能を提供するまでの措置として,Jenkinsの開発者は,GitHubリポジトリへのプッシュを追跡して実行した変更とコミットのSHA値を記録するツールを作成した。皮肉なことに彼らは,rsync
を使ってリポジトリを複数の場所にバックアップすることを提案している。
強力な機能には大きな責任が伴う。GuiHubでforceオプションを使用するのはまさにそのケースだ。今後GitHubがこれを禁止するオプションを提供するかどうかに関わらず,バックアップされていない巨大な公開リポジトリをホストする場合には注意が必要だ。