
# Hoidlatesse kirjutamine

Pitmaster kirjutab git-hoidlaid, kasutades samu binaarvorminguid nagu kanooniline `git` binaar. Objektid kirjutatakse pakkimata objektide hoidlasse (zlib-pakitult), indeks kirjutatakse vormingus v2 (või v3, kui kirjed vajavad laiendatud lippe; olemasolev indeks säilitab oma versiooni) ning viited kirjutatakse eraldi failidena. Kirjutatud andmeid saab kontrollida käsuga `git fsck --strict`.

## Hoidla initsialiseerimine

```php
use Pitmaster\Pitmaster;

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

Sellega luuakse:
- `.git/objects/` (tühi objektide hoidla)
- `.git/refs/heads/` ja `.git/refs/tags/` (tühjad viidete kataloogid)
- `.git/HEAD`, mis sisaldab `ref: refs/heads/main`
- `.git/hooks/`, `.git/info/exclude` ja `.git/description`
- `.git/config` vaikeseadetega

Edasta `'sha256'` teise argumendina, et luua SHA-256 hoidla: `Pitmaster::init($path, 'sha256')`.

Vaikekonfiguratsioon ei määra võtit `core.logallrefupdates`, seega ei salvesta Pitmaster enda loodud hoidlas reflogi kirjeid enne, kui määrad sellele võtmele väärtuse `true` ([#8](https://github.com/inline0/pitmaster/issues/8)). `git init` loodud hoidlates on see juba määratud.

## Failide lisamine ettevalmistusalasse

### add

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

Iga argument on tööpuu juurkataloogi suhtes määratud failitee. Katalooge ja glob-mustreid ei laiendata ning puuduva faili korral visatakse `RuntimeException`. Iga faili puhul Pitmaster:
1. Loeb faili sisu tööpuust
2. Loob objekti `Blob` ja arvutab selle räsi
3. Kirjutab blobi asukohta `.git/objects/` (zlib-pakitult)
4. Uuendab selle tee indeksikirje uue räsi ja faili metaandmetega

### remove

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

Eemaldab jälgitavad teed indeksist ja tööpuust. Ainult indeksist eemaldamiseks kasuta `--cached` või jälgitavate kataloogide jaoks `-r` / `--recursive`.

### mv

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

Nimetab faili tööpuus ümber, eemaldab vana indeksikirje ja lisab uue.

## Commit'ide loomine

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

Commit'i loomise protsess:

1. **Puu koostamine indeksist**: indeksi kirjete lame loend korraldatakse puuhierarhiaks (kataloogidest saavad puuobjektid, failidest blobi viited). Iga puu kirjutatakse objektide hoidlasse.
2. **Vanema määramine**: praegusest HEAD-commit'ist saab vanem. Juur-commit'idel (hoidla esimene commit) vanemaid pole.
3. **Autori määramine**: väärtus saadakse keskkonnamuutujatest `PITMASTER_AUTHOR_*` ja `GIT_AUTHOR_*`, seejärel konstantidest `PITMASTER_AUTHOR_NAME`/`PITMASTER_AUTHOR_EMAIL`, siis `.git/config` (`user.name`/`user.email`) ning seejärel `Pitmaster <pitmaster@localhost>`. Commit'i tegija määratakse samal viisil.
4. **Commit-objekti kirjutamine**: commit'i sisu (`tree`, `parent`, `author`, `committer`, sõnum) järjestatakse, räsitakse ja kirjutatakse.
5. **HEAD-i uuendamine**: haru viide, millele HEAD osutab, uuendatakse uue commit'i räsiga.

Hook'id käivitatakse nende sammude ümber (`pre-commit`, `prepare-commit-msg`, `commit-msg`, `post-commit`), välja arvatud juhul, kui käitleja avati valikuga `['hooks' => false]`. `commit()` viskab vea, kui sõnum puudub, puu pole HEAD-ist muutunud või indeksis on lahendamata teid.

### Kohandatud autor

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

## Kontrollimine käsuga git fsck

Pitmaster integratsioonitestid kontrollivad kirjutatud objekte käsu `git fsck --strict` abil ning saad sama ka käsitsi üle kontrollida:

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

Kui Pitmaster kirjutab vigase objekti, teatab `git fsck` veast kohe.

## Harude haldamine

### Haru loomine

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

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

Loob viitefaili asukohta `.git/refs/heads/<name>`, mis sisaldab siht-commit'i räsi.

### Haru kustutamine

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

### Harude vahetamine

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

Uuendab HEAD-i harule osutavaks sümboolseks viiteks, lähtestab indeksi haru tipu puule vastavaks ja uuendab tööpuud.

Kohalikud muudatused radadel, mis erinevad kahe puu vahel, peatavad väljavõtte veaga `RuntimeException`. Kõikides teistes jälgitavates failides asendatakse commit'imata muudatused haru sisuga seal, kus git jätaks need alles ([#2](https://github.com/inline0/pitmaster/issues/2)). Enne haru vahetamist commit'i või pane need kõrvale.

### Kontrollimine, kas haru on ühendatud

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

## Siltide haldamine

### Lihtsilt

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

Lihtsilt on lihtsalt otse commit'ile osutav viide.

### Annoteeritud silt

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

Annoteeritud silt loob sildiobjekti (koos sildistaja, sõnumi ja sihtmärgiga) ning sellele osutava viite. Sildistajaks on praeguse commit'i tegija identiteet, mis lahendatakse samamoodi nagu commit'i autor.

### Kohandatud sildistaja

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

## Viidete otse uuendamine

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

## Objektide otse kirjutamine

Täiustatud kasutusjuhtudel saad objekte kirjutada ilma kõrgtaseme API-ta.

### Blobi kirjutamine

```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 hoidlas edasta algoritm: `Blob::fromContent('Hello, world!', 'sha256')`.

### Puu kirjutamine

```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()` kirjutab kirjed antud järjekorras ja režiimistringid etteantud kujul. Anna need git-i puujärjekorras (nime järgi, kus katalooge võrreldakse nii, nagu lõppeks nende nimi sümboliga `/`) ning kirjuta kataloogirežiimid kujul `40000`: git salvestab puurežiimid ilma algusnullita ja `git fsck --strict` lükkab `040000` tagasi.

### Commit'i kirjutamine

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

## Lähtestamine

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

## Taastamine

```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 ja ennistamine

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

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

Mõlemad aktsepteerivad suvalist versiooni, mille `resolve()` aktsepteerib. Täispikad räsid sobivad, lühendatud räsid mitte.
