ARTICLES

Pull Requestの送り方

By wraikny

git

はじめに

ある程度gitを使っている初心者向け。Pull Requestを殆ど使ったことない人のための記事。

Pull Requestって?

Pull Requestとは、あるbranch(A)から別のbranch(B)へのMergeをお願いする機能です。 なお、GitHubではPull Request、GitLabではMerge Requestと呼ばれます。

最初は勘違いする人もいますが、commit単位ではありません。

そのため、

  1. 一度branch Aからbranch BへのPRを開いて
  2. 新たなcommitをbranch Aへpushすれば
  3. それはbranch BへのPull Requestに反映される

ということになります。

Pull Requestを送ってみよう

Git練習用のリポジトリを作ってみました。

今回はこちらのSiritori-01.txtというファイルに新しい単語を追加することを目標としてみます。

しりとり
リス

まずはforkする

GitPracticeリポジトリ右上のforkボタンを押して、自分のリポジトリとして複製しましょう。

{あなたのid}/GitPracticeというリポジトリが作成されるので、これをlocalにcloneしましょう。

ここではwraikny/GitPracticeを使います。

また、元の AmusementCreators/GitPracticeリポジトリもremote branchに追加しておくと楽です。

CUIなら

$ git clone git@github.com:{あなたのid}/GitPractice.git
$ git remote add upstream git@github.com:AmusementCreators/GitPractice.git

という感じですね。

GitKrakenを使っている場合は、左のREMOTEタブから追加できます。

編集してcommitする

gitをある程度使ったことのある方はわかると思います。

  1. ファイルを編集
  2. 変更をStage
  3. commit
  4. Remoteへpush

Siritori-01.txt

しりとり
リス
+ スイカ

CUIなら

$ git add Siritori-01.txt
$ git commit -m "Add new word in しりとり"
$ git push

GitHubのウェブサイトからPRを開く

forkしたリポジトリを開きます。

New pull requestというボタンを選択することで、以下のような画面に移ります。

Able to mergeと表示されていいる(conflictが発生していない)ことを確認して、 Create pull requestボタンを押します。 PRのタイトルやメッセージを編集すれば、Pull Requestを作成することができます。

Pull Requestの内容を修正しよう

PRを開くことができましたが、リポジトリの管理者から以下のように修正を求められるかもしれません。

この場合は、一度PRをcloseして新しくPRを開き直す必要があるのでしょうか?

それは違います。 最初にも書いたとおり、Pull Requestはbranchからbranchへ送るものなので、追加でpushすることでPRの内容を変更することができます。

しりとり
リス
- スイカ
+ すき焼き

管理者によって承認されて、無事Mergeされました。

最終的に、以下のように変更されたことになります。

*       wraikny(管理者) dab7b08   (upstream/master) Merge pull request #1 from wraikny/master
|\
| *     wraikny(あなた) 7628ca7  (origin/master) Change しりとり word
| *     wraikny(あなた) b00f99e  Add new word in しりとり
|/
*       wraikny(管理者) 0758b78  Add しりとり
*       wraikny(管理者) 5b25c32  add attributes
*       wraikny(管理者) f22e4c7  Initial commit

rebaseで最新のmasterに合わせる

では、再びPull Requestを作成していきましょう。

その後の変更によって、upstream/masterのSiritori-01.txtは以下のような内容になっていました。

しりとり
リス
すき焼き
機械
岩
輪っか
かもめ
メモ帳
海牛

rebaseコマンドでリポジトリを最新のmasterに合わせます。

$ git rebase upstream/master

今はupstream/masterがlocalのmasterの延長線上にあり、これはFast-forwardと呼ばれる操作です。

では、次のcommitをpushします。

メモ帳
海牛
+ ウサギ

再びPull Requestを送ってみます。

おや、mergeできないと表示されています。 conflictしてしまいました。 とりあえずPRを送ってみます。

rebaseをするように言われてしまいました。

ここで一度、gitのlogを表示してみましょう。

