git 基本操作


### 作業の流れ
- mainブランチから作業ブランチを切る（git checkout -b sagyo_branch_name）
- 作業する
- addする
- commitする（git commit）
- remoteにpushする（git push origin sagyo_branch_name）
- pull requestを作る
- review依頼する
- 修正がある場合は修正する
- approveもらったらmergeする
- ローカルのmainブランチ（or masterブランチ）とリモートの最新を一致させる（git pull origin main --rebase）

### GitHub flow
[GitHub flow](https://zenn.dev/ryo_4947123/books/497459787cb294/viewer/branchstrategy_githubflow)
    
### 変更を取り込む
#### Git Merge: feature/bugFixなどの変更をmainに取り込む
- コミットは１つ増える
```
git checkout main
git merge feature
```

### Git Rebase: 変更履歴をきれいに残しながら、変更を取り込む 
- 現在のブランチの内容が、指定したブランチに取り込まれる
- 変更履歴を、**指定したブランチの根本に付け替える**イメージ
```
git checkout feature
git rebase main
```


```
A--B--C------F--G(master)
       \
        D--E(feature)
```
↓
```
A--B--C------F--G(master)
                 \
                  D--E(feature)
```


### 変更を元に戻す
#### Git Reset: ローカルや他に人が触らないブランチの変更をキャンセルする 
- ブランチのポインタを後方に移動することで変更のキャンセルを行う
- そもそも前のコミットがなかったかのように、ブランチのポインタを元に戻してくれる

```
git reset HEAD~1
```

#### Git Revert: 他の人も使っているリモートにあるリポジトリのブランチの変更をキャンセルする 
- 巻き戻したいコミットの下に新しいコミットができる
- 新しいコミットは、コミット内容を巻き戻す変更が含まれる

```
git revert HEAD
```

### コミットを移動する
#### Git Cherry-pick: 現在の位置（HEAD）の下に一連のコミットをコピーする
```
// commit1とcommit2を現在の位置の下にコピーする
git cherry-pick commit1(ハッシュ) commit2(ハッシュ)
```

### コミットをまとめる 
- 不要なコミットをしてしまった場合にコミットをまとめることができる
- 最新コミットから2つ目までのコミットを確認
```
git rebase -i HEAD~2
```

- vimなどのエディタが開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738663/c3721f0b-4d46-2d8d-1eb2-946f872eb88d.png)


- まとめたいコミットを、`pick`⇒`s`に修正
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738663/81b3c67a-3828-9c28-c8d9-85f09e550379.png)

- コミットメッセージを再度修正する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738663/3fce6429-5b7e-aee0-11af-241e02f29c51.png)

- コミットが１つにまとまる

### 過去の変更を修正する

- ```git rebase -i```でコミット順序を変更し、修正したいコミットを一番先頭に持ってくる
- ```git commit --amend```で修正する
- ```git rebase -i```を再度使用して、順序を元に戻す


### Git Tag: コミットに恒久的なマークを付ける 
- ブランチのように参照でき、永久的な印をコミットに付けることが可能
- ブランチと違い、***コミットを新たに作ってもタグは動かない***

```
// C1にタグV1を付与する
git tag v1(タグ番号) C1(コミットのハッシュ)
```

### Git Describe: 最も近く関係のあるタグを記述する  

```
// <参照>にはコミットの参照表現（ブランチ、タグ、コミットハッシュなど）を入れる
git describe <参照>
```
結果は、
```
// <タグ>から数えて<コミット数>番目の<ハッシュ>
<タグ>_<コミット数>_g<ハッシュ>
```
となる。

### Git checkout ~n/Git checkout ^n: 親の指定を詳細に行う
- Gitは通常、マージコミットから「一つ目」の親、マージされた側のブランチの親を選択する
- しかし、^で数を指定することでこのデフォルトの動作を変えることができる

```
// 一つ上のコミットに移動する
git checkout HEAD~
```

```
// 一つ目の親（マージされた側のブランチ）に移動する
git checkout main^
```

```
// 二つ目の親に移動する
git checkout main^2
```

```
// 修飾子を複数繋げることも可能
git checkout HEAD~^2~2
```

### リモートブランチの内容をローカルブランチに取り込む
#### Git Fetch: リモートリポジトリからデータを取得する 
- git fetchの動作は下記２つ
    - リモートにあってローカルリポジトリにないコミットをダウンロードする
    - リモートブランチの位置を更新する（origin/mainなど）

- ``引数を付けない``と、リモート上に存在する全てのブランチのコミットをダウンロードする
```
// 引数なし
git fetch
```

- 下記例では、リモートのfooブランチに移動して、ローカル上に存在しないコミットを全てローカルのorigin/fooブランチにダウンロードする
```
// git fetch <remote> <place>
git fetch origin foo
```

- 下記例では、``<source>``がリモート上の場所になり、``<destination>``がそのコミットを置くローカル上の場所になる
```
// git fetch origin <source>:<destination>
git fetch origin foo:bar
```

#### Git Pull: リモートブランチの内容をローカルブランチに反映する
- リモートの内容をリモートブランチに取り込んで、ローカルブランチにmergeする
- git fetch + git merge

- 下記例では、``git fetch origin foo; git merge origin/foo``と同じ働きをする
```
// git pull <remote> <place>
git pull origin foo
```
- 下記例では、``git fetch origin foo:bar; git merge bar``と同じ働きをする
```
// git pull origin <source>:<destination>
git pull origin foo:bar
```

#### Git Pull --Rebase
- git pull + git rebase


### リモートトラッキングを行いながら、新しいブランチをチェックアウトする
#### リモートトラッキングとは
- git clone時に、ローカルブランチの``main``がリモートブランチの``origin/main``を追跡するように設定される

```
// 方法①
// origin/mainのリモートブランチを追跡する、fooブランチを作成する
git checkout -b foo origin/main
```

```
// 方法②
// origin/mainのリモートブランチを追跡する、fooブランチを作成する
git branch -u origin/main foo
```

### ローカルブランチの内容をリモートリポジトリに反映する
#### Git Push
- ``引数を付けない``と、現在チェックアウトされているブランチのプロパティを参照する
- その後、pushするリモートブランチを決める
```
// 引数なし
git push
```

- git pushに``引数を付ける``と、リポジトリの ``<place>`` ブランチに移動し、すべてのコミットを取得
- その後、リモートの ``<remote>`` にある ``<place>`` ブランチへ移動し、存在していないコミットをリモートのリポジトリに反映
```
// git push <remote> <place>
git push origin main
```

- 引数で、``<source>``と``<destination>``を指定すると、pushするコミットがどこから来て(source)、どこへ行くのか(destination)を指定できる

```
// git push origin <source>:<destination>
git push origin foo:main
```