GitHubでプルリクエスト用ブランチを保守するメモ

GitHubにリポジトリを置いてる人はみんなプルリクエストを待っています。けどプルリクエスト用にフォークした自分のリポジトリを保守する方法が途中でわからなくなって...という人が案外多いんじゃないかなと思ったり。なので、ちょっとメモ置いときます。って、人のためみたいな言い方ですが、まあ自分用のメモです。

まずこうしたほうがいいという原則。masterブランチはフォーク元から変更せず、かならず自分用のブランチを作る。これは、masterを作業の同期用に置いておくためです。

自分のブランチでコミットしたあと、フォーク元のmasterが進んでないかのチェックは必ずすること。
もし進んでいたら自分のmasterに元作者のコミットを取り込んで自分のGitHubでのフォークが最新と同期してる状態にしましょう。で、元作者のコミットログを確認して何が起こったのかを理解しましょう。

$ git checkout master
Switched to branch 'master'
...

$ git remote add upstream git://github.com/original-developer/repository.git

$ git pull upstream master
From git://github.com/original-developer/repository
 * branch            master     -> FETCH_HEAD
Updating ...
Fast-forward
...

$ git push origin master
Counting objects: ....

$ git log

pull のまえに remote add している upstream という名前は、オリジナル版の名前です。originが自分用なので、オリジナルのほうを指す名前を o で始まる名前にしないほうがいいということで、習慣的によくこの名前が使われます。

で、もし元作者の作業がmasterで進んだのに、自分の作業ブランチが遅れたmasterを元にしてるというのはダメです。なので作業の基点をやり直すためにrebaseをしておきましょう。

$ git checkout mytopic
Switched to branch 'mytopic'
...

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: ...

ここで自分の最後のコミットとフォーク元のmasterの進化の間で競合があると、rebaseプロセスが保留されてこんなメッセージで止まります。これ初めて目にすると「あわわどうしたら」ってなりますね。でも落ち着いて。

CONFLICT (content): Merge conflict in ...
Failed to merge in the changes.
Patch failed at ...

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".

このときソースコード的には競合をマージしないといけない感じになっています。

<<<<<<< HEAD:...
自分が作業してる間に元の作者がやったこと
=======
次分が古いコードをもとに行ってしまった変更
>>>>>>> mine

とにかくこの競合を解決して両方の意図が反映されたコードにすること。それができるまで他のことしちゃダメ。というのも、このときローカルリポジトリは処理保留中の状態なので、下手するとせっかくの自分の作業を紛失しちゃったりするかもしれません。あわてないあわてない。

統合できたら保留されていたrebaseの処理を再開するように指示します。

$ git rebase --continue
Applying: ...

これで競合がなくなれば、ローカルリポジトリでの同期は完了。
あとはGitHubに自分の作業ブランチをpushします。

$ git push origin mytopic

と、ここでもし過去にrebaseされていない作業ブランチをpushしていると ![rejected] とか fast-forwards とかいう例のメッセージが出てうまくいきません。これ、いちどGitHubにpushしたはいいけどやっぱりまだプルリクエストする勇気がないからってそのままにしてたけど、っていうようなブランチでよく起こります。

そんなときは、リモートの自分のコミットをいちど巻き戻します。そこに、rebaseしてマージしたその上に自分のコミットを積んだものをpushします。

$ git push -f origin HEAD~1:mytopic
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:myname/repository.git
...

$ git push origin mytopic
Counting objects: ...
...
To git@github.com:myname/repository.git
   4400314..070e6f3  mytopic -> mytopic

...というここまでの操作を繰り返して、よし送るぞという決意が固まったらGitHubのフォームから熱い思いを綴ったメッセージとともにプルリクエストを。元の作者さんだって、コミットログが少々雑でもないよりあったほうがだんぜん嬉しいのがプルリクエストです。

以上、プルリクエストの作法、というよりは、勇気が出るまで自分のブランチをメンテナンスし続けるうえで、パニックにならないための自分なりの操作手順メモです。より良い作法なんかはもっと詳しい人の情報を参考にしてください。