
# 시작하기

## 설치

Pitmaster을 Composer을 통해 설치하세요.

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

## 요구 사항

- **PHP 8.2+**(읽기 전용 클래스, 열거형, 생성자 프로퍼티 승격 지원)
- **ext-zlib** 객체 압축 및 압축 해제용(대부분의 설치에 기본 포함)
- **ext-json** 작업 상태 파일과 Git LFS API 페이로드용
- **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` 디렉터리를 찾거나(연결된 worktree의 경우 `.git` 파일을 확인해 해결), 객체 데이터베이스, ref 데이터베이스, 설정을 초기화합니다.

`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');
```

객체, refs, HEAD(`refs/heads/main`을 가리킴), 기본 설정이 포함된 `.git` 디렉터리 구조를 만듭니다.

SHA-256 저장소를 만들려면 객체 형식을 두 번째 인수로 전달합니다.

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

이 저장소의 객체 ID는 64자 16진수이며, 설정에는 `extensions.objectformat = sha256`이 기록됩니다. 나중에 연 저장소는 해당 설정 항목에서 형식을 가져옵니다.

## HEAD commit 읽기

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

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

`head()` 메서드는 HEAD를 해석하고(심볼릭 refs를 따라감) `Commit` 객체를 반환합니다.

## 브랜치와 tag 목록 보기

```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']
```

## Commit 기록 순회

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

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

특정 commit에서 시작할 수도 있습니다.

```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";
    }
}
```

## 파일 스테이징 및 commit

```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_*` 이름을 확인하고, 없으면 작성자 상수로 대체합니다.

## Diff 계산

```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');
```

이 작업은 ref를 검색하고, pack 파일을 가져오고, 원격 추적 브랜치를 설정한 다음 기본 브랜치를 체크아웃합니다. HTTP(S) URL은 smart HTTP을 사용하고 실패하면 dumb HTTP로 대체합니다. SSH URL은 SSH 전송 방식을 사용합니다. 얕은 클론을 만들려면 세 번째 인수로 깊이를 전달하세요: `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` | pack을 읽을 때 최대 델타 체인 깊이(정수) |
| `PITMASTER_OBJECT_CACHE_ENTRIES` | `1024` | 메모리 내 객체 캐시에 보관되는 객체 수 |
| `PITMASTER_OBJECT_CACHE_BYTES` | `16M` | 객체 캐시의 바이트 한도 |
| `PITMASTER_PACK_RESOLVED_CACHE_ENTRIES` | `4096` | pack별로 캐시되는 해석된 델타 객체 수 |
| `PITMASTER_PACK_RESOLVED_CACHE_BYTES` | `32M` | 해당 pack 캐시의 바이트 한도 |
| `PITMASTER_MAX_PACK_MEMORY` | 없음 | pack 캐시 바이트 한도의 이전 이름. `PITMASTER_PACK_RESOLVED_CACHE_BYTES`이 정의되지 않은 경우에만 사용됩니다 |

바이트 값은 정수 또는 `'256M'`(`k`, `m` 또는 `g` 접미사 포함) 문자열로 지정할 수 있습니다. 잘못된 값은 기본값으로 대체됩니다.

환경 변수는 신원 상수를 재정의합니다: `PITMASTER_AUTHOR_NAME`, `PITMASTER_AUTHOR_EMAIL`, `PITMASTER_AUTHOR_DATE`, 이에 대응하는 `PITMASTER_COMMITTER_*` 항목, 그리고 git 자체의 `GIT_AUTHOR_*` 및 `GIT_COMMITTER_*` 변수입니다. SSH 전송 방식은 `PITMASTER_SSH_*` 변수를 읽으며, 자세한 내용은 [프로토콜](https://pitmaster.inline0.dev/ko/docs/network/protocols)에서 확인할 수 있습니다.

해시 알고리즘을 설정하는 상수는 없습니다. 객체 형식은 저장소를 만들 때(CLI에서 `Pitmaster::init($path, 'sha256')` 또는 `init --object-format=sha256`) 선택되고, 이후에는 저장소 설정에서 읽어 옵니다.
