
# Начало работы

## Установка

Установите Pitmaster с помощью Composer:

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

## Требования

- **PHP 8.2+** с классами readonly, перечислениями и продвижением аргументов конструктора
- **ext-zlib** для сжатия и распаковки объектов (встроен в большинство установок)
- **ext-json** для файлов состояния операций и данных Git LFS API
- **ext-mbstring**, указанный в `composer.json`, поэтому Composer требует его при установке
- **ext-ctype** для проверки хешей (включён в большинство сборок PHP, но не указан в `composer.json`)

Для основных операций с репозиторием не требуются двоичный файл `git`, FFI или внешние вспомогательные средства. У дополнительных функций есть дополнительные требования к среде выполнения: для выполнения хуков используется `proc_open()`, а транспорт SSH использует `ext-ssh2`, если он загружен, и в противном случае запускает системный двоичный файл `ssh` через `proc_open()`.

## Открытие существующего репозитория

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

Создаёт структуру каталогов `.git` с объектами, ссылками, HEAD (указывающим на `refs/heads/main`) и конфигурацией по умолчанию.

Чтобы создать репозиторий SHA-256, передайте формат объектов вторым аргументом:

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

Идентификаторы объектов в таком репозитории состоят из 64 шестнадцатеричных символов, а в конфигурации записан `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');
```

Обнаруживает ссылки, загружает pack-файл, настраивает ветки отслеживания удалённого репозитория и переключается на ветку по умолчанию. URL HTTP(S) используют умный протокол HTTP с переходом на простой HTTP при сбое; URL SSH используют транспорт 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 учитывает `.git/config` репозитория при получении сведений об авторе и URL удалённых репозиториев. Также можно задать глобальные значения по умолчанию с помощью констант PHP, объявленных до запуска Pitmaster:

```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` | Тайм-аут умного протокола HTTP в секундах (целое число) |
| `PITMASTER_MAX_DELTA_CHAIN` | `50` | Максимальная глубина цепочки delta при чтении pack-файлов (целое число) |
| `PITMASTER_OBJECT_CACHE_ENTRIES` | `1024` | Объекты, хранящиеся в кэше объектов в памяти |
| `PITMASTER_OBJECT_CACHE_BYTES` | `16M` | Лимит размера кэша объектов в байтах |
| `PITMASTER_PACK_RESOLVED_CACHE_ENTRIES` | `4096` | Разрешённые объекты delta, кэшируемые для каждого pack-файла |
| `PITMASTER_PACK_RESOLVED_CACHE_BYTES` | `32M` | Лимит размера кэша этого pack-файла в байтах |
| `PITMASTER_MAX_PACK_MEMORY` | нет | Прежнее имя лимита размера кэша pack-файлов, используемое, только если `PITMASTER_PACK_RESOLVED_CACHE_BYTES` не определена |

Для значений в байтах можно указать целое число или строку с суффиксом `k`, `m` или `g` (`'256M'`). Недопустимые значения заменяются значением по умолчанию.

Переменные среды имеют приоритет над константами идентификации: `PITMASTER_AUTHOR_NAME`, `PITMASTER_AUTHOR_EMAIL`, `PITMASTER_AUTHOR_DATE`, соответствующие переменные `PITMASTER_COMMITTER_*`, а также собственные переменные `GIT_AUTHOR_*` и `GIT_COMMITTER_*` для git. Транспорт SSH считывает переменные `PITMASTER_SSH_*`, описанные в разделе [Протоколы](https://pitmaster.inline0.dev/ru/docs/network/protocols).

Для алгоритма хеширования нет константы. Формат объектов выбирается при создании репозитория (`Pitmaster::init($path, 'sha256')` или `init --object-format=sha256` в CLI), а затем считывается из конфигурации репозитория.
