# 画面設計書 41-コミット詳細

## 概要

本ドキュメントは、GitLabのコミット詳細画面の設計仕様を記載したものである。

### 本画面の処理概要

コミット詳細画面は、リポジトリ内の個別コミットの詳細情報を表示する画面である。コミットのメタデータ、変更されたファイルの差分、関連するパイプラインやマージリクエスト情報を確認できる。

**業務上の目的・背景**：ソフトウェア開発において、コードの変更履歴を追跡し、各変更の内容を詳細に確認することは、コードレビュー、デバッグ、変更の影響範囲の把握において重要である。本画面は、特定のコミットに対して包括的な情報を提供し、開発者がコードの変更内容を正確に理解できるようにする。

**画面へのアクセス方法**：以下のいずれかの方法でアクセス可能
1. コミット一覧画面からコミットSHAまたはコミットメッセージをクリック
2. ブランチ/タグ一覧から特定のコミットを選択
3. マージリクエスト画面からコミット一覧を経由してアクセス
4. 直接URL（`/:namespace/:project/-/commit/:sha`）を指定

**主要な操作・処理内容**：
1. コミット情報（SHA、作成者、日時、メッセージ）の表示
2. 変更ファイルの差分表示（インライン/サイドバイサイド）
3. コミットへのコメント追加
4. コミットの取り消し（Revert）操作
5. コミットのチェリーピック（Cherry-pick）操作
6. 関連するパイプライン状態の確認
7. 関連するマージリクエストの確認
8. ファイルツリーへの遷移

**画面遷移**：
- 遷移元: コミット一覧、マージリクエスト詳細、ブランチ一覧、タグ詳細
- 遷移先: ファイルツリー、ファイル表示、パイプライン詳細、マージリクエスト詳細

**権限による表示制御**：
- リポジトリ閲覧権限（`read_code`）が必要
- Revert/Cherry-pick操作は編集権限（`edit_tree`）が必要
- パイプライン情報の閲覧には`read_pipeline`権限が必要

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | コミット閲覧 | 主機能 | 個別コミットの詳細表示 |
| 22 | 差分表示（Diff） | 補助機能 | コミット差分の表示 |

## 画面種別

詳細

## URL/ルーティング

```
GET /:namespace/:project/-/commit/:id
GET /:namespace/:project/-/commit/:id/pipelines
GET /:namespace/:project/-/commit/:id/merge_requests
POST /:namespace/:project/-/commit/:id/revert
POST /:namespace/:project/-/commit/:id/cherry_pick
GET /:namespace/:project/-/commit/:id/diff_for_path
GET /:namespace/:project/-/commit/:id/diff_files
```

## 入出力項目

| 項目名 | I/O | 型 | 必須 | 説明 |
|--------|-----|-----|------|------|
| id | 入力 | String | 必須 | コミットSHA（40文字または省略形） |
| page | 入力 | Integer | 任意 | 差分ページ番号 |
| ref | 入力 | String | 任意 | 参照ブランチ名 |
| start_branch | 入力 | String | 任意 | Revert/Cherry-pick時の対象ブランチ |
| create_merge_request | 入力 | Boolean | 任意 | MR作成フラグ |
| target_project_id | 入力 | Integer | 任意 | Cherry-pick先プロジェクトID |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| コミットSHA | String | 完全なコミットハッシュ（短縮形も表示） |
| コミットメッセージ | Text | コミットのタイトルと説明 |
| 作成者 | User | コミット作成者の情報（アバター、名前） |
| コミッター | User | コミット実行者の情報（作成者と異なる場合） |
| 作成日時 | DateTime | コミット作成日時 |
| 署名情報 | Object | GPG署名の検証状態 |
| 親コミット | Array | 親コミットのSHAリンク |
| ブランチ一覧 | Array | このコミットを含むブランチ |
| タグ一覧 | Array | このコミットを指すタグ |
| パイプライン状態 | Object | 関連パイプラインのステータス |
| マージリクエスト | Array | 関連するMR情報 |
| 差分ファイル | Array | 変更されたファイルの差分 |
| コメント/ディスカッション | Array | コミットへのコメント |

## イベント仕様

### 1-Browse filesボタン押下

ファイルツリー画面（`/:namespace/:project/-/tree/:commit_sha`）へ遷移する。

### 2-Revertボタン押下

1. 確認モーダルを表示
2. 対象ブランチを選択（新規ブランチ作成またはブランチ指定）
3. MR作成オプションの選択
4. `Commits::RevertService`を実行
5. 成功時：MR詳細画面またはコミット一覧へ遷移
6. 失敗時：エラーメッセージを表示

### 3-Cherry-pickボタン押下

1. 確認モーダルを表示
2. 対象プロジェクト・ブランチを選択
3. MR作成オプションの選択
4. `Commits::CherryPickService`を実行
5. 成功時：MR詳細画面またはコミット一覧へ遷移
6. 失敗時：エラーメッセージを表示

### 4-差分表示切り替え

インライン表示とサイドバイサイド表示を切り替え。設定はCookieに保存される。

### 5-コメント投稿

1. コメント入力フォームを表示
2. コメント内容を入力
3. 送信時に`Notes::CreateService`を実行
4. コメント一覧を更新

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| コメント投稿 | notes | INSERT | コミットへのノート追加 |
| Revert実行 | なし | - | Gitリポジトリ操作のみ |
| Cherry-pick実行 | なし | - | Gitリポジトリ操作のみ |
| MR作成時 | merge_requests | INSERT | 新規MR作成 |

