Git コミット関連コマンド [ 備忘録 ]

#### `git pull -r`
**機能**: リベース（rebase）を使ってリモートの変更を取り込む

**動作**:
1. リモートリポジトリから最新の変更を`fetch`
2. ローカルのコミットを一時的に退避
3. リモートの変更をローカルに適用
4. 退避したローカルのコミットを再適用

#### `git pull -r --autostash` (省略形: `git pull -r --au`)
**機能**: リベース + 自動stash/unstash

**`--autostash`オプション**:
- 作業ディレクトリに未コミットの変更があっても自動で処理
- プル前に自動で`git stash`を実行
- プル完了後に自動で`git stash pop`を実行
- 手動でstash/unstashする手間を省略

### git pullの種類比較

| コマンド | マージ方法 | 未コミット変更 | 用途 |
|---------|-----------|---------------|------|
| `git pull` | merge | エラーで停止 | 通常の同期 |
| `git pull -r` | rebase | エラーで停止 | 綺麗な履歴維持 |
| `git pull -r --autostash` | rebase + stash | 自動退避/復元 | 効率的な作業 |

### autostashの動作詳細

#### 通常の`git pull -r`の場合
```bash
# 未コミットの変更がある状態
echo "変更内容" >> file.txt

# プルしようとするとエラー
git pull -r
# → error: cannot pull with rebase: You have unstaged changes.
# → Please commit or stash them.

# 手動でstashが必要
git stash
git pull -r
git stash pop
```

#### `git pull -r --autostash`の場合
```bash
# 未コミットの変更がある状態
echo "変更内容" >> file.txt

# 自動でstash→pull→unstash
git pull -r --autostash
# → Saved working directory and index state WIP on main
# → (リベース実行)
# → Applied autostash.
```

### リベースとマージの違い詳細

#### **マージ (Merge)** の特徴
- **履歴**: 分岐とマージの履歴が残る
- **安全性**: 既存のコミット履歴を変更しない
- **用途**: チーム開発でブランチの統合履歴を明確に残したい場合

#### **リベース (Rebase)** の特徴  
- **履歴**: 直線的で綺麗な履歴
- **効率性**: マージコミットが作られない
- **用途**: 個人作業やクリーンな履歴を維持したい場合

### 視覚的な比較図

#### 初期状態
```
共通ベース: A---B (リモート/ローカル共通)
             |
            分岐点
```

#### 状況: リモートに新しいコミット、ローカルにも新しいコミット
```
リモート: A---B---C---D (他の人がコミット)
           \
ローカル:   \---E---F (自分がコミット)
```

#### マージの結果 (`git pull` または `git merge`)
```
A---B---C---D (リモート)
 \           \
  \---E---F---M (マージコミット)
```
- **M**: マージコミットが自動作成される
- **特徴**: すべての履歴が保持される
- **見た目**: 分岐した履歴

#### リベースの結果 (`git pull -r` または `git rebase`)
```
A---B---C---D---E'---F' (全て一直線)
```
- **E', F'**: 元のE, Fが新しい位置に移動（コミットIDが変わる）
- **特徴**: マージコミットなし
- **見た目**: 直線的な履歴

### 実際のgit logでの見え方

#### マージの場合
```bash
* a1b2c3d (HEAD) Merge branch 'main'
|\
| * d4e5f6g リモートのコミット
* | g7h8i9j ローカルのコミット
|/
* j1k2l3m 共通のベース
```

#### リベースの場合
```bash
* a1b2c3d (HEAD) ローカルのコミット
* d4e5f6g リモートのコミット  
* j1k2l3m 共通のベース
```

### コンフリクト時の動作比較（訂正版）

#### `git pull -r`の場合
```bash
# 未コミット変更があるとエラー
git pull -r
# → error: cannot pull with rebase: You have unstaged changes.

# 手動でstash→pull→unstash
git stash
git pull -r
git stash pop
```

#### `git pull -r --autostash`の場合
```bash
# 未コミット変更があっても自動処理
git pull -r --autostash
# → Saved working directory and index state WIP on main
# → (リベース処理)
# → Applied autostash.
```

### autostashの処理フロー図

```
作業開始
├── 未コミットの変更あり
└── git pull -r --autostash 実行

     ↓ 自動実行される処理

1. git stash (変更を一時退避)
├── Working Directory: クリーンな状態
└── Stash: 変更内容を保存

     ↓

2. git pull -r (リベース実行)
├── リモートから最新取得
└── ローカルコミットをリベース

     ↓

3. git stash pop (変更を復元)
├── Working Directory: 変更内容復元
└── Stash: 空になる

作業継続可能
```

## git addとgit pullの各コマンド解説

### 1. `git status`
**機能**: 現在のワーキングディレクトリとステージングエリアの状態を表示

**何がわかるか**:
- 変更されたファイル（Modified）
- 新規作成されたファイル（Untracked）
- ステージングエリアに追加されたファイル（Staged）
- 削除されたファイル（Deleted）

### 2. `git add`の様々な指定方法

