【GitHub】開発中ブランチを安全に退避させてプルリクを作成するまでに使うGitコマンド紹介【Pull Request】

# 素早くプルリクを出そう

エンジニアたるもの、自分が書いたコードがマージされて初めて仕事です。
マージされる前には、 **プルリクエスト(プルリク)**を出す必要があります。

最近、プルリクを結構な頻度で投げられるようになったので、ちょっと数えてみました。
大体、一ヶ月で75プルリク、**１営業日あたり3.75個のプルリク**を出していました。

この背景にあるのは、**プルリクを早く作るためのコツを習得した**ことにあると考えています。

というのも、プルリクは差分を作る作業以外に、変更点を確認したり、プッシュしてからブラウザを開いてプルリクを作成したり、意外に雑用が多いです。
この面倒な作業をいかに早くできるようになるかのタイムアタックです。

この記事では、**素早くプルリクを出すコツを習得したような気になっている私が、私のやり方をかなり正直に伝えます**。

ただし、差分の中身や、レビューにかかる時間は計算に入れていません。プルリクにまつわるコード修正以外の作業の時間を最小化することを目指しています。


# よっしゃ！修正箇所発見！

あなたは `my-branch` で絶賛開発中だとします。

`origin/master` で修正が必要な箇所が見つかりました。
あなたがその修正をすることになりました。

しかし、開発中ブランチをどうしましょう。。

一旦開発ブランチの変更を退避して、ブランチを変える必要があります。
修正後、 `my-branch` に戻ってくる未来を信じましょう。


## `git status` 開発中ブランチの変更ファイルを確認する
プルリクだけでなく、gitを扱うものとして、 `git status` は一番使うコマンドと言っても間違いではありません。
実際、私が一回のプルリクで `git status` は10~20回は軽く打つと思います。

`HEAD` コミット、ここでは `my-branch` のコミットから変更されたファイル一覧が出力されます。


```
$ git status -sb
```

この `-sb` オプションは、ブランチを表示した上でシンプルな表記にしてくれるため、 `git status -sb` をエイリアスにすると良いです。


## `git stash` 開発中ファイルを退避

`git stash` で差分のあるファイルを一時保存します。

```
$ git stash
```

新しく追加したファイルはトラッキングされてないので `git add` してから `git stash` しておきましょう。

## `git switch` masterブランチに移動

続いて、プルリクを出すターゲットとなるブランチに移動します。ここでは、 `master` です。

```
$ git switch master
```

## `git pull` masterブランチを最新版にアップデート

この `master` ブランチは最新版とは限りません。移動した瞬間、次のコマンドで最新版にします。
普通の使い方をしていれば、Fast-forwadでシンプルにコミットがくっついてきます。

```
$ git pull
```

## `git switch -c` masterから新しくブランチを生やす

最新版のmasterブランチから、プルリクのための修正ブランチを生やします。
`git checkout -b` でやっているのはちょっとナウくないですね。

```
$ git switch -c pr1-fix-handler-error
```