### テーブル別更新項目詳細

#### notes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | noteable_type | 'Commit' | コミットへのノート |
| INSERT | commit_id | コミットSHA | 対象コミット |
| INSERT | note | 入力テキスト | コメント本文 |
| INSERT | author_id | current_user.id | 投稿者 |
| INSERT | project_id | プロジェクトID | 所属プロジェクト |

## メッセージ仕様

| メッセージID | 種別 | メッセージ | 表示条件 |
|-------------|------|-----------|----------|
| MSG-001 | 成功 | "The commit has been successfully reverted." | Revert成功時 |
| MSG-002 | 成功 | "The commit has been successfully cherry-picked into {branch}." | Cherry-pick成功時 |
| MSG-003 | エラー | "Sorry, we cannot revert this commit automatically." | Revertコンフリクト時 |
| MSG-004 | エラー | "Git revision '{sha}' does not exist." | コミットが見つからない場合 |

## 例外処理

| 例外状態 | 処理内容 |
|---------|----------|
| コミットが存在しない | 404 Not Foundを返却 |
| 権限不足 | 403 Forbiddenを返却 |
| Revert/Cherry-pickコンフリクト | エラーメッセージを表示し、手動解決を促す |
| パイプライン取得エラー | パイプラインセクションのみエラー表示 |

## 備考

- 差分表示は1ページあたり20ファイル（`COMMIT_DIFFS_PER_PAGE`）でページネーション
- 大きな差分ファイルは折りたたまれて表示される
- Rapid Diffs機能が有効な場合、新しい差分表示UIが使用される

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、コミットの情報を表すモデルクラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | commit.rb | `app/models/commit.rb` | コミットのデータ構造、差分取得メソッド |
| 1-2 | diff.rb | `app/models/diff.rb` | 差分データの構造 |

**読解のコツ**: `Commit`クラスはActiveRecordモデルではなく、Gitリポジトリから取得したデータをラップするクラス。`raw`属性に`Gitlab::Git::Commit`が格納される。

#### Step 2: エントリーポイントを理解する

コントローラーの`show`アクションが処理の起点。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | commit_controller.rb | `app/controllers/projects/commit_controller.rb` | showアクション、before_action |

**主要処理フロー**:
1. **行17**: `authorize_read_code!` - 権限チェック
2. **行19**: `commit` - コミット取得（before_action）
3. **行20**: `define_commit_vars` - 差分情報の準備
4. **行34-63**: `show`アクション - レスポンス生成

#### Step 3: ビューを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/projects/commit/show.html.haml` | メインビュー構成 |
| 3-2 | _commit_box.html.haml | `app/views/projects/commit/_commit_box.html.haml` | コミット情報表示 |
| 3-3 | _diffs.html.haml | `app/views/projects/diffs/_diffs.html.haml` | 差分表示 |

**主要処理フロー**:
- **行12**: `commit_box`パーシャルでヘッダー情報表示
- **行14-20**: 差分表示パーシャルの呼び出し
- **行23-26**: ノート・コメント表示とRevert/Cherry-pickモーダル

#### Step 4: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | revert_service.rb | `app/services/commits/revert_service.rb` | Revert処理の実装 |
| 4-2 | cherry_pick_service.rb | `app/services/commits/cherry_pick_service.rb` | Cherry-pick処理の実装 |

### プログラム呼び出し階層図

```
CommitController#show
    │
    ├─ before_action :commit
    │      └─ @project.commit_by(oid: id)
    │
    ├─ before_action :define_commit_vars
    │      └─ @commit.diffs(options)
    │
    ├─ before_action :define_commit_box_vars
    │      └─ @commit.last_pipeline
    │
    ├─ before_action :define_note_vars
    │      ├─ @commit.grouped_diff_discussions
    │      └─ @commit.discussions
    │
    └─ render "show"
           ├─ render "_commit_box"
           ├─ render "_ci_menu"
           ├─ render "projects/diffs/_diffs"
           └─ render "shared/notes/notes_with_form"
```

### データフロー図

```
[入力]               [処理]                    [出力]

commit_id (SHA) ───▶ CommitController#show ───▶ HTML Response
                           │
                           ├─▶ Repository.commit_by()
                           │       └─▶ Commit Object
                           │
                           ├─▶ Commit#diffs()
                           │       └─▶ Diff Collection
                           │
                           └─▶ Commit#pipelines()
                                   └─▶ Pipeline Collection
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| commit_controller.rb | `app/controllers/projects/commit_controller.rb` | コントローラー | リクエスト処理 |
| show.html.haml | `app/views/projects/commit/show.html.haml` | テンプレート | メインビュー |
| _commit_box.html.haml | `app/views/projects/commit/_commit_box.html.haml` | テンプレート | コミット情報表示 |
| commit.rb | `app/models/commit.rb` | モデル | コミットデータ構造 |
| revert_service.rb | `app/services/commits/revert_service.rb` | サービス | Revert処理 |
| cherry_pick_service.rb | `app/services/commits/cherry_pick_service.rb` | サービス | Cherry-pick処理 |
| repository.rb | `config/routes/repository.rb` | ルーティング | URL定義 |
