
# Tárolók írása

Az Pitmaster ugyanazokkal a bináris formátumokkal írja a git-adattárakat, mint a kanonikus `git` bináris. Az objektumokat a lazaobjektum-tárolóba írja (zlib-tömörítéssel), az indexet pedig v2 formátumban (vagy v3 formátumban, ha a bejegyzéseknek kiterjesztett jelzőkre van szükségük; a meglévő index megtartja a verzióját), a hivatkozásokat pedig különálló fájlokként. Az írt adatok a `git fsck --strict` segítségével ellenőrizhetők.

## Tároló inicializálása

```php
use Pitmaster\Pitmaster;

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

Ez hozza létre a következőket:
- `.git/objects/` (üres objektumtároló)
- `.git/refs/heads/` és `.git/refs/tags/` (üres hivatkozáskönyvtárak)
- `.git/HEAD`, amely az `ref: refs/heads/main` értéket tartalmazza
- `.git/hooks/`, `.git/info/exclude` és `.git/description`
- `.git/config` alapértelmezett beállításokkal

Adja meg az `'sha256'` értéket második argumentumként egy SHA-256 tároló létrehozásához: `Pitmaster::init($path, 'sha256')`.

Az alapértelmezett konfiguráció nem állítja be az `core.logallrefupdates` értéket, ezért az Pitmaster nem rögzít reflog-bejegyzéseket az általa létrehozott tárolókban, amíg ezt a kulcsot `true` értékre nem állítja ([#8](https://github.com/inline0/pitmaster/issues/8)). Az `git init` által létrehozott tárolókban ez már be van állítva.

## Fájlok előkészítése

### add

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

Minden argumentum a munkafa gyökérkönyvtárához viszonyított fájlútvonal. A könyvtárakat és globmintákat nem bontja ki, hiányzó fájl esetén pedig `RuntimeException` hibát dob. Minden fájlnál az Pitmaster:
1. Beolvassa a fájl tartalmát a munkafából
2. `Blob` objektumot hoz létre, és kiszámítja a hashét
3. A blobot az `.git/objects/` helyre írja (zlibbel tömörítve)
4. Frissíti az adott útvonal indexbejegyzését az új hash-sel és fájlmetaadatokkal

### remove

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

Eltávolítja a követett útvonalakat az indexből és a munkafából. Az indexből történő eltávolításhoz használja az `--cached` értéket; követett könyvtárakhoz pedig az `-r` / `--recursive` értéket.

### mv

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

Átnevezi a fájlt a munkafában, eltávolítja a régi indexbejegyzést, és hozzáadja az újat.

## Commitok létrehozása

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

A commit létrehozásának folyamata:

1. **Fa felépítése az indexből**: az indexbejegyzések lapos listáját fastruktúrába rendezi (a könyvtárak faobjektumokká, a fájlok pedig blobhivatkozásokká válnak). Minden fa bekerül az objektumtárolóba.
2. **Szülő meghatározása**: az aktuális HEAD commit lesz a szülő. A gyökércommitoknak (a tároló első commitjainak) nincs szülőjük.
3. **Szerző meghatározása**: az `PITMASTER_AUTHOR_*` és `GIT_AUTHOR_*` környezeti változók, majd az `PITMASTER_AUTHOR_NAME`/`PITMASTER_AUTHOR_EMAIL` konstansok, aztán az `.git/config` (`user.name`/`user.email`), végül az `Pitmaster <pitmaster@localhost>` alapján. A commitoló feloldása ugyanígy történik.
4. **Commitobjektum írása**: a commit tartalmát (`tree`, `parent`, `author`, `committer` és az üzenet) szerializálja, hash-eli, majd kiírja.
5. **HEAD frissítése**: frissíti azt az ág-hivatkozást az új commit hashére, amelyre a HEAD mutat.

A hookok e lépések előtt és után futnak (`pre-commit`, `prepare-commit-msg`, `commit-msg`, `post-commit`), kivéve, ha a fogantyút `['hooks' => false]` értékkel nyitották meg. Az `commit()` hibát dob, ha hiányzik az üzenet, ha a fa nem változott a HEAD-hez képest, vagy ha az indexben fel nem oldott útvonalak vannak.

### Egyéni szerző

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

## Ellenőrzés a git fsck segítségével

Az Pitmaster integrációs tesztjei az `git fsck --strict` segítségével ellenőrzik a kiírt objektumokat; ugyanezt manuálisan is megteheti:

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

Ha az Pitmaster érvénytelen objektumot ír, az `git fsck` azonnal jelzi a hibát.

## Ágak kezelése

### Ág létrehozása

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

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

Létrehoz egy hivatkozásfájlt az `.git/refs/heads/<name>` helyen, amely a cél commit hashét tartalmazza.

### Ág törlése

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

### Ágak közötti váltás

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

A HEAD-et az ágra mutató szimbolikus hivatkozásra állítja, visszaállítja az indexet az ág csúcsának fájára, és frissíti a munkafát.

Azokban az útvonalakban lévő helyi módosítások, amelyek eltérnek a két fa között, `RuntimeException` hibával leállítják a váltást. Minden más követett fájl nem véglegesített módosításait az ág tartalma váltja fel, amelyeket a Git megtartana ([#2](https://github.com/inline0/pitmaster/issues/2)). Váltás előtt véglegesítse vagy tegye félre a módosításokat.

### Ellenőrzés, hogy egyesült-e

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

## Címkék kezelése

### Könnyűsúlyú címke

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

A könnyűsúlyú címke egyszerűen egy közvetlenül egy commitra mutató hivatkozás.

### Megjegyzéssel ellátott címke

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

A megjegyzéssel ellátott címke létrehoz egy címkeobjektumot (címkézővel, üzenettel és céllal), valamint egy rá mutató hivatkozást. A címkéző az aktuális commitoló személyazonossága, amelyet a commit szerzőjével azonos módon old fel.

### Egyéni címkéző

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

## Hivatkozások közvetlen frissítése

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

## Objektumok közvetlen írása

Speciális felhasználási esetekben objektumokat a magas szintű API megkerülésével is írhat.

### Blob írása

```php
use Pitmaster\Object\Blob;

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

Egy SHA-256 tárolóban add át az algoritmust: `Blob::fromContent('Hello, world!', 'sha256')`.

### Fa írása

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

Az `Tree::fromEntries()` a megadott sorrendben írja ki a bejegyzéseket, és változtatás nélkül hagyja a megadott módkarakterláncokat. Adja meg őket az git fája szerinti sorrendben (név szerint rendezve, a könyvtárakat úgy kezelve, mintha a nevük `/` karakterrel végződne), a könyvtárak módját pedig `40000` formában írja meg: az git a kezdő nulla nélküli fa módokat tárolja, az `git fsck --strict` pedig elutasítja az `040000`-t.

### Commit írása

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

## Visszaállítás alaphelyzetbe

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

## Visszaállítás

```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 és visszavonás

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

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

Mindkettő bármilyen, a `resolve()` által elfogadott revíziót kezel. A teljes hash-ek működnek, a rövidített hash-ek nem.