[git switchとrestoreの役割と機能について](https://qiita.com/yukibear/items/4f88a5c0e4b1801ee952) などを参考にしてください。

# プルリクを出す

さて、ここまでで **およそ30秒くらい** を目指しましょう。
続いては、実際にファイルを修正します。

ただし、今回は修正の中身自体には興味がないのでスキップします。

修正が終わったあと、コミット・プッシュし、プルリクを作るところまでやってみます。

## `git diff` で修正内容の差分を見る

修正した内容が本当に正しいかは、差分を見て確認しましょう。
問題なければ、修正作業は終了です。

```
$ git diff origin/master
```

## `git add` ステージング領域に上げる

`git status` で変更されたファイル一覧を見ながら、コミットするファイルをステージングに上げていきます。

```
$ git add handler.go
```

`git status` で変更されたファイルが限られている場合、時間短縮のために以下のコマンドを使ってもよいです。

```
$ git add .
```

よくおかしなファイルがコミットされるから一個ずつ上げることを推奨することがあります。
しかし、私の持論として、問題は `git add` ではなく、その手前の段階の `git status` での確認不足にあると考えられます。

## `git commit` コミットメッセージは、プルリクのdescriptionを書く

さて、ついにコミットです。 `git commit -m "commit-message"` は便利ですが、ここでは単純に以下のコマンドを使います。

```
$ git commit
```

このコマンドを打つと、エディタが起動します。そして、次のような入力画面が現れます。

- **一行目 プルリクのタイトル**
- 二行目は空行
- **三行目以降 プルリクのdescription**

を書いていきます。
重要なことは、ここで **人に見せる意識でメッセージを残す** ことです。

```
  1 ↲
  2 ; Please enter the commit message for your changes. Lines starting↲
  3 ; with ';' will be ignored, and an empty message aborts the commit.↲
  4 ;↲
  5 ; On branch master↲
  6 ; Your branch is up to date with 'origin/master'.↲
  7 ;↲
  8 ; Changes to be committed:↲
  9 ;»------new file:   handler.go↲
 10 ;↲↲
```

コミットしたあとに、コミットメッセージを修正したいときや、別ファイルもコミットに加えたいときは `--amend` で一個前のコミットを上書きできます。

```
$ git commit --amend
```

## `git rebase` 最新版のmasterにコミットをつなぎ直す

さて、あなたは素早く修正したつもりでしたが、思いの外masterブランチの開発速度が早く、コミットが進んでしまっていたようです。
場合によっては、プッシュするとコンフリクトしてしまうかもしれません。

こんなときは、まず `git fetch` で `origin/master` をアップデートしたあと、 `git rebase` でコミットを最新版の `origin/master` につけ直します。

```
$ git fetch
$ git rebase origin/master
```

## `git push` リモートリポジトリにブランチを作る

最新版の `origin/master` から一つだけコミットが伸びたブランチが出来上がりました。
これをリモートリポジトリにプッシュします。

```
$ git push
```

## `hub pull-request` プルリクを出す

無事にブランチはプッシュできました。ここでGitHubを開くようではタイムアタックで勝ち上がることはできません。

`hub` コマンドで、まずプルリクを作ります。
以下のコマンドを実行すると、コミットメッセージが並んだ入力画面が開きます。

あなたがさきほど頑張って書いておいたコミットメッセージはそのままプルリクのタイトルと説明文にすることができます。
入力画面を閉じると、プルリクが実際に作られます。

```
$ hub pull-request -a zawawahoge
```

```
$ hub pull-request -a zawawahoge
https://github.com/your-organization/your-repo/pull/123
```

プルリクのURLが出力されました。

上記のコマンドでレビュアーも指定できるのですが、私はまずGUIで確認してからGitHub上で指定するようにしています。
GiｔHubの差分は見やすいので、自分自身のミスも発見しやすくなります。

大丈夫そうだと思ったら、思い切ってレビュアーを設定しましょう！

# プルリクの修正

親切なチームメンバーの方々が、コメントを残してくれました。
少なからず変更点がありました。面倒臭がらず直していきます。

## `git merge` 最新版のmasterをマージする

修正の前に、最新版の `origin/master` をマージしておきましょう。

```
$ git merge origin/master
$ git add .
$ git commit -m "simple message"
$ git push
```

## `rebase` コミット履歴をきれいにする

修正の結果、 `fix` や `trivial change` みたいなコミットがたくさんついてしまうことありますよね。
こういうときは、思い切って `git rebase` して `origin/master` からのコミットをすべて書き換えることもあります。
一個だけコミットを修正したいときは `git commit --amend` も有効です。

```
$ git rebase origin/master -i
$ git push -f
```

または

```
$ git commit --amend
$ git push -f
```

`rebase` した場合は、 `git push -f` でforce pushしないとプッシュできません。なぜなら、**コミット履歴がごっそり書き換わっているから**です。
用法と用量を守ってforce pushしましょう。

GitHub上でのレビュー後の修正コミットもわからなくなるので、マージする直前なんかにやるといいです。

re-reviewしてもらったあと、ついに **approve** いただきましたー！

# プルリクのマージ

マージは気持ちが良いものです。
approveされたら、堂々とマージしましょう。
バグが起きたら、リバートするなり、再度修正プルリクを出しましょう。

## squash mergeでプルリクを一つのコミットに潰す
GitHubでリポジトリの設定を変えると、プルリクのコミット履歴を一つにまとめてマージしてくれるsquash mergeがあります。
チームと相談して、merge commitがいるかどうか議論してからsquash mergeの導入を検討すると良いです。

# 前の開発ブランチに戻る

## `git stash pop` で元のブランチでの開発環境を復活させる

もう忘れかけていた最初のブランチ・・・。
名前も忘れちゃったけど、ちょっと思い出してみると `my-branch` でした。

```
$ git switch first-branch
$ git stash pop
```

ようやく、元の開発環境に完全に戻ることができました。


# まとめ

長くなりましたが、いかがでしたでしょうか？
最近もくもくと一人でタイムアタックしているのですが、誰にも認識されずやっててつまらない気がしたので、いっそ外部公開しようと思って記事にしてみました。

参考になれば幸いです。

**面白かったと思ってもらえたらいいねしてもらえると嬉しいです！**

[Twitter(zawawahoge)](https://twitter.com/zawawahoge)もやってますので、フォローしてくれると泣いて喜びます。

# （おまけ） エイリアス大公開

５個くらいしか登録してないですが、あると便利なエイリアス紹介しておきます。
完全に自己流なのでご注意。

```
alias gf='git fetch'
alias gs='git status -sb'
alias gd='git diff'
alias gw='git switch'
alias gp='git pull'
```