
# はじめに

## インストール

ComposerでPitmasterをインストールします：

```bash
composer require pitmaster/pitmaster
```

## 必要条件

- **PHP 8.2+**（読み取り専用クラス、enum、コンストラクタープロモーションを使用）
- オブジェクトの圧縮／展開用の**ext-zlib**（ほとんどの環境で標準搭載）
- 操作状態ファイルとGit LFSのAPIペイロード用の**ext-json**
- **ext-mbstring**（`composer.json`で宣言されているため、Composerのインストール時に必要）
- ハッシュ検証用の**ext-ctype**（ほとんどのPHPビルドで有効ですが、`composer.json`では宣言されていません）

コアとなるリポジトリ操作に`git`バイナリ、FFI、外部ヘルパーは必要ありません。オプション機能には追加の実行時要件があります。フックの実行には`proc_open()`を使用し、SSHトランスポートは`ext-ssh2`が読み込まれている場合はそれを使い、そうでない場合は`proc_open()`を通じてシステムの`ssh`バイナリを起動します。

## 既存のリポジトリを開く

```php
use Pitmaster\Pitmaster;

$repo = Pitmaster::open('/path/to/project');
```

指定したパスにあるリポジトリを開きます。Pitmasterは`.git`ディレクトリを特定し（リンクされたワークツリーの場合は`.git`ファイルを解決）、オブジェクトデータベース、参照データベース、設定を初期化します。

`open()`、`init()`、`clone()`は、最後の引数としてオプション配列を受け取ります：

```php
// Do not run .git/hooks scripts for this handle
$repo = Pitmaster::open('/path/to/project', ['hooks' => false]);

// Do not start any process: no hooks, no fsmonitor hook, no clone/fetch/push, no SSH
$repo = Pitmaster::open('/path/to/project', Pitmaster::processFreeOptions());
```

フックは既定で実行されます。`Pitmaster::processFreeOptions()`は`['processes' => false, 'hooks' => false]`を返します。このハンドルを使ったローカルの読み書きは引き続き可能です。

## パスがリポジトリかどうかを確認する

```php
if (Pitmaster::isRepository('/path/to/project')) {
    $repo = Pitmaster::open('/path/to/project');
}
```

## 新しいリポジトリを初期化する

```php
$repo = Pitmaster::init('/path/to/new-project');
```

オブジェクト、参照、HEAD（`refs/heads/main`を指す）、既定の設定を含む`.git`ディレクトリ構造を作成します。

SHA-256リポジトリを作成するには、2番目の引数としてオブジェクト形式を渡します：

```php
$repo = Pitmaster::init('/path/to/new-project', 'sha256');
```

このリポジトリのオブジェクトIDは64文字の16進数で、設定には`extensions.objectformat = sha256`が記録されます。後でリポジトリを開くと、この設定項目から形式が取得されます。

## HEADのコミットを読む

```php
$head = $repo->head();

echo "Commit: {$head->id->hex}\n";
echo "Author: {$head->author}\n";
echo "Message: {$head->message}\n";
```

`head()`メソッドはHEADを解決し（シンボリック参照をたどり）、`Commit`オブジェクトを返します。

## ブランチとタグを一覧表示する

```php
// All branch names
$branches = $repo->branches();
// ['main', 'feature/login', 'bugfix/typo']

// Current branch name (null if detached)
$current = $repo->branch();
// 'main'

// All tag names
$tags = $repo->tags();
// ['v1.0.0', 'v1.1.0']
```

## コミット履歴をたどる

```php
// Last 20 commits from HEAD
$commits = $repo->log(20);

foreach ($commits as $commit) {
    echo substr($commit->id->hex, 0, 7) . " {$commit->message}\n";
}
```

特定のコミットから開始することもできます：

```php
$from = $repo->resolve('feature/login');
$commits = $repo->log(10, $from);
```

## 作業ツリーの状態を確認する

```php
use Pitmaster\Status\FileStatus;

$entries = $repo->status();

foreach ($entries as $entry) {
    if ($entry->index === FileStatus::Untracked) {
        echo "?? {$entry->path}\n";
    } elseif ($entry->index === FileStatus::Modified) {
        echo "M  {$entry->path}\n";
    } elseif ($entry->worktree === FileStatus::Modified) {
        echo " M {$entry->path}\n";
    }
}
```

## ファイルをステージしてコミットする

```php
// Stage specific files
$repo->add('src/Feature.php', 'tests/FeatureTest.php');

// Create a commit
$commitId = $repo->commit('Add new feature with tests');

echo "Created commit: {$commitId->hex}\n";
```

