普段使いするGitのコマンドをまとめる

## はじめに
Gitのコマンドは反応で叩くことができるのが理想ですが、VSCodeの左上をぽちぽちしてしまったり、都度調べてしまったりすることが多々あるので、この機会にまとめたいと思います。

## コミット履歴の確認
```sh
  % git log
```
## 差分の確認
### ステージングしていない差分(working treeとindexとの差分)
```sh
  % git diff
```
- ※ untrackedなファイルは含まれません
    - `git add -N`を実行することによって表示させることができます。
    - https://git-scm.com/docs/git-add#Documentation/git-add.txt--N
### ステージングしている差分(indexと最新のcommitとの差分)
```sh
  % git diff --staged
  % git diff --cached
```
- `最新のcommit`と書きましたが、比較するcommitは指定することができます。
    - commitを指定しなかった場合、デフォルトでHEADが比較対象になります。
- `--cached`と`--staged`は同じ意味です。
    - > --staged is a synonym of --cached.
    - https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-emgitdiffemltoptionsgt--cached--merge-baseltcommitgt--ltpathgt82308203
    - かつてindexのことをcacheと呼んでいた名残のようです。
        - https://github.com/git/git/blob/564d0252ca632e0264ed670534a51d18a689ef5d/Documentation/gitcli.txt#L201C11-L205C1
### commit間の差分
```sh
  % git diff commit_1 commit_2
```
### リモートリポジトリとの差分
```sh
  % git diff origin/development
```
- `development`ブランチですでにpushしていると仮定しています。
- `リモートリポジトリ`と書きましたが、pushした時点でそのbranch(ポインタ)が指していたcommitとの差分になります。
    - 他の人が同じリモートのブランチにcommitを追加している場合は、`git pull`して差分を取る必要があります。

## ステージング
### カレントディレクトリ配下をステージング
```sh
  % git add .
```
### 特定のファイルを部分的にステージング
```sh
  % git add -p path
```
- 上記コマンドを実行すると、`(1/1) Stage this hunk [y,n,q,a,d,s,e,?]?`のように選択できるので`e`を選び、含めたい差分を精査します。
    - それぞれのオプションの意味は以下です。
    - https://git-scm.com/docs/git-add#Documentation/git-add.txt-patch
### untrackedなファイルを部分的にステージング
```sh
  % git add -N untracked_file
  % git add -p untracked_file
```
- 新規作成したファイルは`untracked`なので、そのままでは、部分的にステージングに上げていくことができないので`git add -N`を実行します。
    - https://git-scm.com/docs/git-add#Documentation/git-add.txt--N
### ステージングの取り消し
#### HEADが存在しない時(初回commitが終わっていない)
```sh
  % git rm --cached path
```
- indexから削除されますが、差分は残ります。
    - indexの中身は`git ls-files --stage`で確認できます。
    - https://git-scm.com/docs/git-rm#Documentation/git-rm.txt---cached
- 別の使い道ですが、後々トラッキングをやめたくなったファイルを`.gitignore`に追加した時などにも使います。
    - https://qiita.com/fuwamaki/items/3ed021163e50beab7154
#### HEADが存在している時
```sh
  % git reset HEAD path
```
- 差分をそのままで、現在のHEADの位置まで戻ります。
- resetの後ろを指定しなかった場合デフォルトで`HEAD`が入ります。
    - https://git-scm.com/docs/git-reset#Documentation/git-reset.txt-emgitresetem--patch-plttree-ishgt--ltpathspecgt82308203

## コミット
### 普通にコミット
```sh
  % git commit -m "Commit message"
```
### 修正用のコミット
```sh
  % git commit --fixup commit
```
- 特定のcommitに修正を加えたcommitを作りたい時に使います。
    - レビューをいただいた際によく使います。
- コミットメッセージは、対象のコミットのコミットメッセージの先頭に`fixup!`が付いたものになります。
- fixupしたcommitの差分は対象のcommitに含めることができます。
    - `% git rebase -i --autosquash commit`
    - https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---autosquash
### commit取り消し
```sh
  % git reset HEAD~ --soft
```
- indexもworking treeもリセットすることなく、`HEAD~`の位置まで戻ります。
- commitを打つ直前の状態になります。
```sh
  % git reset HEAD~
```
- indexをリセットし、woking treeはリセットせずに、`HEAD~`の位置まで戻ります。
- 変更差分は全て残りますが、ステージングはされていない状態になります。
- オプションを指定しなかった場合は`--mixed`が適用されます。
    - `git reset HEAD~` == `git reset HEAD~ --mixed`
    - https://git-scm.com/docs/git-reset#Documentation/git-reset.txt-emgitresetemltmodegtltcommitgt
```sh
  % git reset HEAD~ --hard
```
- indexもworking treeも共にリセットし、`HEAD~`の位置まで戻ります。
- `HEAD~`以降の変更差分が全てなくなります。(untrackedなファイルは残ります。)
### 「commitを取り消した」という履歴を残してcommit取り消し
```sh
  % git revert HEAD
```
- コミットメッセージは、対象のコミットのコミットメッセージの先頭に`Revert`が付いたものになります。
- そのcommitに対してrevertをするとRevertのRevertになるので元に戻すことができます。

## 修正・整理
### 直前のコミットメッセージの修正
```sh
  % git commit --amend
```
### 特定のコミットメッセージの修正
```sh
  % git rebase -i commit
```
- 指定したcommitよりも新しいcommitが一覧で表示されます。
- `pick`になっている部分を`r`もしくは`reword`で書き換え保存することで、コミットメッセージを編集できるようになります。
- `% git rebase -i HEAD~`をし、rewordを指定した場合、`% git commit --amend`と同じ状態になります。
- https://docs.github.com/ja/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/changing-a-commit-message#amending-older-or-multiple-commit-messages
### コミットをまとめる
```sh
  %  git rebase -i commit
```
- 上記と同様ですが、commitをまとめる場合は`s`もしくは`squash`で書き換えます。
- squashを指定したcommitは直前のcommitに取り込まれます。
### 最新のmain(master)の差分を取り込む
```sh
  % git checkout main
  % git pull origin main
  % git checkout development
  % git rebase main
```
- mergeよりもrebaseの方が履歴が綺麗になるので、rebaseを使っています。
- この場合、リモートにpushする際にはfast-forwardではなくなっているので、force pushが必要になります。
### 特定のcommitを適用させたい
```sh
  % git cherry-pick commit
```
- 特定のコミットだけを現在のブランチに追加したい場合に使います。
## 検索
```sh
  % git grep "target_word"
```
- オプション
    - https://git-scm.com/docs/git-grep
## コミットせずに一時的に差分を退避
- コミットよりも削除難易度が低いので、個人的には`wip`などのコミットメッセージをつけてcommitしてしまった方がいいと思います。
- 「消しちゃった〜」となることが結構あります。
### 普通に退避
```sh
  % git stash
```
### 名前をつけて退避
```sh
  % git stash save stash_message
```
### untrackedなファイルもまとめて退避
```sh
  % git stash -u
  % git stash save -u stash_message # 名前付き
```
### 退避した差分を展開する
```sh
  % git stash pop
  % git stash apply stash@{0}
```
- stashはstack構造で管理されているので`pop`をした場合、1番最後にstashした差分が展開されます。
    - stackの状態は`% git stash list`で確認することができます。
- `pop`の場合、差分の展開とともにstackからは削除されますが、applyの場合はstackに残り続けます。
### 退避した差分を削除する
```sh
  % git stash drop stash@{0}
```
- 展開することなく削除します。