at posts/single.html

Subversion ユーザーが GitHub を使ってみたよ (その2: 他人のプロジェクト編)

前回は GitHub で1つの公開リポジトリを使う場合について書いた。これで git pull / push を使ったリモートリポジトリとの連携についての基本が分かった。 今回は他人が公開しているリポジトリを使う場合、つまり他の人の公開リポジトリと自分の公開リポジトリを連携させるところをやってみる。

目次

リポジトリの基本構成とワークフロー

GitHub 上に他の人が公開しているリポジトリを使う場合は、通常はそのリポジトリへのコミット権を持っていない。 そこで、そのリポジトリを fork して自分用の公開リポジトリを別に用意することになる。 たとえば tDiary のリポジトリを fork する場合の構成は以下のようになる。 ここでは公式のリポジトリに tdiary という別名を付け、自分のリポジトリを origin としている。

公開リポジトリが1つ (origin) だけの時に比べて、連携先のリポジトリが1つ (tdiary) 増えている。 ローカルリポジトリでは、自分がした修正と公式リポジトリ側の修正の両方を管理することになる。 公式の修正と自分の修正を分けるために、ブランチを上手に使うことがポイント。 上記の図では、公式の修正を master ブランチで管理し、自分の修正は future ブランチで管理するようにしている。 一度試してみたら分かるけど、 master ブランチ1つで両方を管理しようとしたら、すぐにごちゃごちゃになってしまう。

  1. 公式リポジトリ (tdiary) を fork して自分の公開リポジトリ (origin) を作成
  2. 自分の公開リポジトリを clone してローカルにリポジトリを複製
  3. ローカルリポジトリにて future ブランチを作成
  4. future ブランチへの修正を公開リポジトリ (origin) へ push
  5. 複数のマシンで開発している場合は、 origin の修正をローカルへ pull
  6. 公式リポジトリ側 (tdiary) の修正をローカルリポジトリの master ブランチへ反映
  7. 自分の修正 (future ブランチ) を公式リポジトリへ pull してもらうようにリクエストする(もしくはパッチをメーリングリストへ送る)

ポイントは、公式リポジトリ側の修正は master ブランチへ反映し、 future ブランチへは反映しないこと。また、自分の修正は future ブランチへ反映し、 master ブランチへは反映しない。 そうすれば future ブランチには自分の修正「のみ」が含まれることになるため、 pull request を送るときに取り込んでもらいやすくなる。

この例では future というブランチ名にしたけど、実際には1つのブランチをずっと使い続けるのではなく、追加する修正ごとにブランチを分けることになる。 例えば、 tDiary を Rack に対応させるような修正をする場合には rackable のような名前を付けるだろうし、簡単なバグ修正だったら bugfix_20100705 のような名前を付けるだろう。 このように、目的別に分けるブランチのことを git ではトピックブランチと呼ぶ。

公式リポジトリの fork

tDiary を例にとる。 tDiary のGitHubページへ行くと、上の方に Fork と書かれたボタンがある。 この Fork ボタンをクリックすると、 GitHub 上に自分用の公開リポジトリが作成される。 この時点でのリポジトリの内容は、公式リポジトリと全く同じ状態。

自分用の公開リポジトリを clone

GitHub のトップページを表示すると、 Fork したリポジトリ (tdiary-core) が右側の「Your Repositories」に表示される。 GitHub 上の公開リポジトリは直接触れないので、このリポジトリをさらにローカルへと clone する。 自分用の公開リポジトリなので、当然 Read+Write が可能な SSH を選択する。

$ git clone git@github.com:machu/tdiary-core.git

この辺は、前回の自分用のプロジェクトを使う場合と同じ。

トピックブランチ future を作成

ローカルに複製したリポジトリにはデフォルトのブランチ (master) だけが存在する。 リポジトリ内のブランチは git branch コマンドで確認できる。

$ git branch
* master

$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

