りんごとバナナとエンジニア

エンジニア修行の記録

[GitHub] hub pull-requestの宛先がフォーク元のリポジトリにならない場合の対処法

f:id:Udomomo:20190321122450j:plain:w300

hub.github.com

GitHubの公式コマンドラインツールであるhubの存在を知り、最近使い始めている。いろいろな作業がコマンドからできてとても便利なのだが、フォーク元のリポジトリにプルリクエストを送るところで詰まってしまった。フォーク元のリポジトリparent/repo、フォークして作られたリポジトリchild/repo としたとき、parentのmasterブランチ(parent:master)にプルリクエストを送りたかったのだが、 hub pull-requestとしたときのプルリクエストの宛先が child:masterになってしまった。

hub forkをしておくことが必要

この原因は、hub forkをしていなかったことにある。今回の場合、GitHubの画面上でリポジトリをフォークし、作成されたchild/repogit cloneして使っていたところで、hubについて知り使い始めた。しかしドキュメントの使用例では、フォークの段階からhub forkを使うことが前提になっている。フォーク元のリポジトリparent/repo、フォークして作られたリポジトリchild/repo としたとき、以下のような流れで使う。

$ hub clone parent/repo //まずフォーク元をclone
$ cd repo
$ git checkout -b feature
$ git commit -m "done with feature" //何か変更を加えてコミット
$ hub fork --remote-name=origin //ここでフォーク
$ git push origin feature
$ hub pull-request

このとき、 hub fork --remote-name=origin は、リモートリポジトリを以下のように変更する。 --remote-name=originの指定があることで、originchild/repoを指すようになり、parent/repoupstreamという名前になる。

$ git remote -v
origin  git@github.com:child/repo.git (fetch)
origin  git@github.com:child/repo.git (push)
upstream    https://github.com/parent/repo (fetch)
upstream    https://github.com/parent/repo (push)

そして、hubはプルリクエストを送る際の宛先となるリモートリポジトリの指定がない場合、upstream -> github -> originという優先順位でリモートリポジトリを探し、見つかった場合はそこを宛先とする。((https://hub.github.com/hub.1.htmlCONVENTIONの項目を参照。))このため、 事前にhub forkした状態で hub pull-requestとすれば、宛先はupstreamという名前で登録されているparent/repoのmasterブランチとなる。

既にフォークしたリポジトリでhubを使うには

今回は既にフォークしたリポジトリgit cloneしてきたため、リモートリポジトリは以下のようになっていた。originという名前のものしかないため、プルリクエストの宛先がchild/repoのmasterブランチになるのも当然である。

$ git remote -v
origin  git@github.com:child/repo.git (fetch)
origin  git@github.com:child/repo.git (push)

これを回避するには、プルリクエストを送る際に以下のようなオプションをつける。-bが宛先のブランチ、-hが変更を加えたブランチを表す。remoteにparent/repoが登録されていなくても、hubコマンドがGitHubを探索してくれる。

$ hub pull-request -b parent:master -h child:feature

しかし、これから何度もプルリクエストを送るのであれば、hub forkと同様に、フォーク元のリポジトリupstreamという名前でリモートリポジトリに登録してしまうのが良いだろう。これでオプションの指定なしでhub pull-requestが使えるようになる。

$ git remote add upstream https://github.com/parent/repo.git
$ git remote -v
origin  https://github.com/child/repo.git (fetch)
origin  https://github.com/child/repo.git (push)
upstream    https://github.com/parent/repo.git (fetch)
upstream    https://github.com/parent/repo.git (push)