*       wraikny(あなた) c946d15  (HEAD -> master, origin/master, origin/HEAD) Add ウサギ in しりとり
| *     wraikny(管理者) 3b38776  (upstream/master) Fix Animal name to カタカナ in Siritori-01
| *     wraikny(管理者) dd98ac1  Add Siritori-02.txt
|/
*       wraikny 7933534  Add しりとり words
*       wraikny dab7b08  Merge pull request #1 from wraikny/master
|\
| *     wraikny(あなた) 7628ca7  Change しりとり word
| *     wraikny(あなた) b00f99e  Add new word in しりとり
|/
*       wraikny(管理者) 0758b78  Add しりとり
*       wraikny(管理者) 5b25c32  add attributes
*       wraikny(管理者) f22e4c7  Initial commit

手元で編集してPull Requestを開くまでの間に、新たなcommitが行われていたのです。

今回は同じ箇所を編集してしまったことで、conflictが発生してしまいました。

そうでなくとも、最新ではないcommitから編集をしてしまったせいで、実際の複雑なプログラムでは依存関係が壊れているかもしれません。

また、gitのlogも見にくくなってしまいます。

こんな状況で活躍するのがrebaseコマンドです。

$ git rebase upstream/master
First, rewinding head to replay your work on top of it...
Applying: Add ウサギ in しりとり
error: Failed to merge in the changes.
Using index info to reconstruct a base tree...
M       Siritori-01.txt
Falling back to patching base and 3-way merge...
Auto-merging Siritori-01.txt
CONFLICT (content): Merge conflict in Siritori-01.txt
Patch failed at 0001 Add ウサギ in しりとり
The copy of the patch that failed is found in: .git/rebase-apply/patch

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

Siritori-01.txtをVSCodeで見てみます。

このように、どちらの変更を採用するかを適切に解消する必要があります。 この場合は ウミウシ -> ウサギ とするのが適切でしょうから、そのようにしてあげましょう。

両方の変更を取り込むを選択すると以下のようになるので、

メモ帳
ウミウシ
海牛
ウサギ

海牛を削除してファイルを保存してから

メモ帳
ウミウシ
- 海牛
ウサギ
$ git add Siritori-01.txt

$ git rebase --continue
Applying: Add ウサギ in しりとり

conflictが解消できたので、pushしてみましょう。 rebaseしたことで、force pushが必要になっています。

$ $ git push --force-with-lease

(force pushは強制的に上書きしてしまうので、複数人で編集しているbranchでは使わないようにしましょう。 まあ、そのためにbranchを分ける事が必要になるのですが)

Pull Requestが更新されています。 conflictが解消されたことで、管理者によってmergeされました。

では、gitのlogを見てみます。

*       wraikny(管理者) cb8aa77  (upstream/master) Merge pull request #2 from wraikny/master
|\
| *     wraikny(あなた) 1d537f6  (HEAD -> master, origin/master, origin/HEAD) Add ウサギ in しりとり
|/
*       wraikny(管理者) 3b38776  Fix Animal name to カタカナ in Siritori-01
*       wraikny(管理者) dd98ac1  Add Siritori-02.txt
*       wraikny(管理者) 7933534  Add しりとり words
*       wraikny(管理者) dab7b08  Merge pull request #1 from wraikny/master
|\
| *     wraikny(あなた) 7628ca7  Change しりとり word
| *     wraikny(あなた) b00f99e  Add new word in しりとり
|/
*       wraikny(管理者) 0758b78  Add しりとり
*       wraikny(管理者) 5b25c32  add attributes
*       wraikny(管理者) f22e4c7  Initial commit

先程は二股に別れていましたが、rebaseによって綺麗に1本のlogになっています。 upstream/masterの最新のcommit3b38776から1d537f6のcommitができていることになっていますね。

また、rabaseのかわりにmergeを使っていた場合は、無駄なmerge commitが発生していました。 何度もレビューを受けて編集する間にmergeも何回も行うことになれば、履歴が見にくくなってしまいますね。

ただ、rebaseは歴史改変の一種なので、使い所は気をつけましょう。 自分は今回のようにPR時に最新に合わせる使い方がほとんどですし、それくらいが良いのではないでしょうか。

あまりmasterなどに対してやる操作では無いと思います。

おわりに

以下は練習用のリポジトリとして好きにPRを投げたりしてみてください。

AmusementCreators/GitPractice - GitHub

SHARE THIS POST