このまま master 上で自分の修正を加えていくと、あとで公式リポジトリから最新の修正を pull してくるときに面倒なことになる。 そのため、自分の修正を加えるためのトピックブランチを作成する。 ここでは future という味気ない名前だけど、実際には修正する内容に合わせて適切な名前を付ける。

git branch コマンドで新しくブランチを作成し、git checkout コマンドでそのブランチへと移動する。

$ git branch future
$ git checkout future

git checkout コマンドに -b オプションを付けると、ブランチの作成と移動が1つのコマンドで可能。

$ git checkout -b future

git branch コマンドを打つと、現在のブランチが future になっていることが分かる。

$ git branch
  master
* future

間違ってブランチを作ってしまった場合は、 -d オプションで削除できる。

$ git branch -d future

future ブランチと master ブランチを行ったり来たりする場合は、作業ディレクトリに修正途中のファイルを残さないことがポイント。 コミットしてしまうか、 git stash コマンドで一時領域に待避できる。

ローカルリポジトリの内容を公開リポジトリ (origin) へ push

これも前回と同じ。ただし、 master ブランチではなく future ブランチへ反映しているところが違う。

$ git push origin future

公開リポジトリ (origin) の内容をローカルリポジトリへ pull

これも前回と同じ。

$ git pull origin

公式リポジトリ (tdiary) の修正を pull

自分の公開リポジトリ (origin) に独自の修正を加えていくと、平行して公式リポジトリ側には(他の人がした)修正が反映されていく。 そうすると、 Fork 直後は同じだったのに、自分の公開リポジトリ (origin) と公式リポジトリ (tdiary) との内容がだんだんとずれてくる。 公式リポジトリ側の修正を自動的に自分の公開リポジトリに反映することはできないので、代わりにローカルリポジトリへ公式の修正を取り込む。

まず、公式リポジトリをリモートリポジトリとして登録する。 通常はコミット権を持っていないので、 ReadOnly の Git プロトコルを使う。 リポジトリの別名は upstream でも official でも何でもいいんだけど、僕は GitHub のアカウント名を使うようにしている。

$ git remote add tdiary git://github.com/tdiary/tdiary-core.git

登録した公式リポジトリ (tdiary) から最新版を取得し、「masterブランチ」へとマージする。

$ git stash   # 編集中のファイルを片付けておく
$ git checkout master  # master ブランチへ移動
$ git pull tdiary   # 公式リポジトリ側の修正を取得し、 master ブランチへマージ
$ git push origin  # 取り込んだ公式リポジトリ側の修正を、自分の公開リポジトリへpushする

自分がした修正はすべてトピックブランチ (future) に反映されているので、 master ブランチは公式と自分のリポジトリのどちらも同じ状態になる。

自分の修正を公式に取り込んでもらえるようにパッチを送る

future ブランチでの修正が形になったら、公開リポジトリへpushし、公式リポジトリに取り込んでもらえるように pull request を送る。 なお、パッチの送り方はコミュニティごとにルールがあるので、いきなりpull requestを送るのではなくそのルールに従うこと。 tDiaryの場合はメーリングリストにパッチを提示することになっている。

自分専用のプロジェクトの場合は、トピックブランチへの修正を自分で master ブランチへとマージする。 でも(コミット権を持たない)他の人のプロジェクトの場合は自分で master ブランチへマージするのではなく、コミッタに pull してもらって、公式リポジトリの master に反映された後に公式リポジトリから取り込む方がいい。 あくまでも master ブランチは取り込み専用。 でないと、提示したパッチがそのまま受け入れられなかった場合に、公式の master ブランチと自分の master ブランチに差異がでることになる。

ここまでのまとめ

  • 公式リポジトリへの追随はローカルリポジトリを経由して
  • 自分の修正はトピックブランチで行う
  • master ブランチは公式リポジトリからのpull専用にする

次回は

他の人が作成しているトピックブランチを自分のリポジトリに取り込む方法について(例えば tDiary の testable ブランチなど)。

関連する日記