
# Zápis do repozitárov

Pitmaster zapisuje repozitáre git pomocou rovnakých binárnych formátov ako kanonický binárny súbor `git`. Objekty sa zapisujú do úložiska voľných objektov (komprimované pomocou zlib), index sa zapisuje vo formáte v2 (alebo v3, ak položky potrebujú rozšírené príznaky; existujúci index si zachová svoju verziu) a odkazy sa zapisujú ako voľné súbory. Zapísané údaje možno overiť pomocou `git fsck --strict`.

## Inicializácia repozitára

```php
use Pitmaster\Pitmaster;

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

Vytvorí sa:
- `.git/objects/` (prázdne úložisko objektov)
- `.git/refs/heads/` a `.git/refs/tags/` (prázdne adresáre odkazov)
- `.git/HEAD` obsahujúci `ref: refs/heads/main`
- `.git/hooks/`, `.git/info/exclude` a `.git/description`
- `.git/config` s predvolenými nastaveniami

Ak chcete vytvoriť repozitár SHA-256, odovzdajte `'sha256'` ako druhý argument: `Pitmaster::init($path, 'sha256')`.

Predvolená konfigurácia nenastavuje `core.logallrefupdates`, takže Pitmaster nezaznamenáva žiadne položky reflogu v repozitári, ktorý vytvorí, kým tento kľúč nenastavíte na `true` ([#8](https://github.com/inline0/pitmaster/issues/8)). Repozitáre vytvorené pomocou `git init` ho už majú nastavený.

## Zaraďovanie súborov do indexu

### add

```php
$repo->add('src/Feature.php');
$repo->add('src/Feature.php', 'tests/FeatureTest.php', 'README.md');
```

Každý argument je cesta k súboru relatívna ku koreňovému adresáru pracovného stromu. Adresáre a glob vzory sa nerozbaľujú a pri chýbajúcom súbore sa vyvolá `RuntimeException`. Pre každý súbor Pitmaster:
1. Načíta obsah súboru z pracovného stromu
2. Vytvorí objekt `Blob` a vypočíta jeho hash
3. Zapíše blob do `.git/objects/` (komprimovaný pomocou zlib)
4. Aktualizuje položku indexu pre danú cestu novým hashom a metadátami súboru

### remove

```php
$repo->remove('old-file.txt');
$repo->remove('-r', 'src');
$repo->remove('--cached', 'old-file.txt');
```

Odstráni sledované cesty z indexu a pracovného stromu. Na odstránenie iba z indexu použite `--cached` alebo pri sledovaných adresároch použite `-r` / `--recursive`.

### mv

```php
$repo->mv('old-name.php', 'new-name.php');
```

Premenuje súbor v pracovnom strome, odstráni starú položku indexu a pridá novú.

## Vytváranie commitov

```php
$commitId = $repo->commit('Fix null pointer bug');
echo $commitId->hex;
```

Postup vytvorenia commitu:

1. **Zostavenie stromu z indexu**: plochý zoznam položiek indexu sa usporiada do hierarchie stromov (z adresárov sa stanú objekty stromu, súbory sú odkazy na bloby). Každý strom sa zapíše do úložiska objektov.
2. **Určenie rodiča**: aktuálny commit HEAD sa stane rodičom. Koreňové commity (prvý commit v repozitári) nemajú rodičov.
3. **Určenie autora**: údaje sa prevezmú z premenných prostredia `PITMASTER_AUTHOR_*` a `GIT_AUTHOR_*`, potom z konštánt `PITMASTER_AUTHOR_NAME`/`PITMASTER_AUTHOR_EMAIL`, ďalej z `.git/config` (`user.name`/`user.email`) a napokon z `Pitmaster <pitmaster@localhost>`. Autor commitu sa určí rovnakým spôsobom.
4. **Zápis objektu commitu**: obsah commitu (`tree`, `parent`, `author`, `committer`, správa) sa serializuje, zahashuje a zapíše.
5. **Aktualizácia HEAD**: odkaz vetvy, na ktorý ukazuje HEAD, sa aktualizuje novým hashom commitu.

Hooky sa spúšťajú pred týmito krokmi a po nich (`pre-commit`, `prepare-commit-msg`, `commit-msg`, `post-commit`), pokiaľ nebol handle otvorený pomocou `['hooks' => false]`. `commit()` vyvolá chybu, ak chýba správa, strom sa nezmenil oproti HEAD alebo index obsahuje nezlúčené cesty.

### Vlastný autor

```php
$author = 'Jane Smith <jane@example.com> 1700000000 +0000';
$commitId = $repo->commit('Add feature', $author);
```

## Overenie pomocou fsck nástroja git

Integračné testy nástroja Pitmaster overujú zapísané objekty pomocou `git fsck --strict` a rovnaké overenie môžete vykonať aj ručne:

```bash
cd /path/to/repo
git fsck --strict
```

Ak Pitmaster zapíše neplatný objekt, `git fsck` chybu okamžite nahlási.

## Správa vetiev

### Vytvorenie vetvy

```php
// Branch from HEAD
$repo->createBranch('feature/new-thing');

