一目置かれるコミット運用

# 綺麗なコミットを心がける

## TL;DR
コードレビューを依頼する立場からgitのコミットログを見やすくするための2つのテクニック


## (1つ目) コミットをまとめる
### 1. データが消えないように小まめにコミットする
様々な開発環境によってリアルタイムに保存されているから予期せぬ事態が発生してもデータが飛ぶことがないということもあるかも知れませんが、安全第一に考えて出来る限りコミットする。

####作業が終わっていなくても以下のタイミングでコミットする

- 休憩前
- ランチなどの食事前
- 1日の作業を終えて帰宅する前

#### コミットのタイトルに[WIP]をつける
- 作業が終わっていないけどコミットする際にはコミットログのタイトルに`[WIP]`をつける

### 2. コミットをまとめる
作業が完了したら`git log`コマンドを実行し、コミットを確認する。
`[WIP]`がついているコミットがある場合コミットをまとめます。

##### 2-1. コミットログを確認する
↓上の方が新しいコミットです。下に行くほど昔のコミットです。

```:コミットログ
$ git log --oneline

611dc15 (HEAD -> master) [WIP] Add test code
8cfe213 [WIP] Add parameter
3c53778 Add main.swift
870eb78 Register project files.
```

上記のコミットログのうち`[WIP]`がついている上から2つコミットをまとめる

- [WIP] Add test code
- [WIP] Add parameter

##### 2-2. git rebaseを使う
2つのコミットをまとめるために以下のコマンドを実行する
`git rebase -i HEAD~2`
実行すると下記のように表示されます。
＊git logの場合は降順(上の方が新しい)で表示されますが、git rebaseの場合は昇順(下の方が新しい)で表示されるので注意が必要です。`pick 611dc15 [WIP] Add test code`の方が新しいコミット

```:rebaseコマンド実行後に表示される
pick 8cfe213 [WIP] Add parameter
pick 611dc15 [WIP] Add test code

# Rebase 3c53778..611dc15 onto 3c53778 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
```


##### 2-3. コミットを編集する

```:編集前
pick 8cfe213 [WIP] Add parameter
pick 611dc15 [WIP] Add test code
```

↑を↓に書き換えます(2行目の`pick`を`s`に変更)

```:編集後
pick 8cfe213 [WIP] Add parameter
s 611dc15 [WIP] Add test code
```

```:編集後(全文)
pick 8cfe213 [WIP] Add parameter
s 611dc15 [WIP] Add test code

# Rebase 3c53778..611dc15 onto 3c53778 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
```

編集完了後に`:wq`で決定する。

##### 2-4. コミットメッセージを編集する

```:コミット編集時の表示
# This is a combination of 2 commits.
# This is the 1st commit message:

[WIP] Add parameter

main.swiftファイルに変数を追加。

# This is the commit message #2:

[WIP] Add test code

main.swiftファイルにテストコードを追加しました。

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Tue Dec 15 15:32:14 2020 +0900
#
# interactive rebase in progress; onto 3c53778
# Last commands done (2 commands done):
#    pick 8cfe213 [WIP] Add parameter
#    squash 611dc15 [WIP] Add test code
# No commands remaining.
# You are currently rebasing branch 'feature/#1_Create_main_file' on '3c53778'.
#
# Changes to be committed:
#       modified:   main.swift
#
# Untracked files:
#       hoge.txt
#
```

編集する部分は以下

```:編集箇所
# This is a combination of 2 commits.
# This is the 1st commit message:

[WIP] Add parameter

main.swiftファイルに変数を追加。

# This is the commit message #2:

[WIP] Add test code

main.swiftファイルにテストコードを追加しました。
```

```:編集後
Add needed functions for main.swift

main.swiftファイルに必要なファイルを全て実装しました。
```

```:編集後全文
Add needed functions for main.swift

main.swiftファイルに必要なファイルを全て実装しました。

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Tue Dec 15 15:32:14 2020 +0900
#
# interactive rebase in progress; onto 3c53778
# Last commands done (2 commands done):
#    pick 8cfe213 [WIP] Add parameter
#    squash 611dc15 [WIP] Add test code
# No commands remaining.
# You are currently rebasing branch 'feature/#1_Create_main_file' on '3c53778'.
#
# Changes to be committed:
#       modified:   main.swift
#
# Untracked files:
#       hoge.txt
#
```

編集完了後に`:wq`で決定する。


```:編集後のコミットログ
$ git log --oneline

6f6c506 (HEAD -> master) Add needed functions for main.swift
3c53778 Add main.swift
870eb78 Register project files.
```

