Git コマンドのメモ

# はじめに

Gitコマンドは覚えることが多いので、あとで思い出せるようにメモる。

## 注意事項
 - リモートリポジトリは作成済みであること

## コマンド一覧
### git管理領域として初期化
---
 - `.git` ファイルが作成されるだけなので、README.mdなどを作成してからでもOK

```
$ git init
```

### git管理領域の状態確認（現在のブランチとかも確認可能）
---
```
$ git status
```

### インデックスへの追加方法
---
```
# ファイルを選択して追加する場合(スペースで複数指定可能)
$ git add test1.txt test2.txt
```

```
# 未登録ファイルを全て指定する場合
$ git add .
```

### ローカルリポジトリへのコミット実行
---
```
# コメントが一行の場合は一行コマンドで可能
$ git commit -m "コメント"
```

```
# きちんとコメントを書きたい場合は `-m` をつけなければいい
$ git commit
```

こんな感じでコメント入力モード（使い方は `vi` と同じ）に移行
`:wq` で確定
`:q!` でコミット中断

### コミットログ確認
---
```
$ git log
```

### もう少しグラフィカルにコミットログを見たい場合
---
```
$ git log --graph --decorate
```

### リモートリポジトリ名を記録する
---

 - リモートリポジトリ名は `origin` とするのが一般的
 - 記録しておくと、今後はURLの代わりに `origin` で済むようになる

```
$ git remote add <リポジトリ名> <リモートリポジトリURL>
```

### リモートリポジトリへプッシュ
---

 - リモートリポジトリ名を記録していない場合はURL入力でも可能
 - ブランチ名の初期値は `master` 
 - `-u` を指定することで、以降 `リポジトリ名` `ブランチ名` を省略可能
 - クローンしてきた環境の場合は最初から `リポジトリ名` `ブランチ名` 省略可能
 - リポジトリ名、ブランチ名はきちんとしていしたほうがいい

```
# 初回プッシュ時は必ずリポジトリ名とブランチ名を指定する必要あり
$ git push <リポジトリ名> <ブランチ名>[:<ブランチ名>]
```


### リモートリポジトリをクローン
---

```
$ git clone <リポジトリURL>　[<作成ディレクトリ名>]
```

### リモートリポジトリの状態をローカルリポジトリへ反映
---

 - リポジトリ名を省略した場合、originの状態を反映
 - ブランチ名を省略した場合、masterの状態を反映
 - 編集箇所が衝突していなければ自動的にマージされる
 - 編集箇所が衝突しているとファイルが暫定マージ状態になるので、手動で修正する必要あり

```
$ git pull [<リポジトリ名>] [<ブランチ名>]
```

### ブランチの切り替え
---

 - 現在使用しているブランチの先頭は `HEAD` と呼ばれる
 - 変更中（未コミット）ファイルを一時退避させる場合は `stash` を使う

```
$ git checkout <branchname>
```

 - ブランチを作成し同時にHEADを切り替える場合

```
$ git checkout -b <branchname>
```


### ブランチの一覧表示
---

```
$ git branch
```

　　- リモートリポジトリも含めて一覧を表示する場合

```
$ git branch -a
```



### ブランチの作成
---

 - これだけでは、ブランチを作成しただけでHEADは移動していないことに注意
 - 同時にブランチ移動したい場合は　`$ git checkout -b <branch name>` を使う

```
$ git branch <branchname>
```


### ブランチをマージする

 - マージされる側のブランチにHEADを移動させておくこと（ `git checkout <branchname>` ）

```
$ git merge <branchname>
```

### ブランチをリベースする
---
 - マージとの違いを理解して実施すること

```
$ git rebase <branchname>
```


### ブランチの削除
---

  - 編集中の状態が残っている場合はこれだと失敗する
  - 強制的に削除する場合は `-d` の代わりに `-D` を使う

```
$ git branch -d <branchname>
```

### フェッチ
---

 - フェッチすると、無名ブランチが新規に作成される
 - ローカルリポジトリとマージする場合は `merge` か `pull` する

```
$ git fetch [<リポジトリ名>] [<ブランチ名>]
```

### その他の小技

#### 編集内容を破棄（直近のコミットに戻す）

```
$ git reset --hard HEAD
```

