
# Rašymas į saugyklas

Pitmaster įrašo git saugyklas naudodamas tuos pačius dvejetainius formatus kaip kanoninis `git` dvejetainis failas. Objektai įrašomi į atskirų objektų saugyklą (zlib suspausti), indeksas įrašomas v2 formatu (arba v3, kai įrašams reikia išplėstinių vėliavų; esamas indeksas išlaiko savo versiją), o nuorodos įrašomos kaip atskiri failai. Įrašytus duomenis galima patikrinti naudojant `git fsck --strict`.

## Saugyklos inicijavimas

```php
use Pitmaster\Pitmaster;

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

Sukuriama:
- `.git/objects/` (tuščia objektų saugykla)
- `.git/refs/heads/` ir `.git/refs/tags/` (tušti nuorodų katalogai)
- `.git/HEAD`, kuriame yra `ref: refs/heads/main`
- `.git/hooks/`, `.git/info/exclude` ir `.git/description`
- `.git/config` su numatytosiomis nuostatomis

Pateikite `'sha256'` kaip antrą argumentą, kad sukurtumėte SHA-256 saugyklą: `Pitmaster::init($path, 'sha256')`.

Numatytojoje konfigūracijoje `core.logallrefupdates` nenustatytas, todėl jos sukurtoje saugykloje Pitmaster nefiksuoja reflog įrašų, kol nenustatysite šio rakto į `true` ([#8](https://github.com/inline0/pitmaster/issues/8)). `git init` sukurtose saugyklose jis jau nustatytas.

## Failų paruošimas

### add

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

Kiekvienas argumentas yra failo kelias, santykinis darbiniam medžiui. Katalogai ir glob šablonai neišplečiami, o neradus failo išmetama `RuntimeException` klaida. Kiekvienam failui Pitmaster:
1. Nuskaito failo turinį iš darbinio medžio
2. Sukuria `Blob` objektą ir apskaičiuoja jo maišą
3. Įrašo blob į `.git/objects/` (zlib suspaustu formatu)
4. Atnaujina to kelio indekso įrašą nauja maiša ir failo metaduomenimis

### remove

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

Pašalina sekamus kelius iš indekso ir darbinio medžio. Naudokite `--cached`, jei norite pašalinti tik iš indekso, arba `-r` / `--recursive`, jei norite pašalinti sekamus katalogus.

### mv

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

Pervadina failą darbiniame medyje, pašalina seną indekso įrašą ir prideda naują.

## Įrašų kūrimas

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

Įrašo kūrimo eiga:

1. **Medžio sudarymas iš indekso**: plokščias indekso įrašų sąrašas sutvarkomas į medžio hierarchiją (katalogai tampa medžio objektais, failai – blob nuorodomis). Kiekvienas medis įrašomas į objektų saugyklą.
2. **Tėvinio įrašo nustatymas**: dabartinis HEAD įrašas tampa tėviniu. Šakniniai įrašai (pirmasis įrašas saugykloje) tėvinių įrašų neturi.
3. **Autoriaus nustatymas**: imamas iš `PITMASTER_AUTHOR_*` ir `GIT_AUTHOR_*` aplinkos kintamųjų, tada iš `PITMASTER_AUTHOR_NAME`/`PITMASTER_AUTHOR_EMAIL` konstantų, tada iš `.git/config` (`user.name`/`user.email`), galiausiai iš `Pitmaster <pitmaster@localhost>`. Įrašytojas nustatomas tokiu pačiu būdu.
4. **Įrašo objekto įrašymas**: įrašo turinys (`tree`, `parent`, `author`, `committer`, pranešimas) serializuojamas, apskaičiuojama jo maiša ir įrašomas.
5. **HEAD atnaujinimas**: šakos nuoroda, į kurią rodo HEAD, atnaujinama nauja įrašo maiša.

Aplink šiuos veiksmus vykdomi kabliukai (`pre-commit`, `prepare-commit-msg`, `commit-msg`, `post-commit`), nebent rankena atverta su `['hooks' => false]`. `commit()` išmeta klaidą, jei trūksta pranešimo, medis nepasikeitė nuo HEAD arba indekse yra nesujungtų kelių.

### Pasirinktinis autorius

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

## Tikrinimas naudojant git fsck

Pitmaster integravimo testai tikrina įrašytus objektus pagal `git fsck --strict`; tą patį galite patikrinti ir rankiniu būdu:

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

Jei Pitmaster įrašo netinkamą objektą, `git fsck` iškart praneš apie klaidą.

## Šakų tvarkymas

### Šakos sukūrimas

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

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

Sukuria nuorodos failą adresu `.git/refs/heads/<name>`, kuriame įrašoma tikslinio įrašo maiša.

### Šakos ištrynimas

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

### Šakų perjungimas

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

Atnaujina HEAD į simbolinę nuorodą į šaką, nustato indeksą pagal šakos viršūnės medį ir atnaujina darbinį medį.

Vietiniai pakeitimai keliuose, kurie skiriasi abiejuose medžiuose, sustabdo išėmimą su `RuntimeException` klaida. Neužfiksuoti kitų sekamų failų pakeitimai pakeičiami šakos turiniu, jei git juos išsaugotų (žr. [#2](https://github.com/inline0/pitmaster/issues/2)). Prieš perjungdami šaką, juos užfiksuokite arba paslėpkite.

### Patikrinimas, ar sujungta

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

## Žymų tvarkymas

### Lengvoji žyma

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

Lengvoji žyma yra tiesiog nuoroda, tiesiogiai rodanti į įrašą.

### Anotuota žyma

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

Anotuota žyma sukuria žymos objektą (su žymos autoriumi, pranešimu ir tikslu) bei į jį rodančią nuorodą. Žymos autorius yra dabartinė įrašytojo tapatybė, nustatoma taip pat kaip įrašo autorius.

### Pasirinktinis žymos autorius

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

## Tiesioginis nuorodų atnaujinimas

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

## Tiesioginis objektų įrašymas

Sudėtingesniais atvejais objektus galite įrašyti nenaudodami aukšto lygio API.

### Blob įrašymas

```php
use Pitmaster\Object\Blob;

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

SHA-256 saugykloje perduokite algoritmą: `Blob::fromContent('Hello, world!', 'sha256')`.

### Medžio įrašymas

```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()` įrašo įrašus pateikta tvarka ir režimų eilutes tokias, kokios pateiktos. Pateikite juos git medžio tvarka (pagal pavadinimą, katalogų pavadinimus lyginant taip, tarsi jų gale būtų `/`) ir katalogų režimus nurodykite kaip `40000`: git saugo medžių režimus be pradinio nulio, o `git fsck --strict` atmeta `040000`.

### Įrašo įrašymas

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

## Atstatymas

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

## Atkūrimas

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

## Pakeitimo pritaikymas ir atšaukimas

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

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

Abu priima bet kokią `resolve()` palaikomą versiją. Visos maišos tinka, sutrumpintos – ne.