コミットをまとめる前とまとめた後のコミットログの比較は以下です。

```:前
611dc15 (HEAD -> master) [WIP] Add test code
8cfe213 [WIP] Add parameter
3c53778 Add main.swift
870eb78 Register project files.
```

```:後
6f6c506 (HEAD -> master) Add needed functions for main.swift
3c53778 Add main.swift
870eb78 Register project files.
```

＊最新のコミット`Add needed functions for main.swift`のコミットID(ハッシュ)が新たに作成されています => `6f6c506 `


### 3. リモートリポジトリへ登録する

コミットを編集する前と編集した後ではコミットのIDが変わってしまっているためそのままgit pushするとエラーが発生します。そこでpushに-fオプションをつけます。強制プッシュとなりますので`master`や`main`、`develop`ブランチでコミットを編集して強制プッシュはしないようにしましょう。チーム開発をしている場合は特に。

`$ git push -u -f origin 作業ブランチ名`




## (2つ目)マージコミットを作らない
チームで開発では各メンバーはfeatureブランチで作業を行なっているかと思います。誰かがPull requestを完了させてdevelopブランチにマージされると他のメンバーはdevelopにマージされた情報を自分の作業ブランチであるfeatureブランチにマージする必要があります。
そこでfeatureブランチにdevelopをマージすると以下のようなマージコミットが作成されます。
`Merge branch 'develop' into feature/自分の作業ブランチ`
自分の作業したコミット以外にマージコミットができるので__コミットログが増えてしまいます__。

そこでコミットログが増えないようにするために利用できるのが__rebase__です。
rebaseはコミットをまとめるでも出てきたように多機能なコマンドです。
ここではマージコミットを作らないようにするための機能を紹介いたします。

まず通常のマージとリベースとの違いを比較いたします。

### マージ
あるキャラクターを作成する作業フローを図式しました。
AさんとBさんの2人でキャラクターを作成しています。
よくあるgit-flowでの開発フローです。
Aさんの作業が先に終わってdevelopにマージされました。
そこでBさんはdevelopが更新されたのでBさんが作業しているブランチにdevelopの情報をマージしました。
すると赤枠になっているマージコミットが作成されます。

![git-pull-rebase.001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/22202ffd-e65b-c6a5-563f-279fe96e6a40.png)


Bさんの作業は「耳の作成」「口の作成」「目と鼻の作成」の3つですがマージコミットが入ってきたので4コミットになっています。自分で作業していないコミットが一つ入ってきてしまっています。

![git-pull-rebase.002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/74c2e63d-615a-a514-1a89-fbdd5234b91a.png)


マージコミットが1つだけなので然程気にならないかも知れませんがもっと大人数で開発している場合はマージコミットがどんどん増えていきます。後から見返すにもコミットログが多くなってしまって他のブランチを含めてコミットログが見にくくなってしまいます。


そこでマージコミットを残さないやり方をしてみます。リベースの登場です。
### リベース
まずは以下のgitのコミットログ画像を参照ください。

![git-pull-rebase.003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/ea035384-9eea-84a5-6ca3-03777d82842a.png)


マージコミットがなく自分で作業したコミットのみになっています。
自分の作業ブランチのコミット数はdevelopをマージした場合は4つ、リベースした場合はコミットが3つとなっています。

どうやってマージコミットを残さないようにするかについて図説致します。

1. developが更新される
![git-pull-rebase.004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/df504085-f914-6198-cf0c-4ce551a54edc.png)


2. `git pull --rebase origin develop`コマンド実行
![git-pull-rebase.005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/17b57819-b416-d8be-8aae-8d5e51d7c147.png)


3. `git pull --rebase origin develop`コマンド完了後
![git-pull-rebase.006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/f52f94eb-89e6-9628-bc18-b48088b97c54.png)


Aさんが更新した顔の色を塗った変更がマージされたdevelopブランチが新たな起点となってBさんの変更が開始されています。


最後に比較です。
左がdevelopの変更をmergeしたもの、右がdevelopの変更をpull --rebaseしたものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59015/9ee8e4ab-d1f9-7dba-9293-03160a016005.png)

## まとめ
1. コミットをまとめる
2. マージコミットを残さない

この2つを実践して自分の作業ブランチのコミットログを綺麗に保ってみましょう。
レビュワーの方が気づいて「できるな！」と思われるかも知れません。
「余計なことするな」と言われる可能性もあるので事前に確認することで「できるな！」と思ってくれるかも知れませんので一度試してみてはいかがでしょうか。