Gitコマンドメモ

よく忘れるので自分用メモ

## 基本

### リポジトリ作成

```shell
git init
```

### ワークスペースの状態確認

```shell
git status
```

### インデックスにステージング

```shell
git add .
git add README.md  # ファイルを指定する場合
```

### リポジトリにコミット

```shell
git commit -m "message"
git commit -am "message"  # ステージング（git add .）とコミットを同時に行う
```

### ステージングを取り消す

```shell
git reset
git reset README.md  # ファイルを指定する場合
```

### コミット前の変更を破棄

```shell
git checkout .
git checkout README.md  # ファイルを指定する場合
```

### コミット後の変更を破棄（任意の状態に戻す）

```shell
git reset HEAD^ --hard  # 1つ前のコミットまで戻す
git reset HEAD^^^ --hard  # 3つ前のコミットまで戻す
git reset ab32c61 --hard  # コミットID ab32c61… まで戻す
```

リセットの構文は以下です。

`git reset [リセット先の状態] [リセットのモード]`

#### リセット先の状態

1番先頭のコミットを`HEAD`と表現します。その後につける`^`の数だけいくつ手前のコミットかを表します。つまり、3つ前のコミットまで戻りたければ`HEAD^^^`と書きます。

また、コミットIDを指定することも可能です。コミットIDは全文字指定してもいいですが、先頭数文字でも一意に特定できればOKです。

#### リセットのモード

gitでの作業を、「変更」→「ステージング」→「コミット」としたとき、どの作業状態に戻すかを以下の3つから選択します。

|モード|どこまでリセットするか？|つまりどうなる？|
|:--|:--|:--|
|--soft|「コミット」だけリセットする。|ワークスペースのファイルが変更されたあと、インデックスにステージングされた状態まで戻る。|
|--mixed|「ステージング」までリセットする。|ワークスペースのファイルは変更されたままだが、インデックスが空の状態になる。|
|--hard|「変更」含めすべてリセットする。|ワークスペースのファイルがすべて変更前まで戻る。|


### タグを管理する

```shell
git tag tag001  # HEADにタグtag001をつける
git tag tag001 ab32c61  # 特定のコミットにtag001をつける
git tag  # タグを確認する
git show tag001  # tag001の詳細を確認する
git tag -d tag001  # tag001を削除する
```

### コミットの一覧を確認する

```shell
git log
git log --oneline  # 1コミット1行で確認したい場合
git log --all  # 他のブランチも確認したい場合
git log --all --graph  # 他のブランチとの関係をツリーで確認したい場合
```

## ブランチ関係

### ブランチを作る

```shell
git branch develop  # HEADからブランチ作成（ブランチは切り替えない）
git checkout -b develop  # HEADからブランチ作成してブランチ切り替え
git checkout ab32c61 -b develop  # 特定のコミットからブランチ作成してブランチ切り替え
```

### ブランチの一覧を取得する

```shell
git branch
```

### ブランチを切り替える

```shell
git checkout develop
```

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

```shell
git checkout master
git merge develop --no-edit
git merge develop --no-edit --no-ff  # ファストフォワードなしでマージ
```

:::note info
ファストフォワードとは、マージ時に片方のブランチでしか作業をしていないがために、マージコミットが作られないようなマージの仕方のことです。このような状態でも明示的にマージコミットを作成したい場合に`--no-ff`オプションを使います。
:::

### ブランチを削除する

```shell
git branch -d develop
```

### ブランチ名を変更する

```shell
git branch -m master main
```

## リモート関係

### リモートリポジトリを管理する

```shell
git remote add origin https://github/com/[ユーザ名]/[リポジトリ名].git  # 追加する場合
git remote rm origin  # 削除する場合
git remote  # 一覧を確認する場合
```

### リモートリポジトリにプッシュする

```shell
git push origin main  # originリモートにmainブランチをプッシュ
git push origin tag001  # tag001の情報をリモートにプッシュ
git push origin --tags  # リモートにないタグを一斉送信
git push --set-upstream origin main  # 現在のブランチにアップストリームを設定
git push  # アップストリームの設定に従ってプッシュ
```

:::note
`git push`だけではリモートにタグ情報が送られません。`git push origin --tags`などでタグ情報を別途送信する必要があります。
:::

### リモートリポジトリをクローンする

```shell
git clone https://github/com/[ユーザ名]/[リポジトリ名].git
git clone https://github/com/[ユーザ名]/[リポジトリ名].git [ディレクトリ名]  # クローン先ディレクトリを指定する場合
```

### リモートリポジトリとの差分の有無を取得する

```shell
git fetch
git log --oneline  # 変更がlogで確認できる
```

### リモートリポジトリの変更をローカルに反映する

```shell
git pull origin main  # originリポジトリのmainブランチを取得
```

:::note
`pull`は、`fetch`と`merge`を一度に行うコマンドです。この本質を理解しておいて、通常は`pull`だけ行えば問題ありません。
:::

### リモートリポジトリへのコミットを取り消す

```shell
git revert HEAD --hard  # 最新のコミットを取り消す場合
```

:::note
ローカル内のコミットの取り消しには`reset`コマンドが使えましたが、リモートへのコミットはそう簡単に取り消せません。なぜなら、コミットしてから取り消すまでの間に、取り消したいコミットを`pull`してしまっているユーザがいるかもしれないからです。そのため、`revert`は実際にはコミットを取り消しているわけではなく、コミットをなかったことにするような内容で新たにコミットするような動きをしています。
:::