ちなみに、`--soft`をつけると、HEAD以外（インデックス、ワーキングツリー）は一切動かない。
`--soft`/`--hard`をつけない（=`--mixed`）場合、HEADとインデックスが影響を受け、ワーキングツリーは動かない。
`--hard`をつけた場合は、全て（HEAD、インデックス、ワーキングツリー）が指定のコミットに移動する。

#### 特定のファイルだけ編集内容を破棄

```
$ git checkout <filename>
```


#### リモートのブランチを削除する

 - 空っぽのブランチをpushしているのと同じ ＝ 削除

```
$ git push <リポジトリ名> :<削除するブランチ名>
```

#### リモートのブランチ名変更

 - カレントブランチの名前を変える場合は `old_branchname` は省略可能

```
$ git branch -m [<old_branchname>] <new_branchname>
```

#### 編集状態を一時退避

```
$ git stash [save]
```

#### stash一覧

```
$ git stash list
```

#### 退避したものを復元

```
$ git stash pop <復元させるlist_no>
```

### ブランチの派生元を移動させる(rebase --onto）

 - master（親）ブランチから派生している開発（子）ブランチを`rebase`する場合は、特に`--onto`を付ける必要は無い。（所謂普通のrebase）
 - 開発（子）ブランチから更に派生している孫ブランチを、master（親）ブランチへリベースする場合は、`--onto`を指定しないと子ブランチからの分岐点（共通祖先）のコミットを含めてrebaseされてしまう。
 - [参考になりました](https://liginc.co.jp/web/tool/79390)

１. 付け替える元となる（push先）ブランチを最新化する

```
$ git checkout <base_branch>
$ git pull
```

２. 開発ブランチへ移動する

```
$ git checkout <dev_branch>
```

３. ログから移動させるコミットIDを探す

 - この時のポイントは、自分がコミットしたコミットIDではなくて **「その一つ前の」** コミットIDを確認する

```
$ git log
```

４. rebase コマンド実行（コンフリクトがあれば解消）

```
$ git rebase --onto <base_branch> <3で確認したコミットID>
# 発生したコンフリクトを解消したら以下を実行し、全て解消されるまで繰り返す
$ git rebase --continue
```

５. push

 - 差分がないということで reject されることが多いので、必要に応じて -f をつける。

```
$ git push [-f] <リポジトリ名> <ブランチ名>
```

### 特定のブランチの最新ソースをローカルブランチに反映させる

 - 上記の手順をめっちゃ簡潔にしたバージョン。


```
$ git pull --rebase <リポジトリ名> <ブランチ名>
```

6. reset

 - 最低限、`--soft`、`--hard`、`HEAD`、`HEAD^`の意味を理解しておく

  - `--soft`はHEADだけを移動させる。（インデックス、ワーキングツリーは変化させない）
  - `--hard`はHEAD,インデックス、ワーキングツリーすべてを移動させる。
  - なにも指定しない場合（`--mixed`）は、HEAD、インデックスだけ移動させる。（ワーキングツリーは移動させない）
  - ファイル名を指定しない場合は、ブランチ全体が対象となる

以下はHEADをHEADの位置に移動させる。という意味なので、結果として何も変化しない。

```
$ git reset --soft HEAD
```

以下はHEAD、インデックスをHEADの位置に移動させる。（インデックスに登録されている変更が戻る）
`filename`を指定しない場合は、ブランチ全体のインデックス登録状態が消える

```
$ git reset [--mixed] HEAD [filename]
```

以下は、変更すべてをなかったコトにする
※厳密にはHEADの位置に移動させることになるので、予め`git reset --soft XXXX`でHEADを移動させている場合は、とんでもない場所に移動するので注意

```
$ git reset --hard HEAD
```

#### コミットをまとめる

複数のコミットが存在する状態で、`git log`を実行し、**まとめたいコミットの直前のコミットID**をメモって、以下のコマンドを実行

```
$ git rebase -i <メモったコミットID>
```

実行すると対話型の画面が表示されるので、まとめたいコミット（下ほど最新）を`pick`から`s`または`f`に書き換える。
※`s`ならsquash。コミットコメントまで編集出来る。
※`f`ならfixup。コメント編集はなし。（まとめる側のコメントは消失）