これでアカウントが用意できたので、次は、既存のプロジェクトへの貢献にあたって役立つであろうことを説明していきましょう。
既存のプロジェクトに貢献したいけれども、そのリポジトリにプッシュする権限がないという場合は、プロジェクトを「フォーク」できます。 「フォーク」するとは、GitHub があなた専用にそのプロジェクトのコピーを作るということです。あなた自身の名前空間に置かれるので、そこには自分でプッシュできます。
Note
|
歴史的に、この「フォーク」という用語はあまり好ましくない意味で使われてきました。 何かのオープンソースプロジェクトの方針を気に入らない人が、別の道を歩み出すこと (そして時には、競合するプロジェクトを作って、貢献者を引き抜いてしまうこと)を指していたのです。 GitHub における「フォーク」とは、単にあなたの配下に作られるコピー以外の何者でもありません。 自分自身による変更を公開の場でそのプロジェクトに適用でき、よりオープンなやりかたでプロジェクトに貢献できるようにするための手段なのです。 |
この方式なら、協力してくれる人たちにいちいちプッシュアクセス権を付与していく必要はありません。 それぞれがプロジェクトをフォークして、そこにプッシュして、その変更を元のリポジトリに提供したければ、いわゆる「プルリクエスト」を作ればいいのです。 プルリクエストについては、後ほど説明します。 プルリクエストを作ると、そこにコードレビューのスレッドが立ち上がります。 プロジェクトのオーナーとプルリクエストの作者は、そこで変更についての議論を重ねて、 オーナーが納得した時点で、それをマージすることができます。
プロジェクトをフォークするには、プロジェクトのページに行って、ページ右上にある``Fork''ボタンを押します。
数秒後、新しいプロジェクトのページに自動的に移動します。これは、あなた自身が書き込み可能なコピーです。
GitHub は、プルリクエストを中心としたコラボレーションのワークフローを想定して作られています。 ひとつのリポジトリを共有する密接に連携したチームでの作業であっても、世界中に広がる企業や個人が関わるプロジェクトで何十ものフォークがあるプロジェクトであっても、 このワークフローはうまく機能します。 その中心になるのが、ch03-git-branching.asc でとりあげた ch03-git-branching.asc のワークフローです。
全体的な流れは、以下のようになります。
-
master
からトピックブランチを作る。 -
そこに、プロジェクトの改良につながるコミットをする。
-
このブランチを、自分の GitHub プロジェクトにプッシュする。
-
GitHub 上でプルリクエストを作る。
-
議論を重ね、必要ならさらにコミットをする。
-
プロジェクトのオーナーは、プルリクエストをマージする(あるいは、マージせずに閉じる)。
これは基本的に、ch05-distributed-git.asc でとりあげる、統合マネージャー型のワークフローです。 しかし、変更についてのやりとりやレビューをメールで行う代わりに、ここでは GitHub のウェブベースのツールを使います。
GitHub で公開しているオープンソースのプロジェクトに対して、このフローを使って変更を提案する例を見ていきましょう。
自分のArduino上で実行するコードを探していたトニーは、GitHub 上にすばらしいプログラムがあることを発見しました。 それが https://github.com/schacon/blink です。
ただ、ひとつ問題がありました。点滅の間隔が速すぎるのです。1 秒おきに状態を切り替えるのではなく、3 秒くらいは間を置きたいものです。 さて、このプログラムを改良して、その変更を提案してみましょう。
まずは、先ほど説明した 'Fork' ボタンをクリックして、このプロジェクトのコピーを手に入れます。
この例で使うユーザー名は `tonychacon'' とします。つまり、できあがったコピーは `https://github.com/tonychacon/blink
となり、ここからはこのプロジェクトを変更していきます。
これをローカルにクローンして、トピックブランチを作り、コードを変更して、その変更を GitHub にプッシュしましょう。
$ git clone https://github.com/tonychacon/blink (1)
Cloning into 'blink'...
$ cd blink
$ git checkout -b slow-blink (2)
Switched to a new branch 'slow-blink'
$ sed -i '' 's/1000/3000/' blink.ino (3)
$ git diff --word-diff (4)
diff --git a/blink.ino b/blink.ino
index 15b9911..a6cc5a5 100644
--- a/blink.ino
+++ b/blink.ino
@@ -18,7 +18,7 @@ void setup() {
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
[-delay(1000);-]{+delay(3000);+} // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
[-delay(1000);-]{+delay(3000);+} // wait for a second
}
$ git commit -a -m 'three seconds is better' (5)
[slow-blink 5ca509d] three seconds is better
1 file changed, 2 insertions(+), 2 deletions(-)
$ git push origin slow-blink (6)
Username for 'https://github.com': tonychacon
Password for 'https://[email protected]':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/tonychacon/blink
* [new branch] slow-blink -> slow-blink
-
フォークしたプロジェクトを、ローカルにクローンする
-
わかりやすい名前のトピックブランチを作る
-
コードを変更する
-
問題はなさそうだ
-
この変更をトピックブランチにコミットする
-
新しいトピックブランチを、GitHub 上のフォークに書き戻す
この状態で GitHub 上のフォークに戻ると、GitHub 上に新しいトピックブランチがプッシュされたことを伝えてくれます。 また、大きな緑色のボタンを使えば、変更点を確認したり、元のプロジェクトへのプルリクエストを送ったりできます。
あるいは、https://github.com/<user>/<project>/branches
にある ``Branches'' ページから自分のトピックブランチに移動して、そこからプルリクエストを送ることもできます。
この緑のボタンをクリックすると、プルリクエストのタイトルと説明を入力する画面に遷移します。 ちゃんと時間をかけて説明を書きましょう。損はしないはずです。プルリクエストを受ける側のプロジェクトオーナーからすれば、説明文がよければあなたの意図が汲み取りやすくなるからです。そうすれば、オーナーはプルリクエストの内容を正確に評価できますし、それを取り込むことがプロジェクトにとってプラスかどうかを判断できるでしょう。
この画面では、トピックブランチ内のコミットのうち、`master`よりも先行しているコミットの一覧 (今回の場合はひとつだけ) も確認できます。 また、このブランチをオーナーがマージしたときに適用される変更の、unified形式の差分も表示されます。
この画面で 'Create pull request' ボタンを押すと、フォーク元のプロジェクトのオーナーに、 誰かが変更を提案しているという通知が届きます。この通知には、変更に関するすべての情報が記載されたページへのリンクが含まれています。
Note
|
一般にプルリクエストは、こういった公開プロジェクトに対する変更を、その準備が整った時点で提案するために作るものです。 しかし、内部的なプロジェクトの開発サイクルにおいて、 開発を始めるタイミングで プルリクエストを作ることもよくあります。 プルリクエストを作った*後でも*、そのトピックブランチへのプッシュを続けることができます。 最後の最後にプルリクエストを行うのではなく、早い時点でプルリクエストを作っておけば、 その後の作業状況をチーム内で共有できます。 |
これで、元のプロジェクトのオーナーは、変更の提案を見られるようになりました。それをマージしたり、却下したり、コメントしたりすることができます。 ここでは、オーナーが変更提案を気に入ったものの、ライトが消えている時間を点灯している時間よりも少しだけ長くしたほうがいいと感じたことにしましょう。
ch05-distributed-git.asc のワークフローなら、この手のやりとりはメールで行うところですが、GitHub の場合はこれをオンラインで行います。 プロジェクトのオーナーはunfied diffをレビューして、コメントを残します。コメントしたい行をクリックすれば、コメントを残せます。
メンテナがコメントを入れると、プルリクエストの作者 (そして、そのリポジトリをウォッチしているすべての人たち) に、通知が届きます。 通知をカスタマイズする方法については後述しますが、メールでの通知を受け取るように設定している場合は、以下のようなメールも届きます。
オーナーだけでなく誰でも、プルリクエスト全体に対するコメントができます。 プルリクエストのディスカッションページ では、プロジェクトのオーナーがコードの特定の行についてコメントしたうえで、さらにプルリクエスト全体に関するコメントも残しています。 また、コードへのコメントが、一連の会話に組み込まれていることにもお気づきでしょう。
プルリクエストの作者は、自分の変更を受け入れてもらうために何が必要なのかがわかりました。 幸運にも、そんなに手間のかかることではありません。 メールでのやりとりの場合は、一連の作業をやり直した上でもう一度メーリングリストに投稿する必要がありますが、 GitHub なら、単にトピックブランチにコミットしてそれをプッシュするだけで済みます。 また、プルリクエストの最終形 にあるように、更新されたプルリクエストでは変更前のコードへのコメント表示が省略されています。追加されたコミットによって変更されたコードへのコメントだからです。
なお、既存のプルリクエストにコミットを追加しても、通知は送られません。そこで、修正をプッシュしたトニーは、修正が終わったことをコメントでプロジェクトオーナーに伝えることにしました。
このプルリクエストのページで Files Changed'' タブをクリックすると、
unified'' 形式の diff を確認できます。
つまり、このトピックブランチをマージしたときにどんな変更が施されるのかを、まとめて確認できるのです。
git diff
の用語に直すと、このタブを開いたときに表示される内容は、プルリクエストの対象になっているブランチ上で
git diff master…<branch>
を実行した結果になります。
この形式の diff についての詳細は、ch05-distributed-git.asc を参照ください。
もうひとつお気づきのことがあることでしょう。 GitHub は、このプルリクエストが問題なくマージできることを確認したうえで、サーバー上でマージを実行するためのボタンを表示します。 このボタンが表示されるのは、あなたがこのリポジトリへの書き込みアクセス権限を持っていて、かつ問題なくマージ可能な場合だけです。 このボタンをクリックすると、GitHub は ``non-fast-forward'' なマージを行います。 つまり、仮に fast-forward 可能なマージであったとしても、明示的にマージコミットを作ります。
お望みなら、このブランチを取得した上で、ローカルでマージすることもできます。
このブランチを master
にマージしてから GitHub にプッシュすると、このプルリクエストは自動的に閉じられます。
これが、大半の GitHub プロジェクトが使っている基本的なワークフローです。 トピックブランチを作り、そこからプルリクエストを作って、議論を重ね、必要に応じてさらに作業を重ねて、最終的にそのリクエストをマージするか、あるいはマージせずに終了します。
Note
|
フォークしなくてもかまわない
同じリポジトリのふたつのブランチ間でのプルリクエストもできるということを知っておきましょう。
誰かと一緒に何らかのフィーチャーの作業をしていて、両方ともそのプロジェクトへの書き込み権限を持っている場合なら、
トピックブランチをそのリポジトリにプッシュした上で、同じプロジェクトの |
GitHub のプロジェクトに貢献する際の基本がわかったところで、 プルリクエストに関するちょっとしたヒントやテクニックを紹介しましょう。これらを使えば、プルリクエストをさらに活用できるでしょう。
実際のところ、多くのプロジェクトは、プルリクエストを完璧なパッチ群である (つまり、きちんと順序どおりに適用しなければいけない) とは考えていません。 これは、メーリングリストベースで運営するプロジェクトで一般的な考えかたとは異なります。 GitHub のプロジェクトでは、プルリクエストのブランチを変更提案に関する議論の場と捕らえていることが多く、 最終的にできあがった unified diff をマージするのだと考えています。
この違いを認識しておくことが大切です。一般に、変更を提案するのは、コードが完璧に仕上がる前の段階です。 一方、メーリングリストベースの運営では、まだできあがってもいないパッチを投稿することなど、まずないでしょう。 未完成の段階で変更を提案することで、メンテナとの議論を早めに始めることができます。 コミュニティの協力で、より適切なソリューションにたどり着けるようになるでしょう。 プルリクエストで提案したコードに対してメンテナやコミュニティから変更の提案があったときに、 パッチをゼロから作り直す必要はありません。 差分だけを、新たなコミットとしてプッシュすればいいのです。 その後の議論は、これまでの経緯を踏まえた上で進みます。
プルリクエストの最終形 をもう一度見てみましょう。プルリクエストの作者は、自分のコミットをリベースして新たなプルリクエストを作ったわけではありません。 単に、新しいコミットを追加して、それを既存のブランチにプッシュしただけです。 そのおかげで、今後このプルリクエストのページを見直すことがあったときにも、最終的な決定に至るまでの経緯を簡単に確認できるのです。 ``Merge'' ボタンを押したときに、本来不要な場面でも意図的にマージコミットを作っているのは、 後からそのプルリクエストを参照しやすいようにするためです。 必要に応じて、それまでの流れをすぐに調べることができます。
プルリクエストを作った後で元のプロジェクトに変更が加わったなどの理由で、プルリクエストがそのままではマージできなくなることがあります。 そんな場合は、そのプルリクエストを修正して、メンテナがマージしやすいようにしておきたいことでしょう。 GitHub は、そのままでマージできるかどうかをチェックして、すべてのプルリクエストのページの最下部に結果を表示します。
そのままではマージできないプルリクエスト のようになっていたら、自分のブランチを修正して、この表示がグリーンになるようにしたいところです。 そうすれば、メンテナに余計な手間をかけさせずに済みます。
グリーンにするための主な選択肢は、二種類あります。
ひとつは、自分のブランチを、プルリクエストの対象ブランチ (普通は、フォーク元のリポジトリの master
) の先端にリベースすること。
もうひとつは、その対象ブランチを自分のブランチにマージすることです。
GitHub 上の開発者の多くは、後者を選んでいるようです。その理由は、先述したとおりです。 重要なのは、そこにいたるまでの歴史と、最終的にマージしたという事実だと考えているのでしょう。 リベースをすると、歴史がすっきりするという以外の利点はありません。そして、リベースはマージに比べて ずっと 難しいし、間違いを起こしやすいものです。
対象ブランチをマージして、自分のプルリクエストをそのまま取り込んでもらえるようにする手順は、次のとおりです。 まず、オリジナルのリポジトリを新しいリモートとして追加して、それをフェッチします。 そして、そのリポジトリのメインブランチを自分のトピックブランチにマージします。 何か問題があれば修正し、その結果をプルリクエストと同じブランチにプッシュします。
先ほどの ``tonychacon'' の例に戻りましょう。プルリクエストを出した後にオリジナルの作者がリポジトリに変更を加えたため、 プルリクエストがそのままでは取り込めなくなってしまいました。そんな場合の手順は、以下のとおりです。
$ git remote add upstream https://github.com/schacon/blink (1)
$ git fetch upstream (2)
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From https://github.com/schacon/blink
* [new branch] master -> upstream/master
$ git merge upstream/master (3)
Auto-merging blink.ino
CONFLICT (content): Merge conflict in blink.ino
Automatic merge failed; fix conflicts and then commit the result.
$ vim blink.ino (4)
$ git add blink.ino
$ git commit
[slow-blink 3c8d735] Merge remote-tracking branch 'upstream/master' \
into slower-blink
$ git push origin slow-blink (5)
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 682 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/tonychacon/blink
ef4725c..3c8d735 slower-blink -> slow-blink
-
オリジナルのリポジトリを ``upstream'' という名前のリモートとして追加する
-
そのリモートの、最新の状態をフェッチする
-
メインブランチを、自分のトピックブランチにマージする
-
衝突を解決する
-
同じトピックブランチに、再びプッシュする
これでプルリクエストが自動的に更新されて、マージ可能かどうかが再びチェックされます。
Git のすばらしいところのひとつが、これらの作業を継続的に行えるということです。 長期にわたるプロジェクトでも、対象ブランチからのマージを何度でも繰り返せるので、前回のマージ以降に発生した衝突さえ気をつけていれば、混乱なく作業を続けられます。
ブランチをリベースしてすっきりさせたい場合は、そうしてもかまいません。 しかし、既に作成済みのプルリクエストに対して、それを強制的にプッシュするのは避けたほうがいいでしょう。 もし他の人がそれを手元に取得して何かの作業を進めると、ch03-git-branching.asc で説明したような問題が発生します。 リベースした場合は、それを GitHub 上で新しいブランチにして、新しいプルリクエストを作るようにしましょう。 新しいプルリクエストから元のプルリクエストを参照して、そして元のプルリクエストは閉じてしまいます。
…と言われて気になるのは、「元のプルリクエストをどうやって参照すればいいの?」ということでしょう。 GitHub 上で他のものを参照するにはいろんな方法があって、GitHub 上で何かを書ける場所ならほぼどこでも他のものを参照できます。
まずは、別のプルリクエストあるいは Issue を相互参照する方法から紹介します。
プルリクエストや Issue には番号が振られていて、この番号はプロジェクト内で一意になっています。
つまり、たとえばプルリクエスト#3とIssue 3が 両方とも 存在することはありえないのです。
他のプルリクエストや Issue を参照したい場合は、コメントや説明文の中で単に <num>
と書くだけでかまいません。
あるいは、もう少し細かく、誰か他の人が作った Issue やプルリクエストを指定することもできます。
username#<num>
と書けば、今いるリポジトリの別のフォーク上での Issue やプルリクエストを参照できるし、
username/repo#<num>
と書けば、別のリポジトリ上のものも参照できます。
実例を見てみましょう。 先ほど説明したとおり、リベースをした上で新しいプルリクエストを作ったものとします。新しいプルリクエストから、古いプルリクエストを参照したいところです。 また、そのリポジトリのフォーク上にある Issue や、まったく別のプロジェクトにある Issue も参照するつもりです。 説明文は、プルリクエスト内での相互参照 のようになります。
このプルリクエストを投稿すると、画面上では プルリクエスト内での相互参照のレンダリング のような表示になります。
GitHub の完全な URL を入力したところも、画面上では短縮されて、必要な情報だけが見えていることがわかるでしょう。
トニーが元のプルリクエストを閉じると、そのことが新しいプルリクエストのほうにも表示されることがわかります。 GitHub が、プルリクエストのタイムラインに自動的にトラックバックを送ったのです。 これで、古いプルリクエストを見にきたすべての人は、そのリクエストの後継となる新しいプルリクエストにたどり着けるようになるのです。 リンクは、プルリクエスト内での相互参照のレンダリング のように表示されます。
issue の番号だけでなく、SHA-1 を示して特定のコミットを参照することもできます。 SHA-1 を指定する際には 40 文字ぶんすべてを示す必要がありますが、コメントの中に SHA-1 を発見すると、GitHub はそれを当該コミットへリンクしてくれます。 他のフォークやその他のリポジトリのコミットを参照する場合の方法は、issue の場合と同じです。
他の Issue へのリンクは、GitHub のテキストボックスでできるさまざまなことのうちの、ほんの始まりに過ぎません。 Issue やプルリクエストの説明、それに対するコメント、コードに対するコメントなどなどでは、いわゆる ``GitHub Flavored Markdown'' を使うことができます。 Markdown はプレーンテキストと似ていますが、よりリッチなレンダリングを行います。
コメントや説明文を、Markdown を使って書いた例を Markdown での記述例と、そのレンダリング結果 に示します。
GitHub Flavored Markdownは、基本的なMarkdownの文法に、GitHub 流の味付けをしたものです。 プルリクエストや Issue を作ったり、それにコメントしたりするときに、役立つことでしょう。
GitHub 流の Markdown で追加された便利な機能の中で、最初に紹介する機能が、タスクリストです。これは、プルリクエストで特に便利です。 タスクリストとは、チェックボックス付きの、やることリストです。 これを Issue やプルリクエストで使うと、完了させるまでに何を済ませなければいけないのかを表せます。
タスクリストの作りかたは、以下のとおりです。
- [X] Write the code
- [ ] Write all the tests
- [ ] Document the code
プルリクエストや Issue の説明文にこのように書いておくと、Markdown でのコメント内に表示されたタスクリスト のような表示になります。
これはたとえば、プルリクエストに対して、「これだけのことを済ませればマージの準備が整う」ということを示すために使うことがあります。 この機能のすばらしいところは、単にチェックボックスをクリックするだけで、コメントが更新できるということです。 タスクが完了したときに、わざわざ Markdown を直接編集する必要はありません。
さらに、GitHub は、Issue やプルリクエストの中にあるタスクリストを見つけて、そのメタデータを一覧ページにも表示してくれます。 たとえば、あるプルリクエストの中でタスクを作ったときに、プルリクエストの一覧ページを見ると、タスクがどの程度完了しているのかを確認できるのです。 これは、プルリクエストをサブタスクに切り分けたり、他のひとたちがそのブランチの進捗を追いかけたりする際にも役立ちます。 この機能の実例を プルリクエスト一覧における、タスク一覧の概要表示 に示します。
この機能は、 トピックブランチを作ったばかりのときにプルリクエストを出して、その後の実装の進捗をプルリクエスト上で追いかけていくような場合に、とても便利です。
コメントに、コードスニペットを追加することもできます。 これは、これから やろうとしている ことを、実際に実装する前に表明したりするときに便利です。 また、うまく動かないサンプルコードや、このプルリクエストで実装できることを説明するサンプルコードなどを示すときにも使われます。
コードスニペットを追加するには、バッククォートで「囲む」必要があります。
```java
for(int i=0 ; i < 5 ; i++)
{
System.out.println("i is : " + i);
}
```
このサンプルでの 'java' のように言語名を追加すると、GitHub はスニペットのシンタックスハイライトを行います。 このサンプルは、最終的に サンプルコードをレンダリングした結果 のような表示になります。
長いコメントの一部に返信するときは、その部分を引用することができます。引用するには、各行の先頭に >
を付け加えます。
これはとても便利で、よく使われるものなので、キーボードショートカットも用意されています。
コメントの中で返信したい部分を選択して r
キーを押すと、選択した部分を引用した、新しいコメント入力欄が現れます。
引用は、このような感じになります。
> Whether 'tis Nobler in the mind to suffer
> The Slings and Arrows of outrageous Fortune,
How big are these slings and in particular, these arrows?
このコメントが、画面上では 引用のレンダリングの例 のようにレンダリングされます。
最後に紹介するのが絵文字です。コメントの中で、絵文字を使えます。
実際に、GitHub の Issue やプルリクエストの多くで、絵文字が使われています。
GitHub には、絵文字の入力支援機能もあるのです。
コメントの記入中に :
を入力すると、オートコンプリート機能が立ち上がって、絵文字を探すのを手伝ってくれます。
絵文字は :<name>:
形式で表し、コメント内のどこでも使えます。
たとえば、このように書いたとしましょう。
I :eyes: that :bug: and I :cold_sweat:.
:trophy: for :microscope: it.
:+1: and :sparkles: on this :ship:, it's :fire::poop:!
:clap::tada::panda_face:
これをレンダリングした結果は、絵文字だらけのコメント のようになります。
めちゃめちゃ便利というほどのものではありませんが、 楽しさや熱意を伝える手段としては他の追随を許さないものでしょう。
Note
|
最近は、絵文字を使えるウェブサービスも多くなってきました。 自分の言いたいことをうまく伝えられる絵文字を見つけるための、チートシートも公開されています。 |
厳密に言うと GitHub Flavored Markdown とは関係ありませんが、これはとても便利な機能です。 Markdown でのコメントに画像のリンクを追加するのは、画像を探したり URL を埋め込んだりと面倒くさいものです。 しかし GitHub では、テキストエリアに画像をドラッグ&ドロップするだけで、それを埋め込めるのです。
プルリクエスト内での相互参照 に戻ると、テキストエリアの上に小さく ``Parsed as Markdown'' とヒントが書かれていることがわかります。 これをクリックすると、GitHub 上での Markdown でできるすべてのことをまとめた、チートシートを見ることができます。