JGitへのコントリビュートとGerritを使ってみた感想

GitBucketではバックエンドの実装にJGitを使っているのですが、gitリポジトリをzipファイルとしてダウンロードした際に、同じコミットでもダウンロードしたzipファイルのハッシュが同じ値にならないというレポートがあり、調べたところJGitのarchiveコマンド部分の実装に問題があることがわかったため*1、JGitにフィードバックを行ってみました。

こちらがGitBucketのユーザさんからいただいたレポートです。

github.com

JGitへのコントリビューション方法

さて、JGitはオープンソースプロジェクトではありますが、Eclipse Foundationで開発されているものなので、Apache Software Foundationと同じくコントリビューションは面倒そうな予感がします。GitHubリポジトリがあるのですがどうやらこちらはミラーのようで、プルリクエストを送っても受け付けてもらえないようです。

github.com

調べてみたところ、コントリビューター向けのガイドがありました。どうやらGerritでコードレビューの依頼をする必要があるようです。もちろん事前にアカウントを作成してCLAへの同意などを行っておく必要があります。*2

Gerritによるコードレビュー

Gerritは1コミット=1プルリクエストのような感じでレビューを行います。以下のようにrefs/for/masterにpushすることでレビュー依頼が登録されます。

git push ssh://username@git.eclipse.org:29418/jgit/jgit.git HEAD:refs/for/master

レビューを受けて修正する場合は元のコミットにamendするなどして新しいコミットをpushするわけですが、以前のコミットと紐づけるためにコミットメッセージにChange-Idを含めておく必要があります。また、修正者を明示するためにアカウントの情報をSigned-off-byに含めておく必要もあります。JGitのGerritではこれらのフィールドが含まれていないとpushがリジェクトされました。

実際にpushしたコメントはこんな感じです。

Set commit time to ZipArchiveEntry

Archived zip files for a same commit have different MD5 hash because
mdate and mdate in the header of zip entries are not specified. In
this case, Commons Compress sets an archived time.

In the original git implementation, it's set a commit time:
https://github.com/git/git/blob/e2b2d6a172b76d44cb7b1ddb12ea5bfac9613a44/archive.c#L378

By this fix, archive command sets the commit time to ZipArchiveEntry
when RevCommit is given as an archiving target.

Change-Id: I30dd8710e910cdf42d57742f8709e9803930a123
Signed-off-by: Naoki Takezoe <takezoe@gmail.com>

Change-Idはコミットフックで自動的に付与することができます。フックスクリプトは通常Gerritサーバで提供されており、JGitの場合は以下のようにしてローカルリポジトリにインストールすることができました。

scp -p -P 29418 username@git.eclipse.org:hooks/commit-msg .git/hooks/

これで修正をローカルリポジトリにコミットした時点でコミットメッセージにChange-Idが自動的に追加されます(修正時など、すでにChange-Idが付与されている場合は何も行いません)。

レビューで指摘があった場合は修正して再度pushすると新しいpatch setが作成されます。前述の通り、Gerritは1コミットが1プルリクエストに相当するのですが、patch setによって1コミット内のレビューや変更の履歴を管理することができます。もちろん途中のpatch setからやり直したりということもできます。

ちなみに以下が今回フィードバックした修正のレビューです。JGit 4.7でマージしていただけるようです。

https://git.eclipse.org/r/#/c/91116/

f:id:takezoe:20170218214029p:plain

感想

JGitは目立たないライブラリではありますが、JVMベースの様々な開発者向けツールで使用されており、もちろんGitBucketでも活用させていただいているので、ちょっとした修正ではありますが貢献できて嬉しいところです。

また、Gerritは初めて使ったのですが、綺麗なコミット履歴を保ちつつ、その過程も管理できるという点はメリットだと感じました。ただ、Gitの操作が複雑なだけでなく*3、Web UIも非常にわかりづらく初見だと何をしていいのかさっぱりわからないという敷居の高さがあります。

最近は企業が主体となって開発しているOSSや、ASFのプロダクトなどでもGitHubでのプルリクエストを受け付けてくれるものが増えてきていますが、golangなどGerritを使ってレビューを行っているプロジェクトもあります。今回の作業はGerritの使い方も含め勉強になりました。

Gerritの使い方を手取り足取り教えてくれた弊社ターミナル部部長である@tanacasinoに感謝の意を表したいと思います。ありがとうありがとう。

*1:zipファイルのエントリにファイルのタイムスタンプを設定していなかったため、zipファイル作成時のタイムスタンプが使用されてしまっていたのが原因でした。

*2:GerritはGoogleが開発したGitベースのコードレビューシステムで、JGitを使用して実装されています。

*3:通常の操作を行うだけでもそれなりのGit力を要求されますし、patch setの操作や複数のレビューが相互に関連する大きな修正の場合はかなり複雑な操作が必要になりそうです。