// Branch from a specific commit
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));
```

Vytvorí súbor odkazu v `.git/refs/heads/<name>` obsahujúci hash cieľového commitu.

### Odstránenie vetvy

```php
$repo->deleteBranch('feature/old');
```

### Prepnutie vetiev

```php
$repo->checkout('feature/login');
```

Aktualizuje HEAD na symbolický odkaz ukazujúci na vetvu, resetuje index tak, aby zodpovedal špičke vetvy, a aktualizuje pracovný strom.

Lokálne zmeny na cestách, ktoré sa medzi týmito dvoma stromami líšia, zastavia checkout s chybou `RuntimeException`. Nepotvrdené zmeny vo všetkých ostatných sledovaných súboroch sa nahradia obsahom vetvy; git by ich zachoval ([#2](https://github.com/inline0/pitmaster/issues/2)). Pred prepnutím ich commitnite alebo odložte.

### Kontrola, či je zlúčená

```php
if ($repo->isBranchMerged('feature/done')) {
    $repo->deleteBranch('feature/done');
}
```

## Správa tagov

### Ľahký tag

```php
$repo->createLightweightTag('v1.0.0');                          // At HEAD
$repo->createLightweightTag('v0.9.0', $repo->resolve('HEAD~5'));
```

Ľahký tag je jednoducho odkaz smerujúci priamo na commit.

### Anotovaný tag

```php
$tagId = $repo->createTag('v2.0.0', 'Release version 2.0.0');
```

Anotovaný tag vytvorí objekt tagu (s autorom tagu, správou a cieľom) a odkaz, ktorý naň ukazuje. Autorom tagu je aktuálna identita autora commitu, určená rovnakým spôsobom ako autor commitu.

### Vlastný autor tagu

```php
$tagId = $repo->createTag(
    'v2.0.0',
    'Release version 2.0.0',
    $repo->resolve('HEAD'),
    'Jane Smith <jane@example.com> 1700000000 +0000',
);
```

## Priama aktualizácia odkazov

```php
$repo->updateRef('refs/heads/main', $commitId);
$repo->updateRef('refs/tags/latest', $commitId);
```

## Priamy zápis objektov

V pokročilých prípadoch použitia môžete zapisovať objekty bez použitia vysokoúrovňového rozhrania API.

### Zápis blobu

```php
use Pitmaster\Object\Blob;

$blob = Blob::fromContent('Hello, world!');
$id = $repo->writeObject($blob);
echo $id->hex;  // SHA-1 of "blob 13\0Hello, world!"
```

V repozitári SHA-256 odovzdajte algoritmus: `Blob::fromContent('Hello, world!', 'sha256')`.

### Zápis stromu

```php
use Pitmaster\Object\Tree;
use Pitmaster\Object\TreeEntry;
use Pitmaster\Object\ObjectId;

$entries = [
    new TreeEntry('100644', 'README.md', $blobId),
    new TreeEntry('40000', 'src', $subtreeId),
];

$tree = Tree::fromEntries($entries);
$id = $repo->writeObject($tree);
```

`Tree::fromEntries()` zapisuje položky v zadanom poradí a reťazce režimov tak, ako boli zadané. Odovzdajte ich v poradí stromu nástroja git (podľa názvu, pričom názvy adresárov sa porovnávajú, akoby sa končili znakom `/`) a režimy adresárov zapisujte ako `40000`: git ukladá režimy stromov bez úvodnej nuly a `git fsck --strict` odmieta `040000`.

### Zápis commitu

```php
use Pitmaster\Object\Commit;
use Pitmaster\Object\ObjectId;
use Pitmaster\Object\ObjectType;

$content = Commit::buildContent(
    tree: $treeId,
    parents: [$parentId],
    author: 'Name <email> 1700000000 +0000',
    committer: 'Name <email> 1700000000 +0000',
    message: "Commit message\n",
);

$commitId = ObjectId::compute(ObjectType::Commit, $content);
$commit = Commit::parse($content, $commitId);
$repo->writeObject($commit);
```

## Reset

```php
// Soft: move HEAD only
$repo->reset('HEAD~1', 'soft');

// Mixed: move HEAD + reset index (default)
$repo->reset('HEAD~1');

// Hard: move HEAD + reset index + reset working tree
$repo->reset('HEAD~3', 'hard');
```

## Obnovenie

```php
// Restore a file from the index into the worktree
$repo->restore('src/File.php');

// Restore the index version from HEAD (the worktree is left alone)
$repo->restore('src/File.php', staged: true);

// Restore from a specific commit
$repo->restore('src/File.php', 'HEAD~1');

// Restore both index and worktree from a specific commit
$repo->restore('src/File.php', 'HEAD~1', staged: true, worktree: true);
```

## Cherry-pick a vrátenie zmien

```php
// Apply a commit on the current branch
$newId = $repo->cherryPick('feature~1');

// Undo a commit
$revertId = $repo->revert('HEAD~2');
```

Oba príkazy prijímajú ľubovoľnú revíziu, ktorú prijíma `resolve()`. Celé hashe fungujú; skrátené nie.