#### すべて追加する方法
- `git add -A` = `git add --all`: すべての変更を追加
- `git add .`: カレントディレクトリ以下の変更のみ追加
- `git add -u`: 既存ファイルの変更と削除のみ追加（新規ファイルは除く）

#### 個別指定する方法

**単一ファイル指定**:
```bash
git add README.md
git add src/main.js
git add docs/guide.txt
```

**複数ファイル指定**:
```bash
git add file1.txt file2.txt file3.txt
git add README.md src/main.js docs/guide.txt
```

**フォルダ指定**:
```bash
git add src/                    # srcフォルダ内のすべて
git add docs/                   # docsフォルダ内のすべて
git add src/ docs/              # 複数フォルダ指定
```

**ワイルドカード指定**:
```bash
git add *.txt                   # すべての.txtファイル
git add src/*.js                # srcフォルダ内のすべての.jsファイル
git add **/*.css                # すべてのサブフォルダの.cssファイル
git add test_*                  # test_で始まるファイル
```

**パターン指定例**:
```bash
git add "*.md"                  # すべてのMarkdownファイル
git add "src/**/*.java"         # srcフォルダ内のすべてのJavaファイル
git add "!test/*"               # testフォルダ以外（除外指定）
```

### 実際の使用シナリオ

#### シナリオ1: 未コミット変更がある状態での同期
```bash
# ファイルを編集中（未コミット）
echo "作業中の変更" >> src/main.js

# 通常のpullだとエラーになる
git pull -r
# → error: cannot pull with rebase: You have unstaged changes.

# autostashなら自動で処理
git pull -r --autostash
# → Saved working directory and index state WIP on main
# → (リベース実行)  
# → Applied autostash.
# → 作業中の変更も復元される
```

#### シナリオ2: 効率的な開発フロー
```bash
# 作業中にリモートの最新を取得したい場合
git pull -r --autostash    # 変更を退避→最新取得→変更復元

# そのまま作業継続
# ファイル編集...

# 作業完了後
git add .
git commit -m "feat: 新機能完了"
git push
```

#### シナリオ3: チーム開発での使い分け

**頻繁に最新を取得したい場合**:
```bash
git pull -r --autostash    # 作業を中断せずに最新取得
```

**変更が確定している場合**:
```bash
git add .
git commit -m "WIP: 作業途中"
git pull -r                # 通常のリベース
```

### マージとリベースの使い分け指針

#### **マージを選ぶべき場面**
- **機能ブランチの統合**: 新機能開発完了時
- **チーム作業**: どのタイミングで何が統合されたかを明確にしたい
- **安全性重視**: 既存の履歴を絶対に変更したくない
- **公開されたブランチ**: 他の人も使っているブランチ

```bash
# 機能ブランチをmainに統合
git checkout main
git merge feature-branch
```

#### **リベースを選ぶべき場面**
- **個人の作業同期**: `git pull -r`で最新を取得
- **履歴の整理**: プルリクエスト前のコミット整理
- **クリーンな履歴**: プロジェクトの変更履歴をシンプルに保つ
- **ローカル作業**: まだプッシュしていないコミット

```bash
# 日常的な同期作業
git pull -r --auto

# プルリクエスト前の整理
git rebase -i HEAD~3  # 直近3コミットを整理
```

#### **注意すべきリベースの制約**
- **既にプッシュしたコミットはリベースしない**
- **他の人と共有しているブランチでは慎重に**
- **コンフリクト解決が複雑になる場合がある**

### 実践的な判断基準

| 状況 | 推奨方法 | 理由 |
|------|---------|------|
| 毎日の最新取得 | `git pull -r` | 履歴がクリーン |
| 機能ブランチ統合 | `git merge` | 統合履歴が重要 |
| コミット履歴整理 | `git rebase -i` | プルリク前の整理 |
| コンフリクト多発 | `git pull -r --auto` | 効率的な解決 |
| 共有ブランチ作業 | `git merge` | 安全性優先 |

### git statusとgit diff --cachedの説明

#### `git diff --cached`
**機能**: ステージングエリアと最新コミット（HEAD）の差分を表示

**重要なポイント**:
- `--cached`オプションにより、ステージされた変更の内容を確認
- コミット前に何がコミットされるかを確認できる
- `git diff`（オプションなし）は、ワーキングディレクトリとステージングエリアの差分

#### `git status`（再実行）
**目的**: `git add`後の状態確認
- ファイルが正しくステージングエリアに追加されたかを確認
- コミット準備完了の確認

### Gitの3つのエリアの関係図

#### `git diff --cached`
**機能**: ステージングエリアと最新コミット（HEAD）の差分を表示

**重要なポイント**:
- `--cached`オプションにより、ステージされた変更の内容を確認
- コミット前に何がコミットされるかを確認できる
- `git diff`（オプションなし）は、ワーキングディレクトリとステージングエリアの差分

#### `git status`（再実行）
**目的**: `git add`後の状態確認
- ファイルが正しくステージングエリアに追加されたかを確認
- コミット準備完了の確認