作成者名とメールアドレスは次の順で解決されます：`PITMASTER_AUTHOR_NAME`／`PITMASTER_AUTHOR_EMAIL`環境変数、`GIT_AUTHOR_NAME`／`GIT_AUTHOR_EMAIL`環境変数、`PITMASTER_AUTHOR_NAME`／`PITMASTER_AUTHOR_EMAIL`定数、リポジトリ独自の`.git/config`（`user.name`と`user.email`）、最後に`Pitmaster <pitmaster@localhost>`です。リポジトリの設定ファイルとそこから読み込まれるファイルだけが対象で、`~/.gitconfig`は読み込まれません。コミッターも同じ方法で`*_COMMITTER_*`の名前から解決され、作成者定数にフォールバックします。

## 差分を計算する

```php
// Unstaged changes (worktree vs index)
$diffs = $repo->diff();

foreach ($diffs as $diff) {
    echo $diff->format(); // Unified diff output
}

// Staged changes (index vs HEAD)
$staged = $repo->diffStaged();
```

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

```php
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/path/to/destination');
```

参照を検出し、パックファイルを取得して、リモート追跡ブランチを設定し、既定のブランチをチェックアウトします。HTTP(S)のURLではsmart HTTPを使い、失敗した場合はdumb HTTPにフォールバックします。SSHのURLではSSHトランスポートを使います。浅いクローンを作成するには、3番目の引数として深さを渡します：`Pitmaster::clone($url, $path, 1)`。

## ハッシュから任意のオブジェクトを読む

```php
$object = $repo->readObject($fullHash); // full 40-character (or 64 for SHA-256) hex hash

if ($object instanceof \Pitmaster\Object\Blob) {
    echo $object->content;
} elseif ($object instanceof \Pitmaster\Object\Commit) {
    echo $object->message;
}
```

## 設定

Pitmasterは、作成者情報とリモートURLにリポジトリの`.git/config`を使用します。Pitmasterの実行前に定義したPHP定数で、グローバルな既定値を設定することもできます：

```php
define('PITMASTER_AUTHOR_NAME', 'Your Name');
define('PITMASTER_AUTHOR_EMAIL', 'you@example.com');
define('PITMASTER_HTTP_TIMEOUT', 60);        // Seconds
define('PITMASTER_MAX_DELTA_CHAIN', 50);     // Max delta chain depth
define('PITMASTER_OBJECT_CACHE_BYTES', '64M');
```

| 定数 | 既定値 | 効果 |
|----------|---------|--------|
| `PITMASTER_AUTHOR_NAME`、`PITMASTER_AUTHOR_EMAIL` | なし | 作成者の識別情報（上記の順序を参照） |
| `PITMASTER_COMMITTER_NAME`、`PITMASTER_COMMITTER_EMAIL` | 作成者の値 | コミッターの識別情報 |
| `PITMASTER_HTTP_TIMEOUT` | `30` | Smart HTTPのタイムアウト（秒、整数） |
| `PITMASTER_MAX_DELTA_CHAIN` | `50` | パック読み込み時のデルタチェーンの最大深度（整数） |
| `PITMASTER_OBJECT_CACHE_ENTRIES` | `1024` | メモリ内オブジェクトキャッシュに保持するオブジェクト数 |
| `PITMASTER_OBJECT_CACHE_BYTES` | `16M` | オブジェクトキャッシュのバイト数上限 |
| `PITMASTER_PACK_RESOLVED_CACHE_ENTRIES` | `4096` | パックごとにキャッシュする解決済みデルタオブジェクト数 |
| `PITMASTER_PACK_RESOLVED_CACHE_BYTES` | `32M` | パックキャッシュのバイト数上限 |
| `PITMASTER_MAX_PACK_MEMORY` | なし | パックキャッシュのバイト数上限を表す旧名称。`PITMASTER_PACK_RESOLVED_CACHE_BYTES`が未定義の場合のみ使用 |

バイト数は、整数または`k`、`m`、`g`のいずれかのサフィックス付き文字列（`'256M'`）で指定できます。無効な値の場合は既定値が使用されます。

環境変数は、ID定数である`PITMASTER_AUTHOR_NAME`、`PITMASTER_AUTHOR_EMAIL`、`PITMASTER_AUTHOR_DATE`と、それぞれに対応する`PITMASTER_COMMITTER_*`の値、さらにgit固有の`GIT_AUTHOR_*`および`GIT_COMMITTER_*`変数を上書きします。SSHトランスポートは`PITMASTER_SSH_*`変数を読み込みます。詳細は[プロトコル](https://pitmaster.inline0.dev/ja/docs/network/protocols)を参照してください。

ハッシュアルゴリズムを指定する定数はありません。オブジェクト形式はリポジトリの作成時に選択され（CLIで`Pitmaster::init($path, 'sha256')`または`init --object-format=sha256`を指定）、その後はリポジトリの設定から読み込まれます。
