# 機能設計書 119-LibGit2

## 概要

本ドキュメントは、Julia標準ライブラリ `LibGit2` モジュールの機能設計を記述する。libgit2のJuliaバインディングによるGitリポジトリ操作機能を提供するモジュールである。

### 本機能の処理概要

**業務上の目的・背景**：Juliaのパッケージ管理システム（Pkg）は、Gitリポジトリを介してパッケージのソースコードを管理・取得する。LibGit2モジュールは、libgit2（C言語で実装されたGitライブラリ）のJuliaバインディングを提供し、Gitリポジトリのクローン、フェッチ、プッシュ、マージ、リベース、ブランチ操作などをプログラム的に実行できるようにする。これにより、Pkgモジュールや他のツールがシェルコマンドに依存せずにGit操作を行える。

**機能の利用シーン**：パッケージのクローン・更新（Pkg内部）、リポジトリの状態確認（isdirty, isdiff）、ブランチの作成・切り替え（branch!, checkout!）、リモートリポジトリとの同期（fetch, push）、コミット履歴の分析（authors, revcount）、認証情報の管理（Credentials）。

**主要な処理内容**：
1. リポジトリのクローン（clone）、オープン（GitRepo）
2. リモートリポジトリとの同期（fetch, push）
3. ブランチ操作（branch, branch!, checkout!）
4. マージ・リベース（merge!, rebase!）
5. 差分検出（isdirty, isdiff, diff_files）
6. コミット操作（commit, iscommit, is_ancestor_of）
7. リポジトリ状態管理（snapshot, restore, transact）
8. 認証管理（CredentialPayload, credentials_cb）
9. Gitオブジェクト操作（GitTree, GitCommit, GitBlob, GitReference等）

**関連システム・外部連携**：libgit2（LibGit2_jll経由）、NetworkOptions（SSL証明書設定）、SHA（ハッシュ計算）。

**権限による制御**：リモートリポジトリへの認証（SSH鍵、HTTPSクレデンシャル）は`credentials`パラメータで制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | REPL / Pkg | 主画面 | パッケージのクローン・更新時のGit操作 |

## 機能種別

バージョン管理連携 / システム連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| repo_url | AbstractString | Yes (clone時) | リモートリポジトリURL | 有効なGit URL |
| repo_path | AbstractString | Yes (clone/open時) | ローカルリポジトリパス | 有効なファイルパス |
| branch | AbstractString | No | ブランチ名 | - |
| remote | AbstractString | No | リモート名。デフォルト="origin" | - |
| depth | Integer | No | シャロークローンの深さ。デフォルト=0（フル） | 非負整数 |
| credentials | Creds | No | 認証情報 | Credsプロトコル準拠 |
| callbacks | Callbacks | No | コールバック辞書 | - |
| force | Bool | No | 強制実行フラグ | - |
| fastforward | Bool | No | FFマージのみ許可 | - |

### 入力データソース

- ローカルファイルシステム（リポジトリパス）
- リモートGitサーバー（URL経由）
- SSH鍵 / HTTPSクレデンシャル（認証情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| repo | GitRepo | Gitリポジトリオブジェクト |
| oid | GitHash | コミットハッシュ（SHA-1） |
| branch_name | String | ブランチ名 |
| is_dirty | Bool | 未コミットの変更有無 |
| files | Vector{AbstractString} | 変更ファイル一覧 |
| state | State | リポジトリ状態スナップショット（head, index, work） |

### 出力先

- 戻り値としてGitRepo、GitHash、Bool等を返却
- ローカルファイルシステム（クローン、チェックアウト時）

## 処理フロー

### 処理シーケンス

```
1. LibGit2.clone(repo_url, repo_path) 呼び出し
   └─ 認証情報の設定（CredentialPayload）
   └─ RemoteCallbacksの構築
   └─ FetchOptions / CloneOptionsの構築
   └─ libgit2 git_clone()呼び出し
   └─ 認証結果の処理（approve/reject）
   └─ GitRepoオブジェクトを返却

2. LibGit2.fetch(repo) 呼び出し
   └─ リモートの取得（GitRemote or GitRemoteAnon）
   └─ 認証設定
   └─ FetchOptionsの構築（depth対応、libgit2 >= 1.7.0）
   └─ libgit2 git_remote_fetch()呼び出し

3. LibGit2.merge!(repo) 呼び出し
   └─ マージ対象のアノテーション取得
   └─ fastforwardの場合はFF可否を判定
   └─ マージ実行
```

