
# Rakstīšana repozitorijos

Pitmaster raksta git repozitorijus, izmantojot tos pašus bināros formātus kā kanoniskajā `git` binārajā failā. Objekti tiek ierakstīti nesaspiesto objektu krātuvē (saspiesti ar zlib), indekss tiek rakstīts v2 formātā (vai v3, ja ierakstiem nepieciešami paplašinātie karodziņi; esošais indekss saglabā savu versiju), bet atsauces tiek rakstītas kā nesaspiesti faili. Ierakstītos datus var pārbaudīt ar `git fsck --strict`.

## Repozitorija inicializēšana

```php
use Pitmaster\Pitmaster;

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

Tiek izveidoti:
- `.git/objects/` (tukša objektu krātuve)
- `.git/refs/heads/` un `.git/refs/tags/` (tukši atsauču direktoriji)
- `.git/HEAD` ar `ref: refs/heads/main`
- `.git/hooks/`, `.git/info/exclude` un `.git/description`
- `.git/config` ar noklusējuma iestatījumiem

Lai izveidotu SHA-256 repozitoriju, kā otro argumentu norādiet `'sha256'`: `Pitmaster::init($path, 'sha256')`.

Noklusējuma konfigurācijā `core.logallrefupdates` nav iestatīts, tāpēc Pitmaster neveido reflog ierakstus izveidotajā repozitorijā, kamēr šo atslēgu neiestata uz `true` ([#8](https://github.com/inline0/pitmaster/issues/8)). Repozitorijos, ko izveido `git init`, šī atslēga jau ir iestatīta.

## Failu pievienošana indeksam

### add

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

Katrs arguments ir faila ceļš attiecībā pret darba koka sakni. Direktoriji un glob izteiksmes netiek izvērstas, un, ja fails neeksistē, tiek izmests `RuntimeException`. Katram failam Pitmaster:
1. Nolasa faila saturu no darba koka
2. Izveido `Blob` objektu un aprēķina tā jaucējvērtību
3. Ieraksta blob objektu `.git/objects/` (saspiestu ar zlib)
4. Atjaunina indeksa ierakstu šim ceļam ar jauno jaucējvērtību un faila metadatiem

### remove

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

Noņem izsekotos ceļus no indeksa un darba koka. Lai noņemtu tikai no indeksa, izmantojiet `--cached`, bet izsekotiem direktorijiem — `-r` / `--recursive`.

### mv

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

Pārdēvē failu darba kokā, noņem veco indeksa ierakstu un pievieno jauno.

## Komitējumu izveide

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

Komitēšanas process:

1. **Koka izveide no indeksa**: plakanais indeksa ierakstu saraksts tiek sakārtots koka hierarhijā (direktoriji kļūst par koka objektiem, faili — par blob atsaucēm). Katrs koks tiek ierakstīts objektu krātuvē.
2. **Vecākkomitējuma noteikšana**: pašreizējais HEAD komitējums kļūst par vecākkomitējumu. Saknes komitējumiem (pirmajam komitējumam repozitorijā) vecākkomitējumu nav.
3. **Autora noteikšana**: autors tiek iegūts no vides mainīgajiem `PITMASTER_AUTHOR_*` un `GIT_AUTHOR_*`, pēc tam no konstantēm `PITMASTER_AUTHOR_NAME`/`PITMASTER_AUTHOR_EMAIL`, tad no `.git/config` (`user.name`/`user.email`) un visbeidzot no `Pitmaster <pitmaster@localhost>`. Komitētājs tiek noteikts tāpat.
4. **Komitējuma objekta ierakstīšana**: komitējuma saturs (`tree`, `parent`, `author`, `committer`, ziņojums) tiek serializēts, tam aprēķina jaucējvērtību un tas tiek ierakstīts.
5. **HEAD atjaunināšana**: zara atsauce, uz kuru norāda HEAD, tiek atjaunināta uz jaunā komitējuma jaucējvērtību.

Šo darbību laikā tiek izpildīti āķi (`pre-commit`, `prepare-commit-msg`, `commit-msg`, `post-commit`), ja vien deskriptors nav atvērts ar `['hooks' => false]`. `commit()` izmet kļūdu, ja trūkst ziņojuma, koks nav mainījies salīdzinājumā ar HEAD vai indeksam ir neapvienoti ceļi.

### Pielāgots autors

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

## Pārbaude ar git fsck

Pitmaster integrācijas testos pārbauda rakstītos objektus, salīdzinot tos ar `git fsck --strict`; to pašu varat pārbaudīt arī manuāli:

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

Ja Pitmaster ieraksta nederīgu objektu, `git fsck` nekavējoties ziņos par kļūdu.

## Zaru pārvaldība

### Zara izveide

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

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

Izveido atsauces failu `.git/refs/heads/<name>` ar mērķa komitējuma jaucējvērtību.

### Zara dzēšana

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

### Zaru pārslēgšana

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

Atjaunina HEAD, lai tas būtu simboliska atsauce uz zaru, atiestata indeksu atbilstoši zara jaunākā komitējuma kokam un atjaunina darba koku.

Ja starp abiem kokiem atšķirīgie ceļi ietver lokālas izmaiņas, pāreja tiek apturēta ar `RuntimeException`. Visu pārējo izsekoto failu nekomitētās izmaiņas tiek aizstātas ar zara saturu, kā to darītu git, saglabājot šīs izmaiņas ([#2](https://github.com/inline0/pitmaster/issues/2)). Pirms zara pārslēgšanas izveidojiet komitējumu vai noglabājiet izmaiņas.

### Apvienošanas statusa pārbaude

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

## Birkas pārvaldība

### Vieglā birka

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

Vieglā birka ir tikai atsauce, kas tieši norāda uz komitējumu.

### Anotētā birka

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

Anotēta birka izveido birkas objektu (ar birkas autoru, ziņojumu un mērķi) un atsauci, kas uz to norāda. Birkas autors ir pašreizējā komitētāja identitāte, ko nosaka tāpat kā komitējuma autoru.

### Pielāgots birkas autors

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

## Tieša atsauču atjaunināšana

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

## Objektu tieša ierakstīšana

Papildu lietojuma gadījumos objektus var ierakstīt, neizmantojot augsta līmeņa API.

### Blob objekta ierakstīšana

```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 repozitorijā norādiet algoritmu kā argumentu: `Blob::fromContent('Hello, world!', 'sha256')`.

### Koka ierakstīšana

```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()` ieraksta ierakstus norādītajā secībā un režīma virknes tādas, kādas tās norādītas. Padodiet tās git koka secībā (pēc nosaukuma, direktorijus salīdzinot tā, it kā to nosaukuma beigās būtu `/`) un ierakstiet direktoriju režīmus kā `40000`: git glabā koka režīmus bez sākuma nulles, bet `git fsck --strict` noraida `040000`.

### Komitējuma ierakstīšana

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

## Atiestatīšana

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

## Atjaunošana

```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 un atgriešana

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

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

Abi pieņem jebkuru pārskatījumu, ko atbalsta `resolve()`. Pilni jaucējkodi darbojas, saīsināti — ne.