```
ワーキングディレクトリ  →  ステージングエリア  →  リポジトリ（HEAD）
   (作業領域)              (インデックス)         (コミット履歴)
        |                      |                     |
    ファイル編集              git add             git commit
        |                      |                     |
   - 新規ファイル          - 追加予定ファイル      - 確定した変更
   - 変更ファイル          - 変更予定内容
   - 削除ファイル          - 削除予定ファイル
```

## コマンド実行フローの可視化

```
初期状態
├── 変更されたファイル（Modified）
├── 新規ファイル（Untracked）
└── 削除されたファイル（Deleted）

     ↓ git status（1回目）

状態確認：変更内容をリスト表示

     ↓ git add -A

すべての変更をステージングエリアに移動
├── 変更されたファイル → Staged
├── 新規ファイル → Staged
└── 削除されたファイル → Staged

     ↓ git diff --cached

ステージングエリアの変更内容を表示
（実際のコード差分を確認）

     ↓ git status（2回目）

最終確認：コミット準備完了状態を表示
```

## 実際の使用例とファイル指定

### プロジェクト構造例
```
my-project/
├── README.md
├── package.json
├── src/
│   ├── main.js
│   ├── utils.js
│   └── styles.css
├── docs/
│   ├── guide.md
│   └── api.md
├── tests/
│   ├── main.test.js
│   └── utils.test.js
└── config/
    └── settings.json
```

### 具体的な指定例

#### ケース1: 特定のファイルのみ追加
```bash
git add README.md                # READMEのみ
git add src/main.js              # メインJSファイルのみ
git add package.json README.md   # 複数ファイル
```

#### ケース2: フォルダ単位で追加
```bash
git add src/                     # srcフォルダ内すべて
git add docs/                    # docsフォルダ内すべて
git add src/ docs/               # 複数フォルダ
```

#### ケース3: 特定の種類のファイルのみ
```bash
git add *.md                     # すべてのMarkdownファイル
git add src/*.js                 # srcフォルダのJSファイルのみ
git add **/*.test.js             # すべてのテストファイル
```

#### ケース4: 段階的にコミットしたい場合
```bash
# 機能実装のファイルのみ先にコミット
git add src/main.js src/utils.js
git commit -m "feat: 新機能実装"

# ドキュメントは別コミット
git add docs/
git commit -m "docs: ドキュメント更新"

# テストファイルも別コミット
git add tests/
git commit -m "test: テスト追加"
```

### コマンド実行結果例

#### 初期状態: `git status`
```
On branch main
Changes not staged for commit:
  modified:   README.md
  modified:   src/main.js
  modified:   src/utils.js
  deleted:    old_file.txt

Untracked files:
  docs/new-guide.md
  config/settings.json
```

#### 個別追加の例
```bash
# READMEのみ追加
git add README.md
git status
# → README.mdだけがStaged状態になる

# srcフォルダ全体を追加
git add src/
git status
# → src/内のすべてのファイルがStaged状態になる

# 残りのファイルを個別に追加
git add docs/new-guide.md
git add config/settings.json
```

#### 最終状態: `git status`
```
On branch main
Changes to be committed:
  modified:   README.md
  modified:   src/main.js
  modified:   src/utils.js
  new file:   docs/new-guide.md
  new file:   config/settings.json
  deleted:    old_file.txt
```

## まとめ

### `git add`の指定方法まとめ

| 指定方法 | 説明 | 例 |
|---------|------|-----|
| **ファイル指定** | 個別のファイルを指定 | `git add README.md` |
| **複数ファイル** | スペース区切りで複数指定 | `git add file1.txt file2.txt` |
| **フォルダ指定** | フォルダ内全ファイル | `git add src/` |
| **ワイルドカード** | パターンマッチング | `git add *.js` |
| **すべて** | 全変更を一括追加 | `git add -A` または `git add .` |

## 全体的なGitワークフローの統合

### 完全なワークフロー例
```bash
# 1. 最新のリモート変更を取得（リベースで履歴を綺麗に）
git pull -r --auto

# 2. 現在の状態確認
git status

# 3. ファイル編集
# ...

# 4. 再度状態確認
git status

# 5. 関連するファイルのみ追加
git add src/main.js src/utils.js

# 6. ステージされた変更内容を確認
git diff --cached

# 7. 最終状態確認
git status

# 8. コミット
git commit -m "feat: 新機能実装"

# 9. リモートにプッシュ
git push
```

### コマンドの使い分け指針

**`git pull`の選択**:
- `git pull -r`: 通常のリベース（未コミット変更があるとエラー）
- `git pull -r --autostash`: 効率的なリベース（未コミット変更を自動退避/復元）
- `git pull`: マージ方式（分岐履歴を保持したい場合）

**`git add`の選択**:
- `git add -A`: すべての変更を一括追加
- `git add ファイル名`: 論理的な単位でコミットしたい場合
- `git add フォルダ名/`: 特定の領域の変更のみ