### フローチャート

```mermaid
flowchart TD
    A["clone(repo_url, repo_path)"] --> B["CredentialPayload設定"]
    B --> C["RemoteCallbacks構築"]
    C --> D["FetchOptions構築"]
    D --> E["CloneOptions構築"]
    E --> F["git_clone() ccall"]
    F --> G{"成功?"}
    G -->|Yes| H["approve(cred_payload)"]
    G -->|No, EAUTH| I["reject(cred_payload)"]
    G -->|No, other| J["shred!(cred_payload)"]
    H --> K["GitRepo返却"]
    I --> L["rethrow"]
    J --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-119-01 | 遅延初期化 | libgit2はensure_initialized()で初回使用時にのみ初期化 | 全API呼び出し時 |
| BR-119-02 | 参照カウント | REFCOUNTで初期化/終了を管理。atexit()でgit_libgit2_shutdown | プロセスライフサイクル |
| BR-119-03 | SSL証明書 | NetworkOptions.ca_roots()で証明書パスを設定 | HTTPS通信時 |
| BR-119-04 | 認証フロー | 認証失敗時にreject、成功時にapproveでクレデンシャルを管理 | リモート操作時 |
| BR-119-05 | シャロークローン | depthパラメータはlibgit2 >= 1.7.0でのみ対応 | clone/fetch時 |
| BR-119-06 | トランザクション | transact()でsnapshot→処理→失敗時restore | 状態保全が必要な操作時 |

### 計算ロジック

- revcount: GitRevWalkerで左右のコミット数をカウントし、merge_baseとの差分を返す

## データベース操作仕様

該当なし（Gitリポジトリはファイルシステムベース）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| GitError(EAUTH) | 認証エラー | リモートリポジトリへの認証失敗 | 正しいクレデンシャルを提供 |
| GitError(Merge) | マージエラー | マージ対象のフェッチヘッドがない | フェッチを先に実行 |
| GitError(Rebase) | リベースエラー | トラッキング情報がない | リモートトラッキングブランチを設定 |
| ArgumentError | 引数エラー | credentialsとcallbacksの両方にクレデンシャルを設定 | どちらか一方のみ使用 |

### リトライ仕様

認証失敗時は`reject`でクレデンシャルを無効化し、ユーザーに再入力を促す仕組みがCredentialPayloadに組み込まれている。

## トランザクション仕様

`transact(f, repo)`により、操作前にsnapshot()でリポジトリ状態を保存し、失敗時にrestore()で元の状態に戻す擬似トランザクション機能を提供する。

## パフォーマンス要件

- ネットワーク操作（clone, fetch, push）のパフォーマンスはネットワーク帯域に依存
- ローカル操作（isdirty, branch!等）はミリ秒オーダー

## セキュリティ考慮事項

- 認証情報（パスワード、SSHキー）は`Base.shred!`で安全に消去される
- SSL証明書の検証はNetworkOptionsモジュール経由で設定
- GITHUB_REGEXでGitHub URLのパターンマッチングを行い、適切な認証方法を選択

## 備考

- LibGit2は多数のサブファイル（error.jl, utils.jl, types.jl, repository.jl等）にincludeで分割されている
- State構造体（head, index, work）でリポジトリのスナップショットを管理
- `with()`パターンで自動close()を実現

---

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

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

### 推奨読解順序

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

Gitオブジェクト型とState構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.jl | `stdlib/LibGit2/src/types.jl` | GitRepo, GitCommit, GitTree, GitReference, GitRemote等のGitオブジェクト型定義 |
| 1-2 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **52-56行目**: State構造体（head::GitHash, index::GitHash, work::GitHash） |
| 1-3 | consts.jl | `stdlib/LibGit2/src/consts.jl` | Git定数の定義（RESET_*, DELTA_STATUS等） |

**読解のコツ**: LibGit2はlibgit2のC APIの薄いラッパー。各Julia型はlibgit2のCポインタをラップしており、close()で解放する必要がある。`with()`パターンの使用が推奨される。

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

clone, fetch, push, merge!がメインのエントリーポイント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **577-622行目**: clone()の実装。認証設定→CloneOptions構築→git_clone() |
| 2-2 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **276-318行目**: fetch()の実装。リモート取得→認証→FetchOptions→git_remote_fetch() |
| 2-3 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **337-374行目**: push()の実装。リモート取得→認証→PushOptions→git_remote_push() |

**主要処理フロー**:
1. **584行目**: `CredentialPayload(credentials)`で認証ペイロード作成
2. **596-602行目**: FetchOptionsの構築（libgit2 >= 1.7.0でdepth対応）
3. **603-608行目**: CloneOptionsの構築
4. **610行目**: `clone(repo_url, repo_path, clone_opts)`で実際のクローン実行

#### Step 3: リポジトリ状態管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **967-986行目**: snapshot()の実装。HEAD、index、workの各ハッシュを保存 |
| 3-2 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **995-1007行目**: restore()の実装。unstage→work tree復元→index復元→head復元 |
| 3-3 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **1017-1025行目**: transact()の実装。snapshot→f(repo)→失敗時restore |

#### Step 4: 遅延初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **1035-1048行目**: ensure_initialized()。Threads.atomic_cas!で初回のみ初期化 |
| 4-2 | LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | **1050-1062行目**: initialize()。git_libgit2_init + SSL証明書設定 + atexit登録 |

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

```
LibGit2.clone(repo_url, repo_path; ...)
    |
    +-- ensure_initialized()
    |   +-- git_libgit2_init (ccall)
    |   +-- set_ssl_cert_locations()
    |
    +-- CredentialPayload(credentials)
    +-- RemoteCallbacks(callbacks)
    +-- FetchOptions(callbacks, depth)
    +-- CloneOptions(bare, branch, fetch_opts, remote_cb)
    +-- git_clone (ccall)
    +-- approve/reject(cred_payload)

