状況で使い分けるGit術　前編

Qiita内にも数多に存在しているGitの記事。
コマンド然り、奥義や裏ワザもたくさんありますが正直全部覚えなくても開発はできます。

ただ、「機能はわかるけど使い所がわからない」という場合はあるかと思いますので、ある程度厳選してフィクションに沿った状況に応じた使い分けを残します。
※フィクションですよ

### 設定
* 月君 ... 慣れてくると調子に乗りミスをする常習犯。SouceTree崇拝者。
* A先輩 ... 開発チームメンバーの先輩。デキる意識高い系。
* P上司 ... 二人の上司。通称：レビューの鬼。

#### 前提
  * GitFlowを使用している
  * Macでvimを使用している

コンフリクト(競合)が発生
---
**月君**「ア"ッ！！プルリクだしたのにdevelopブランチとコンフリクトしてる…。A先輩がmergeした`paisen_A`ブランチが原因か。」

<img width="514" alt="スクリーンショット 2018-05-28 17.32.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/834a1288-2d7f-e760-644e-cedec736a4ad.png">

### **方法1　mergeで対応する**

**月君**「私のmoon_devブランチにdevelopブランチをmergeして発生するコンフリクトを直そう」

月君は「〜動きをチェックするための〜」を「〜動きをチェックしたいがための〜」に変更しましたが、
A先輩は「〜プロジェクト。」を「〜プロジェクトだよ。」にしていたようです。

![スクリーンショット 2018-05-28 17.37.50.png](https://qiita-image-store.s3.amazonaws.com/0/129996/1b277b8b-e4e7-d58f-fdd5-f70e7ba507de.png)

**月君**「よし、コンフリクトを解消してmoon_devブランチでマージコミットを作成したぞ。これでOKだ。」

コミット履歴は雑多になりましたが、コンフリクトは解決でき、無事マージされました。

<img width="565" alt="スクリーンショット 2018-05-28 17.53.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/8ed34e55-9a41-7ae8-468f-fe78335e26b7.png">

※マージ先のブランチでコンフリクト解消コミットを作成する方法もあります
※GithubなどはコンフリクトをWeb上で修正できます。便利ですね

### **方法2　rebaseで対応する**

**月君**「私のmoon_devブランチにdevelopブランチをrebaseして発生するコンフリクトを直そう」

rebaseでコンフリクト解消したら、`git add`でインデックスに登録し、`--continue`を叩きます。

```bash
$ (moon_dev) git rebase --continue
Applying: 変更しました。
```
**月君**「よし、じゃあtopicブランチをプッシュしよう。」

```bash
$ (moon_dev) git push origin moon_dev

error: failed to push some refs to 'git@github.com:hogehoge/hugahuga.git'
...
```
**月君**「謎のエラーだ！」

月君はテンパったようですが、このエラーはrebaseにしてコミット履歴が`develop`ブランチにくっついた事により、git logの整合性が取れないというエラーでした。
<img width="560" alt="スクリーンショット 2018-05-28 18.07.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/3bb5923c-092f-c8ee-3d17-707927b76c11.png">
↑moon_devのリモートブランチとローカルブランチのグラフが全く違います。

こういう時は`強制オプション -f`を使用します。(賛否両論有)

```bash
$ (moon_dev) git push -f origin moon_dev
```

<img width="547" alt="スクリーンショット 2018-05-28 18.11.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/f344f5f7-4c12-a952-d804-518deaaed132.png">

`moon_dev`リモートブランチが強制的に変更されました。

**月君**「rebaseの方がコミット履歴綺麗になるじゃん！！よーし、今後は多用するぞ！！」

mergeとrebaseの違いについては記事が世の中に溢れかえってるので割愛します。
ただ、
「コレを`rebase`したらコンフリクト地獄で終わるからmergeしよう」
「ここは`merge`するとコミットがわけわからないことになるからリベースしよう」
といった使い分けは必要ですし、

* mergeは動きが分かりやすいがコミット履歴は散らかりやすくなる
* rebaseはコミット履歴を綺麗にしやすいが調子こくとやらかしやすい

といった特徴もあるので一概に断言できません。
そこを勘違いした月君は・・・

コミット履歴をまとめる
---
**A先輩**「月君の作業コミット、多すぎてマージしたときに散らかってしまうから不要な部分は整理するようにしてね。」
**月君**「はい、わかりました。(わかってない)」

<img width="564" alt="スクリーンショット 2018-05-28 18.34.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/1b7a977a-f7b5-6f59-e320-4ff48ef03b25.png">

月君は`とりあえずコミット`をそのままpushしてプルリクエストを出していたようです。
これではコミット履歴が乱雑になる原因になってしまいます。

**月君**「ググったぞ！！`rebase -i`だ！！」

```bash
$ (moon_dev2) git rebase -i HEAD~5
```
`HEAD~5`はHEADから5つのコミットを対象とする。(`HEAD~~~~~`と同義)
2行目からの`pick`を`s(squashの略)`にして保存。
余計なコミットをsquashでまとめ、「一旦コミット」というコミットログを変更します。(vi系は`:wq`)

![スクリーンショット 2018-05-28 18.54.10.png](https://qiita-image-store.s3.amazonaws.com/0/129996/2d55f361-ab8f-8571-1441-153cdd36afae.png)
参考：[git rebaseでsquashした場合とfixupした場合の違い](https://qiita.com/shyamahira/items/47557acfe88ba392561e)

![スクリーンショット 2018-05-28 18.54.36.png](https://qiita-image-store.s3.amazonaws.com/0/129996/15f9e0f8-8ffd-a8ea-78aa-3f8c44348e0e.png)

コミットログを変更したら保存

<img width="600" alt="スクリーンショット 2018-05-28 18.59.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/9b7130b4-0601-d689-5d46-5363fa472950.png">

**月君**「`push -f`だ！！！」

```bash
$ (moon_dev2) git push -f origin moon_dev2
```

<img width="648" alt="スクリーンショット 2018-05-28 19.00.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/90e34e87-37d4-457f-a077-5d81aa731ebc.png">

コミットがまとまりました。

---
まとめるコミット数を間違えた場合

```bash
$ (moon_dev2) git rebase -i HEAD~6
```
(略)

<img width="590" alt="スクリーンショット 2018-05-28 19.04.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/3619e431-c711-e597-89de-ea5499072c26.png">

月君はこの間違いに気づかず...

**月君**「`push -f`だ！！！！」

<img width="615" alt="スクリーンショット 2018-05-28 19.07.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/129996/89a576a4-7d0e-60c8-0829-f2016bb92c75.png">

**月君**「！？」

こうなると、`develop`のHEADより1つ前のコミットで分岐された過去になってしまうので、
mergeしようとするとコンフリクトを起こします。
(今回はdevelopのHEADとmoon_devのHEADで修正されているファイルが同じな為)

---
月君のようによく考えず`rebase`したり`push -f`を多用するとその時は来てしまいます。

[後編「月君のやらかし事例とその対処」](https://qiita.com/moonwalkerpoday/items/bf9fb0545f003055fdee)