Gitのコマンド一覧(4) -rebase, cherry-pick, reset-

# 概要
[Gitのコマンド一覧(3)](https://qiita.com/sepakTama/items/74b8c28da4d300a62135)では`fetch`や`pull`に関して説明したが、本ブログでは、`rebase`や`cherry-pick`など、gitのログを改編する（実際にはそのログも残るため改編ではないが）コマンドについて説明をする。本ブログの内容までを理解することで、一通りの基礎を学ぶことができ、あらゆる場面に対応できる知識を身につけることができるはずである。


# 主に使っているコマンド
- init
- add
- commit
- push
- clone
- status
- **log**
- **reflog**
- branch
- checkout
- remote
- fetch
- merge
- pull
- **rebase**
- **cherry-pick**
- **reset**
- rm


## rebase
`git rebase`はブランチの根元を修正する時に用いるものである。具体的には以下のような修正をしたい時に用いる。

![git_rebase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2207583/6e0338ba-f7db-fca1-a81f-d795ca171f99.png)

過去の歴史を改編するわけだからコンフリクトが起こる可能性が極めて高い。以下にコマンドの手順を載せる。

1. `git checkout develop`でブランチの根元を変えたいブランチにチェックアウトする。
1. `git rebase master`で幹のブランチ(master)を指定する。（この時点ではrebaseされない）
1. （恐らく）コンフリクトが生じるため、1ファイルずつ解消していく。
    1. 表示されているコンフリクトが解消できたら`git rebase --continue`でrebaseを継続する。
    1. もしrebaseを中断したい場合は`git rebase --abort`を実行すると、1の状態まで戻る。
1. 全てのコンフリクトが解消されれば**ローカルリポジトリ**でのrebaseは完了である。
    1. リモートリポジトリに反映させる場合には、add -> commit -> pushをするのだが、この際に`git push -f origin master`とオプション`-f`(force)をつける必要がある。

`-f`をつける理由として、ローカルリポジトリとリモートリポジトリでブランチの生える場所が異なるため必ずコンフリクトが生じてしまうためである。（試しに`git push origin master`を実行すると、エラーを吐き、`git pull`を要求されるが、当然`git pull`をしてしまっては意味がない）

このrebaseを用いる理由として、**ブランチの整理をする**が大きな理由だと筆者は考えている。例えば複数人が同時に様々な部分の回収をそれぞれブランチを切って行なっており、masterブランチがv0からv1になった場合、v0から生えてるブランチをv1にマージするのは運用・管理するには非常に見づらく一貫性のないgit運営に見えないだろうか。


## cherry-pick
`git cherry-pick`はあるブランチのコミットの内容を別のブランチに反映させることである。（筆者は初めこのコマンドを教えてもらった時、急に美味しそうなコマンドが出てきたな、と不覚にも思った。）主に以下のようなことを行える。

![git_cherry_pick.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2207583/a22524c3-67d6-4b50-9fbf-3af38ba0a027.png)

以下にコマンドの手順を載せる。（途中でログのハッシュ値に関して出てくるが、その詳細は本ブログの後半で述べる）

1. `git checkout develop`でコミットの情報を取りたいブランチにチェックアウトする。
1. `git log --oneline`でそのブランチのログとそのハッシュを確認する。（qを押すことで確認を終了する）
1. 情報を取りたいコミットの開始点の**一つ前**(ここでいうA)から終点(ここでいうY)のキャッシュを取得する。
1. `git checkout master`でコミットの情報を付与したいブランチにチェックアウトする。
1. `git cherry-pick [Aのハッシュ値]..[Yのハッシュ値]`を実行する。

上記で気をつけたいことは**情報を取りたいコミットの開始点の一つ前**である。次の章では触れてこなかったlogとそのハッシュに関して説明する。

# ログの確認
Gitでプロジェクトを管理していると、過去にどのようなコミットをしてきたかを確認することができる。また、上記のcherry-pickで出てきたログのハッシュ値についてもこのログを確認することで取得することができる。

## log
筆者が用いているコマンドは主に以下の二つである。

```terminal
> git log
```
`git log`は現在いるブランチのHEAD(最先端の部分、上記developブランチにいる場合、Zの部分)から親元を再起的にログを見ていくコマンドである。すなわち上記の例だとZ -> Y -> X -> Aとログが出力されることになる。`git log`では誰が(Author)いつ(Date)何を（commit等）を行なったかを確認することができる。

また、qを押すことで閲覧モードを解除できる。

```terminal
> git log --oneline
```
`--oneline`オプションをつけることで、`git log`の一つずつのログを一行ずつ表示することができる。

![git_log_oneline.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2207583/949e68bc-f652-993f-23d4-22aac765b681.png)

この左側の黄色の部分が**ログのハッシュ値**である。このハッシュ値を用いて`git cherry-pick`や`git reset`を行うことができる。

## reflog

```terminal
> git reflog
```

上記の`git log`とは異なり、あらゆる（他ブランチも含め）歴史を見ることができる。また、本ブログの最後で詳細に述べるが`git reset --hard`で過去の状態に戻った場合にも、`git reflog`コマンドを実行することで、リセットしたログまで残るため（'git log'では確認できない）、リセットする前の状態まで戻すことも可能である。

# 元のバージョンまで戻す
git管理のメリットとして、過去のバージョンに戻れることにある。例えば、新規で開発したものに重大なバグを見つけた場合や、ブランチ管理が正しく行われなかった場合に過去の状態に戻ることができる。

## reset

```terminal
git reset --hard [hash値]
```

上記のコマンドが筆者が（たまに）行うコマンドである。`git log --oneline`で取得したハッシュ値を入れることで、その状態まで戻すことができるコマンドである。正直な話`--hard`オプションは結構危ないコマンドとの認識なので、`git reset`を行うことがないように慎重にgit管理をしたいところである。

```terminal
git reset --soft
```

上記のコマンドでコミットの情報を戻すことも可能だが、筆者はあまりコミットの情報だけを元に戻すことはしないため詳細までは把握できていない（完全に勉強不足）。
詳細を知りたい方は筆者が読んでいて参考になった以下のサイトを確認してほしい。

https://qiita.com/shuntaro_tamura/items/db1aef9cf9d78db50ffe

## 次のブログでは
次のブログでは筆者が困ったことのある場面別に、解決方法と実行すべきコマンドについて紹介しようと思う。