LibGit2.transact(f, repo)
    |
    +-- snapshot(repo)
    |   +-- GitHash(repo, HEAD)
    |   +-- GitIndex → write_tree!
    |
    +-- f(repo)                            # ユーザー操作
    |
    +-- [失敗時] restore(state, repo)
        +-- reset!(repo, HEAD, "*")
        +-- read_tree!(idx, state.work)
        +-- checkout_index(repo, idx)
        +-- reset!(repo, state.head, RESET_SOFT)
```

### データフロー図

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

リモートURL    ───▶  clone()                   ───▶  GitRepo
+認証情報            libgit2 git_clone()              (ローカルリポジトリ)

GitRepo        ───▶  fetch()                   ───▶  更新されたref
                     libgit2 git_remote_fetch()

GitRepo        ───▶  snapshot()                ───▶  State
                     HEAD/index/workハッシュ取得        (head,index,work)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LibGit2.jl | `stdlib/LibGit2/src/LibGit2.jl` | ソース | メインモジュール。高レベルAPI（clone, fetch, push, merge!, branch!等） |
| types.jl | `stdlib/LibGit2/src/types.jl` | ソース | Gitオブジェクト型定義 |
| consts.jl | `stdlib/LibGit2/src/consts.jl` | ソース | Git定数定義 |
| error.jl | `stdlib/LibGit2/src/error.jl` | ソース | GitErrorモジュール |
| repository.jl | `stdlib/LibGit2/src/repository.jl` | ソース | リポジトリ操作の低レベルAPI |
| remote.jl | `stdlib/LibGit2/src/remote.jl` | ソース | リモート操作 |
| callbacks.jl | `stdlib/LibGit2/src/callbacks.jl` | ソース | 認証コールバック |
| commit.jl | `stdlib/LibGit2/src/commit.jl` | ソース | コミット操作 |
| merge.jl | `stdlib/LibGit2/src/merge.jl` | ソース | マージ操作 |
| rebase.jl | `stdlib/LibGit2/src/rebase.jl` | ソース | リベース操作 |
| reference.jl | `stdlib/LibGit2/src/reference.jl` | ソース | 参照操作 |
| diff.jl | `stdlib/LibGit2/src/diff.jl` | ソース | 差分操作 |
| gitcredential.jl | `stdlib/LibGit2/src/gitcredential.jl` | ソース | クレデンシャル管理 |
| Project.toml | `stdlib/LibGit2/Project.toml` | 設定 | パッケージ依存関係（LibGit2_jll, NetworkOptions, SHA） |
