
# Първи стъпки

## Инсталиране

Инсталирайте Pitmaster чрез Composer:

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

## Изисквания

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

Основните операции с хранилището не изискват двоичния файл `git`, FFI или външни помощни програми. Незадължителните функции имат допълнителни изисквания по време на изпълнение: изпълнението на hook използва `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());
```

По подразбиране hook-овете се изпълняват. `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');
```

ID-тата на обектите в това хранилище са с дължина 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) използват smart транспорта HTTP и преминават към dumb 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` | Време на изчакване за smart 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 `GIT_AUTHOR_*` и `GIT_COMMITTER_*`. Транспортът SSH чете променливите `PITMASTER_SSH_*`, описани в [Протоколи](https://pitmaster.inline0.dev/bg/docs/network/protocols).

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