
# PHP API

## `Pitmaster\Pitmaster`

`Pitmaster\Pitmaster`-luokka on staattinen aloituspiste. Se tarjoaa tehdasmetodeja arkistojen avaamiseen, luomiseen ja kloonaamiseen sekä tunnistusapuja.

```php
use Pitmaster\Pitmaster;
```

### `open`

```php
public static function open(string $path, array $options = []): Repository
```

Avaa olemassa oleva arkisto kohteessa `$path`. Polun tulee olla työhakemiston juurihakemisto (sisältää kohteen `.git/`). Tukee myös linkitettyjä työhakemistoja (joissa `.git` on tiedosto, joka sisältää arvon `gitdir: <path>`) ja paljaita arkistoja (joissa `$path` on itse `.git`-hakemisto).

`$options` hyväksyy kaksi totuusarvoa, joiden oletusarvo on `true`:

- `hooks`: suorita `.git/hooks`-komentosarjat. Anna `false`, jos haluat ohittaa ne tässä kahvassa.
- `processes`: salli kaikki, mikä käynnistää prosessin tai avaa verkkoyhteyden. Anna `false`, jos haluat poistaa käytöstä koukut, fsmonitor-koukun, kloonauksen, haun, lähetyksen ja SSH-prosessikuljetuksen. Paikallinen luku ja kirjoitus toimivat edelleen.

Aiheuttaa `InvalidArgumentException`-poikkeuksen, jos polku ei ole git-arkisto.

```php
$repo = Pitmaster::open('/home/user/project');
$repo = Pitmaster::open('/home/user/project', ['hooks' => false]);
$repo = Pitmaster::open('/home/user/project', Pitmaster::processFreeOptions());
```

### `init`

```php
public static function init(string $path, string $objectFormat = 'sha1', array $options = []): Repository
```

Alusta uusi tietovarasto kohteeseen `$path`. Luo `.git`-hakemistorakenteen, jossa on `objects/`, `refs/heads/`, `refs/tags/`, `hooks/`, `info/`, `HEAD` (osoittaa kohteeseen `refs/heads/main`) sekä oletusarvoinen `config`.

`$objectFormat` on `'sha1'` tai `'sha256'`. SHA-256-tietovarasto saa asetuksiinsa arvot `repositoryformatversion = 1` ja `extensions.objectformat = sha256`. Mikä tahansa muu arvo aiheuttaa virheen `InvalidArgumentException`. `$options` käyttää samoja avaimia kuin `open()`.

Aiheuttaa virheen `RuntimeException`, jos polussa on jo tietovarasto.

```php
$repo = Pitmaster::init('/home/user/new-project');
$repo = Pitmaster::init('/home/user/sha256-project', 'sha256');
```

### `clone`

```php
public static function clone(string $url, string $path, ?int $depth = null, array $options = []): Repository
```

Kloonaa etätietovaraston. Alustaa uuden tietovaraston, etsii etäviitteet, noutaa pakettitiedoston, määrittää etäseurannan haarat ja luo työhakemiston sisällön. SSH-URL-osoitteet (`ssh://...` tai `user@host:path`) käyttävät SSH-siirtotapaa; muut URL-osoitteet käyttävät älykästä HTTP-siirtotapaa ja palaavat yksinkertaiseen HTTP-siirtotapaan, jos älykäs tiedonsiirto epäonnistuu. Välitä `$depth`, jos haluat tehdä matalan kloonauksen.

Aiheuttaa virheen `RuntimeException`, kun `$options['processes']` on `false`. Jos kloonaus epäonnistuu eikä `$path` ollut olemassa etukäteen, osittain luotu hakemisto poistetaan.

```php
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/tmp/repo');
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/tmp/shallow', 1);
$repo = Pitmaster::clone('https://github.com/user/repo.git', '/tmp/repo', null, ['hooks' => false]);
```

### `processFreeOptions`

```php
public static function processFreeOptions(): array
```

Palauttaa arvon `['processes' => false, 'hooks' => false]` suorituksille, jotka eivät saa käynnistää isäntäprosesseja. Välitä se funktiolle `open()` tai `init()`.

### `isRepository`

```php
public static function isRepository(string $path): bool
```

Tarkistaa, onko polku git-tietovarasto. Palauttaa arvon `true` tavallisille tietovarastoille (`.git/`-hakemisto), linkitetyille työhakemistoille (`.git`-tiedosto) ja paljaille tietovarastoille (`HEAD`-tiedosto on olemassa).

```php
if (Pitmaster::isRepository('/path/to/check')) {
    // It's a git repo
}
```

### `isWorktree`

```php
public static function isWorktree(string $path): bool
```

Tarkistaa, onko polku linkitetty työhakemisto (ei päätietovarasto). Palauttaa arvon `true` vain, jos `.git` on tiedosto, joka sisältää `gitdir:`-viitteen.

```php
if (Pitmaster::isWorktree('/path/to/worktree')) {
    // It's a linked worktree
}
```

### `commonGitDir`

```php
public static function commonGitDir(string $path): ?string
```

Ratkaisee yhteisen git-hakemiston mistä tahansa työkopion polusta. Tavallisissa tietovarastoissa tämä on `.git`-hakemisto. Linkitetyissä työhakemistoissa tämä on jaettu git-hakemisto, joka sisältää objektit, asetukset ja pakatut viitteet. Palauttaa arvon `null`, jos polku ei ole tietovarasto.

```php
$common = Pitmaster::commonGitDir('/path/to/worktree');
// '/path/to/main-repo/.git'
```

---

## `Pitmaster\Repository`

`Pitmaster\Repository`-luokka on kaikkien git-toimintojen päärajapinta. Luo olio kutsumalla `Pitmaster::open()`, `Pitmaster::init()` tai `Pitmaster::clone()`.

```php
use Pitmaster\Repository;
```

### Polun apufunktiot

#### `gitDir`

```php
public function gitDir(): string
```

Palauttaa työhakemiston git-hakemiston. Tavallisissa tietovarastoissa se on `.git/`. Linkitetyissä työhakemistoissa se on `.git/worktrees/<name>/`.

#### `commonGitDir`

```php
public function commonGitDir(): string
```

Palauttaa jaetun git-hakemiston. Tavallisissa tietovarastoissa sama kuin `gitDir()`. Linkitetyissä työhakemistoissa tämä on päätietovaraston `.git/`-hakemisto (jossa objektit, asetukset ja pakatut viitteet sijaitsevat).

#### `workDir`

```php
public function workDir(): string
```

Palauttaa työhakemiston juuripolun.

#### `isLinkedWorktree`

```php
public function isLinkedWorktree(): bool
```

Palauttaa arvon `true`, jos tämä tietovarasto-olio edustaa linkitettyä työhakemistoa.

#### `isBare`, `hooksEnabled`, `processesEnabled`

```php
public function isBare(): bool
public function hooksEnabled(): bool
public function processesEnabled(): bool
```

Ilmoittaa, puuttuuko tietovarastolta työhakemisto, ja mitkä vaihtoehdoista `hooks` / `processes` ovat käytössä tässä olion käsittelyssä. `hooksEnabled()` on `false` aina, kun prosessit on poistettu käytöstä.

---

### Objektit

#### `readObject`

```php
public function readObject(string $hash): GitObject
```

Lukee minkä tahansa objektin sen täydellä heksadesimaalisella tiivisteellä (40 merkkiä tai 64 SHA-256-tietovarastossa). Lyhennettyjä tiivisteitä ei hyväksytä. Palauttaa instanssin, jonka tyyppi on `Blob`, `Tree`, `Commit` tai `Tag`. Etsii ensin irralliset objektit ja sen jälkeen pakatut tiedostot.

Aiheuttaa virheen `ObjectNotFoundException`, jos tiivistettä ei löydy.

```php
$object = $repo->readObject('a1b2c3d4e5f6...');
```

#### `writeObject`

```php
public function writeObject(GitObject $object): ObjectId
```

Kirjoittaa objektin irrallisten objektien säilöön. Palauttaa lasketun arvon `ObjectId`.

```php
use Pitmaster\Object\Blob;

$blob = Blob::fromContent('Hello, world!');
$id = $repo->writeObject($blob);
```

#### `catFile`

```php
public function catFile(string $hash): string
```

Palauttaa objektin raakasisällön, vastaa toimintoa `git cat-file -p`.

```php
echo $repo->catFile('a1b2c3d4...');
```

#### `objectExists`

```php
public function objectExists(string $hash): bool
```

Tarkistaa, onko objekti olemassa tietovarastossa (irrallisena tai pakattuna).

#### `listObjects`

```php
public function listObjects(): array
```

Luettelee kaikki tietovaraston objektitiivisteet. Palauttaa heksadesimaalimerkkijonojen taulukon.

---

### Viitteet

#### `head`

```php
public function head(): Commit
```

Palauttaa nykyisen HEAD-sitoumuksen. Seuraa symbolisia viitteitä (HEAD -> refs/heads/main -> sitoumuksen tiiviste).

Aiheuttaa virheen `RuntimeException`, jos HEAD ei osoita kelvolliseen sitoumukseen (e.g., tyhjä tietovarasto).

#### `branch`

```php
public function branch(?string $name = null): ?string
```

Ilman argumentteja palauttaa nykyisen haaran nimen (e.g., `'main'`) tai arvon `null`, jos HEAD on irrotettu.

Haaran nimi annettuna ratkaisee sen sitoumuksen tiivisteeksi (heksadesimaalimerkkijonoksi) tai palauttaa arvon `null`, jos haaraa ei ole.

```php
$current = $repo->branch();        // 'main'
$hash = $repo->branch('feature');   // 'abc123...' or null
```

#### `branches`

```php
public function branches(): array
```

Palauttaa lajitellun taulukon kaikista haarojen nimistä (ilman etuliitettä `refs/heads/`).

```php
$branches = $repo->branches();
// ['bugfix/typo', 'feature/login', 'main']
```

#### `tags`

```php
public function tags(): array
```

Palauttaa lajitellun taulukon kaikista tunnisteiden nimistä (ilman etuliitettä `refs/tags/`).

#### `resolve`

```php
public function resolve(string $revision): ObjectId
```

Ratkaisee versiomääritteen `ObjectId`-arvoksi. Tuetut muodot:
- Täydet heksadesimaaliset tiivisteet (40 merkkiä tai 64 muodossa SHA-256). Lyhennettyjä tiivisteitä, kuten `abc1234`, ei ratkaista.
- `HEAD`
- Haarojen nimet (`main`, `feature/login`)
- Tunnisteiden nimet (`v1.0.0`)
- Täydet viitepolut (`refs/heads/main`)
- Versiolausekkeet (`HEAD~3`, `main^2`)

Aiheuttaa virheen `RuntimeException`, jos versiota ei voida ratkaista.

```php
$id = $repo->resolve('HEAD~3');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('feature/login');
```

#### `allRefs`

```php
public function allRefs(): array
```

Palauttaa kaikki viitteet assosiatiivisena taulukkona, jossa viitteen nimi vastaa heksadesimaalista tiivistettä.

```php
$refs = $repo->allRefs();
// ['refs/heads/main' => 'abc123...', 'refs/tags/v1.0.0' => 'def456...']
```

#### `updateRef`

```php
public function updateRef(string $name, ObjectId $target): void
```

Päivittää viitteen osoittamaan uuteen kohteeseen.

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

#### `createBranch`

```php
public function createBranch(string $name, ?ObjectId $from = null): void
```

Luo uuden haaran. Jos `$from` on null, haara luodaan nykyisestä HEADista.

```php
$repo->createBranch('feature/new-thing');
$repo->createBranch('hotfix', $repo->resolve('v1.0.0'));
```

#### `deleteBranch`

```php
public function deleteBranch(string $name): void
```

Poistaa haaran nimen perusteella. Aiheuttaa virheen `RuntimeException`, jos haara on työhakemistossa käytössä tai sitä ei ole. Toisin kuin `git branch -d`, tämä ei tarkista, onko haara yhdistetty.

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

#### `createLightweightTag`

```php
public function createLightweightTag(string $name, ?ObjectId $target = null): void
```

Luo kevyen tunnisteen. Jos `$target` on null, tunniste lisätään suoraan nykyiseen HEADiin.

```php
$repo->createLightweightTag('v2.0.0');
$repo->createLightweightTag('hotfix-start', $repo->resolve('main~2'));
```

#### `createTag`

```php
public function createTag(string $name, string $message, ?ObjectId $target = null, ?string $tagger = null): ObjectId
```

Luo selittävän tunnisteen. Jos `$target` on null, tunniste lisätään nykyiseen HEADiin. Palauttaa tunnisteobjektin arvon `ObjectId`.

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

#### `deleteTag`

```php
public function deleteTag(string $name): void
```

Poistaa tunnisteen nimen perusteella.

```php
$repo->deleteTag('v1.0.0');
```

#### `packRefs`

```php
public function packRefs(): void
```

Kirjoittaa jaetun `packed-refs`-tiedoston uudelleen nykyisten irrallisten viitteiden perusteella ja poistaa niitä vastaavat jaetut irralliset viitteet. Linkitetyissä työhakemistoissa kirjoitus tehdään yhteiseen git-hakemistoon.

```php
$repo->packRefs();
```

#### `defaultBranch`

```php
public function defaultBranch(): string
```

Ratkaisee tietovaraston oletushaaran. Tarkistaa ensin etä-HEADin symbolisen viitteen, sitten paikallisen HEADin ja käyttää lopuksi arvoa `main` tai `master`.

#### `isBranchMerged`

```php
public function isBranchMerged(string $branch, ?string $target = null): bool
```

Tarkistaa, onko haara yhdistetty kokonaan toiseen haaraan (oletuksena oletushaaraan).

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

#### `checkout`

```php
public function checkout(string $target): void
```

Vaihtaa haaraa tai irrottaa HEADin. Päivittää HEADin, indeksin ja työhakemiston. `$target` voi olla haaran nimi, tunniste, täydellinen tiiviste tai versiolauseke; mikä tahansa muu irrottaa HEADin.

Aiheuttaa virheen `RuntimeException`, jos paikallinen muutos (indeksoitu tai ei) tai seuraamaton tiedosto sijaitsee polussa, joka eroaa nykyisen ja kohdepuun välillä.

Muiden seurattujen tiedostojen vahvistamattomia muutoksia ei säilytetä: indeksi ja työhakemisto rakennetaan uudelleen kohdepuusta, joten tiedostoihin, jotka ovat identtisiä kummallakin puolella, tehdyt muutokset menetetään, vaikka git säilyttäisi ne ([#2](https://github.com/inline0/pitmaster/issues/2)). Vahvista tai siirrä muutokset ensin jemmaan. `merge()`, `cherryPick()`, `revert()`, `rebase()` ja puolitusmenetelmät rakentavat työhakemiston samalla tavalla.

```php
$repo->checkout('feature/login');
$repo->checkout($repo->resolve('v1.0.0')->hex);  // Detached HEAD
```

---

### Indeksi

#### `index`

```php
public function index(): Index
```

Lukee ja palauttaa nykyisen indeksin (valmistelualueen) sijainnista `.git/index`.

#### `add`

```php
public function add(string ...$paths): void
```

Lisää tiedostoja valmistelualueelle. Lukee kunkin tiedoston työhakemistosta, luo blob-objektin ja päivittää indeksin. Jokaisen argumentin on oltava työhakemiston juureen suhteutettu tiedostopolku (tai symbolinen linkki); hakemistoja ja jokerimerkkejä ei laajenneta, ja puuttuva tiedosto aiheuttaa virheen `RuntimeException`.

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

#### `remove`

```php
public function remove(string ...$paths): void
public function removeCached(string ...$paths): void
```

Poistaa seuratut polut sekä indeksistä että työhakemistosta. Tukee argumenttilistassa muotoja `--cached` ja `-r` / `--recursive` toiminnallisuuden Git mukaisesti.

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

#### `mv`

```php
public function mv(string $source, string $destination): void
```

Siirtää tai nimeää tiedoston uudelleen sekä työhakemistossa että indeksissä.

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

---

### Sitoumukset

#### `commit`

```php
public function commit(?string $message = null, ?string $author = null): ObjectId
```

Luo sitoumuksen nykyisestä indeksistä. Rakentaa puuhierarkian indeksimerkintöjen perusteella, luo sitoumusobjektin (tarvittaessa nykyinen HEAD vanhempana) ja päivittää HEADin. Palauttaa uuden sitoumuksen arvon `ObjectId`.

`$message` voi olla `null` vain, kun yhdistäminen, valikoiva poiminta, palautus tai uudelleenpohjaus on pysähtynyt ristiriitaan; tällöin käytetään valmisteltua viestiä. Muussa tapauksessa `null`-viesti aiheuttaa virheen `RuntimeException('Commit message required')`. Sitoumus epäonnistuu myös, jos indeksissä on yhdistämättömiä polkuja, indeksi on tyhjä tietovarastossa, jossa ei ole sitoumuksia, tai puu ei ole muuttunut HEADista.

`$author`-parametri on täydellinen git-tekijämerkkijono (`Name <email> timestamp timezone`). Jos se on null, arvo ratkaistaan ympäristömuuttujista, vakioista ja `.git/config`-asetuksista [Aloitusoppaassa](https://pitmaster.inline0.dev/fi/docs/getting-started) kuvatulla tavalla.

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

#### `show`

```php
public function show(string $revision): array
```

Näyttää sitoumuksen tai sitä vastaavan viitteen ja sen eron ensimmäiseen vanhempaan. Kun versio ratkeaa selittäväksi tunnisteeksi, paluuarvo sisältää myös `['tag' => Tag]`, ja `commit` on kohdesitoumus, johon tunniste on purettu.

```php
$result = $repo->show('HEAD');
echo $result['commit']->message;

foreach ($result['diff'] as $diff) {
    echo $diff->format();
}
```

#### `reset`

```php
public function reset(string $revision, string $mode = 'mixed'): void
```

Palauttaa HEADin sitoumukseen. Tilat:
- `'soft'`: siirtää vain HEADin
- `'mixed'`: siirtää HEADin ja nollaa indeksin (oletus)
- `'hard'`: siirtää HEADin, nollaa indeksin ja palauttaa työhakemiston alkutilaan

```php
$repo->reset('HEAD~1', 'soft');
$repo->reset('main', 'hard');
```

#### `restore`

```php
public function restore(string $path, ?string $source = null, bool $staged = false, bool $worktree = false): void
```

Palauttaa polun indeksistä tai tietystä lähdeversiosta. Jos kumpaakaan valintaa ei ole asetettu, Pitmaster palauttaa työhakemiston indeksin mukaiseksi (tai käyttää versiota `$source`, jos se annetaan). `staged: true` palauttaa indeksin HEADin mukaiseksi (tai käyttää `$source`) eikä muuta työhakemistoa; välitä `staged: true, worktree: true`, jos haluat palauttaa molemmat.

```php
$repo->restore('src/File.php');                                        // Worktree from index
$repo->restore('src/File.php', staged: true);                          // Index from HEAD
$repo->restore('src/File.php', 'HEAD~1');                              // Worktree from another commit
$repo->restore('src/File.php', 'HEAD~1', staged: true, worktree: true); // Index + worktree from another commit
```

#### `cherryPick`

```php
public function cherryPick(string $revision): ObjectId
public function cherryPickContinue(): ObjectId
public function cherryPickAbort(): void
```

Ottaa sitoumuksen käyttöön nykyisellä haaralla uutena sitoumuksena alkuperäisen tekijän säilyttäen. Jos ristiriidat pysäyttävät toiminnon, ratkaise ne, lisää polut valmistelualueelle ja kutsu sitten `cherryPickContinue()` tai `cherryPickAbort()`.

```php
$newId = $repo->cherryPick('feature~2');

// After resolving conflicts:
$repo->add('src/File.php');
$repo->cherryPickContinue();
```

#### `revert`

```php
public function revert(string $revision): ObjectId
public function revertContinue(): ObjectId
public function revertAbort(): void
```

Luo sitoumuksen, joka kumoaa toisen sitoumuksen. Jos ristiriidat pysäyttävät palautuksen, ratkaise ne, lisää polut valmistelualueelle ja kutsu sitten `revertContinue()` tai `revertAbort()`.

```php
$revertId = $repo->revert('HEAD~1');

// After resolving conflicts:
$repo->add('src/File.php');
$repo->revertContinue();
```

#### `rebase`

```php
public function rebase(string $onto): array
public function rebaseContinue(): array
public function rebaseAbort(): void
public function rebaseSkip(): array
```

Uudelleenpohjaa nykyinen haara toisen version päälle. Pitmaster tukee tällä hetkellä lineaarista uudelleenpohjausta, jossa ristiriitojen pysäytystila on muotoa Git, sekä jatkamista, keskeyttämistä ja ohittamista. HEADin on osoitettava haaraan.

`rebase()`, `rebaseContinue()` ja `rebaseSkip()` palauttavat arvon `['success' => bool, 'commits' => int, 'conflicts' => list<string>]`: valmistuiko uudelleenpohjaus, kuinka monta sitoumusta otettiin käyttöön ja mitkä polut olivat ristiriidassa toiminnon pysähtyessä.

```php
$result = $repo->rebase('main');

if (!$result['success']) {
    // Resolve conflicts, then continue or skip/abort.
    $repo->add('src/File.php');
    $repo->rebaseContinue();
}
```

---

### Tila

#### `status`

```php
public function status(): array
```

Laskee työhakemiston tilan. Palauttaa taulukon `StatusEntry`-olioita, joista kukin sisältää:
- `path`: tiedostopolku
- `index`: HEADin ja indeksin välisten muutosten `FileStatus`-luettelo
- `worktree`: indeksin ja työhakemiston välisten muutosten `FileStatus`-luettelo
- `origPath`, `renameScore`: asetettuina uudelleennimettyjen merkintöjen kohdalla, muuten `null`

Seuraamattomien tiedostojen molemmissa sarakkeissa on `FileStatus::Untracked`. Ohitettuja tiedostoja ei ilmoiteta.

```php
foreach ($repo->status() as $entry) {
    echo $entry->shortFormat() . "\n"; // "M  src/File.php", "?? notes.txt"
}
```

#### `statusPorcelainV2`

```php
public function statusPorcelainV2(): string
```

Koneellisesti luettava tilatuloste gitin porcelain-muodossa v2.

```php
echo $repo->statusPorcelainV2();
// 1 M. N... 000000 000000 000000 0000...0000 0000...0000 modified-file.txt
// ? untracked-file.txt
```

---

### Ero

#### `diff`

```php
public function diff(?string $pathspec = null, string $algorithm = 'myers'): array
```

Näyttää työhakemiston ja indeksin väliset erot (valmistelualueelle lisäämättömät muutokset). Palauttaa taulukon `DiffResult`-olioita. `$pathspec` rajaa tuloksen täsmälleen yhteen tiedostopolkuun. `$algorithm` on `'myers'` (oletus), `'patience'`, `'histogram'` tai `'minimal'`; mikä tahansa muu arvo aiheuttaa virheen `InvalidArgumentException`.

```php
$diffs = $repo->diff();

foreach ($diffs as $diff) {
    echo $diff->format();  // Unified diff output
}
```

#### `diffStaged`

```php
public function diffStaged(?string $pathspec = null, string $algorithm = 'myers'): array
```

Näyttää indeksin ja HEADin väliset erot (valmistelualueelle lisätyt muutokset). Palauttaa arvon `DiffResult[]` ja tunnistaa uudelleennimetyt tiedostot poistettujen ja lisättyjen tiedostojen välillä.

Argumentti `$pathspec` ohitetaan tällä hetkellä, joten kaikki valmistelualueelle lisätyt tiedostot palautetaan. Ennen ensimmäistä sitoumusta metodi palauttaa tyhjän taulukon ([#5](https://github.com/inline0/pitmaster/issues/5)).

```php
$staged = $repo->diffStaged();
```

#### `diffTree`

```php
public function diffTree(ObjectId $a, ObjectId $b, string $algorithm = 'myers'): array
```

Näyttää kahden puun erot niiden `ObjectId`-tunnisteiden perusteella. Palauttaa arvon `DiffResult[]`. Välitä puutunnisteet, älä sitoumustunnisteita: sitoumustunnistetta ei lueta puuna, joten tulos on tyhjä.

```php
$old = $repo->readObject($repo->resolve('HEAD~1')->hex);
$new = $repo->head();
$diffs = $repo->diffTree($old->tree, $new->tree);
```

---

### Lokit

#### `log`

```php
public function log(int $limit = 50, ?ObjectId $from = null): array
```

Käy sitoumushistorian läpi uusimmasta alkaen tekijän aikaleiman mukaan. Palauttaa arvon `Commit[]`. Jos `$from` on null, aloituskohtana käytetään HEADia. Palauttaa tyhjän taulukon, jos HEADilla ei vielä ole sitoumusta.

```php
$commits = $repo->log(10);
```

#### `logAll`

```php
public function logAll(int $limit = 50): array
```

Käy läpi kaikkien viitteiden ja HEADin kautta saavutettavat sitoumukset uusimmasta alkaen. Palauttaa arvon `Commit[]`.

#### `logOneline`

```php
public function logOneline(int $limit = 50, bool $all = false, ?string $path = null): array
```

Palauttaa lokirivit muodossa `git log --oneline` (`abc1234 Subject`), HEADista, kaikista viitteistä (`$all`) tai polun mukaan suodatettuina.

#### `logPath`

```php
public function logPath(string $path, int $limit = 50): array
```

Näyttää tiedostopolun mukaan suodatetun lokin. Palauttaa vain sitoumukset, joiden ero ensimmäiseen vanhempaan lisää, muuttaa, poistaa tai nimeää uudelleen kyseisen tiedoston. Hakemistopolut eivät täsmää.

Vain uusimmat `5 * $limit` sitoumusta tutkitaan, joten vanhemmat tiedostoon liittyvät sitoumukset voivat puuttua tuloksesta ([#7](https://github.com/inline0/pitmaster/issues/7)).

```php
$commits = $repo->logPath('src/Repository.php', 20);
```

---

### Yhdistäminen

#### `merge`

```php
public function merge(string $branch, string $strategy = 'recursive'): MergeResult
public function mergeOctopus(array $branches): MergeResult
public function mergeContinue(): ObjectId
public function mergeAbort(): void
```

Yhdistää haaran (tai minkä tahansa version) HEADiin. Tunnistaa pikakelauksen automaattisesti. Muissa yhdistämisissä tarkistaa puutason ristiriidat ja luo siistissä tilanteessa yhdistämissitoumuksen. Ristiriitatilanteessa kirjoittaa indeksiin ja työhakemistoon yhdistämistilan muodossa Git; ratkaise polut, lisää ne valmistelualueelle ja kutsu sitten `mergeContinue()` tai `mergeAbort()`.

`$strategy` `'ours'` tallentaa yhdistämissitoumuksen, joka säilyttää HEADin puun; mikä tahansa muu arvo käyttää oletusarvoista rekursiivista yhdistämistä. `mergeOctopus()` yhdistää vähintään kaksi haaraa yhdeksi sitoumukseksi. Jos jokin haara aiheuttaa ristiriitoja, palautetaan epäsiisti tulos kirjoittamatta yhdistämistilaa tai luomatta sitoumusta.

Jo HEADiin sisältyvän haaran yhdistäminen luo uuden yhdistämissitoumuksen sen sijaan, että ilmoittaisi "Jo ajan tasalla" ([#6](https://github.com/inline0/pitmaster/issues/6)). Seurattujen tiedostojen vahvistamattomat muutokset korvataan kohdassa `checkout()` kuvatulla tavalla.

Palauttaa arvon `MergeResult`, joka sisältää:
- `clean`: onnistuiko yhdistäminen ilman ristiriitoja
- `commitId`: yhdistämissitoumuksen tunniste (jos yhdistäminen onnistui siististi)
- `conflictPaths`: ristiriitaisten tiedostopolkujen taulukko (jos yhdistäminen ei onnistunut siististi)
- `mergedContents`: ristiriitainen polku ja tiedoston sisältö ristiriitamerkkeineen (jos yhdistäminen ei onnistunut siististi)

```php
$result = $repo->merge('feature/login');

if ($result->clean) {
    echo "Merged: {$result->commitId->hex}\n";
} else {
    echo "Conflicts in: " . implode(', ', $result->conflictPaths) . "\n";
    $repo->add('src/File.php');
    $repo->mergeContinue();
}
```

#### `mergeBase`

```php
public function mergeBase(ObjectId $a, ObjectId $b): ?ObjectId
```

Etsii kahden sitoumuksen yhdistämiskohdan (alimman yhteisen edeltäjän). Palauttaa null, jos yhteistä edeltäjää ei ole.

```php
$base = $repo->mergeBase(
    $repo->resolve('main'),
    $repo->resolve('feature/login'),
);
```

### Puolitus

```php
public function bisectStart(string $bad, string $good): ObjectId
public function bisectGood(?string $revision = null): ?ObjectId
public function bisectBad(?string $revision = null): ?ObjectId
public function bisectReset(): void
```

Etsii puolittamalla sitoumuksen, joka toi muutoksen. `bisectStart()` tallentaa huonot ja hyvät versiot, ottaa ensimmäisen ehdokkaan käyttöön ja palauttaa sen. `bisectGood()` ja `bisectBad()` merkitsevät nykyisen HEADin (tai arvon `$revision`) ja ottavat seuraavan ehdokkaan käyttöön sekä palauttavat sen. Kun jäljellä on yksi epäilty, kyseinen sitoumus palautetaan ja se jää ehdokkaaksi: se on ensimmäinen huono sitoumus. `bisectReset()` päättää istunnon ja palaa haaraan tai sitoumukseen, josta se alkoi.

```php
$candidate = $repo->bisectStart('HEAD', 'v1.0.0');
// test $candidate ...
$candidate = $repo->bisectBad();
$candidate = $repo->bisectGood();
$repo->bisectReset();
```

---

### Verkko

#### `fetch`

```php
public function fetch(string $remote = 'origin', ?int $depth = null): void
```

Noutaa muutoksia etätietovarastosta. Lataa uudet objektit ja päivittää etäseurannan viitteet. Syvennä tai rajaa matalaa historiaa välittämällä `$depth`.

`fetch()` ja `push*()`-metodit aiheuttavat virheen `RuntimeException`, kun käsittelyolio on avattu asetuksella `['processes' => false]`.

```php
$repo->fetch();
$repo->fetch('upstream');
```

#### `push`

```php
public function push(string $remote = 'origin', ?string $branch = null): void
public function pushForceWithLease(string $remote = 'origin', ?string $branch = null, ?ObjectId $expected = null): void
public function pushAtomic(string $remote = 'origin', array $branches = []): void
public function pushMirror(string $remote = 'origin'): void
```

Lähettää nykyisen haaran (tai määritetyn haaran) etätietovarastoon. Tiukempia tai laajempia viitepäivityksiä varten käytettävissä ovat pakotettu lähetys lease-tarkistuksella, atominen lähetys ja peilausversio.

```php
$repo->push();
$repo->push('origin', 'feature/login');
$repo->pushForceWithLease('origin', 'main', $repo->resolve('refs/remotes/origin/main'));
$repo->pushAtomic('origin', ['main', 'release']);
$repo->pushMirror();
```

---

### Työhakemistot

#### `addWorktree`

```php
public function addWorktree(string $path, string $branch, ?ObjectId $from = null, ?string $name = null): Worktree
```

Lisää linkitetyn työhakemiston. Luo haaran, jos sitä ei ole, määrittää työhakemiston metatiedot ja luo työhakemiston tiedostot. Välitä `$name`, jos tarvitset deterministisen metatietotunnisteen, joka eroaa työkopion hakemiston perusnimestä.

```php
$wt = $repo->addWorktree('/tmp/review', 'feature/review');
$wt = $repo->addWorktree('/tmp/checkouts/review', 'feature/review', name: 'review-wt');
```

#### `removeWorktree`

```php
public function removeWorktree(string $pathOrName, bool $force = false): void
```

Poistaa linkitetyn työhakemiston. Poista myös lukittu työhakemisto käyttämällä valintaa `$force = true`.

#### `worktrees`

```php
public function worktrees(): array
```

Luettelee kaikki työhakemistot (päätyöhakemisto ja linkitetyt). Palauttaa arvon `Worktree[]`.

```php
foreach ($repo->worktrees() as $wt) {
    echo "{$wt->path} [{$wt->branch}]\n";
}
```

---

### Asetukset

#### `config`

```php
public function config(): GitConfig
```

Käyttää tietovaraston git-asetuksia sekä lukee ja kirjoittaa asetusarvoja.

```php
$config = $repo->config();
$name = $config->get('user.name');
$config->set('user.email', 'new@example.com');
```

---

### Sisäinen käyttö

Nämä metodit tarjoavat pääsyn sisäisiin komponentteihin edistyneitä käyttötapauksia varten.

#### `objectDatabase`

```php
public function objectDatabase(): ObjectDatabase
```

Käyttää objektitietokantaa suoraan (irralliset ja pakatut objektit).

#### `refDatabase`

```php
public function refDatabase(): RefDatabase
```

Käyttää viitetietokantaa suoraan (irralliset ja pakatut viitteet).

---

## Alemman tason luokat

Nämä luokat eivät ole `Repository`-luokan kääreitä, vaan ne luodaan sen sisäisistä komponenteista.

### `Pitmaster\Graph\Blame`

```php
public function blame(ObjectId $headId, string $path): array
```

Palauttaa yhden merkinnän jokaiselle sijainnissa `$headId` olevan `$path`-tiedoston riville: `['line' => int, 'hash' => string, 'author' => string, 'content' => string]`. `author` on koko tunnistemerkintä (`Name <email> timestamp timezone`).

```php
use Pitmaster\Graph\Blame;

$blame = new Blame($repo->objectDatabase());

foreach ($blame->blame($repo->resolve('HEAD'), 'src/File.php') as $line) {
    echo substr($line['hash'], 0, 8) . " {$line['content']}\n";
}
```

### `Pitmaster\Graph\Grep`

```php
public function grep(ObjectId $treeId, string $pattern, string $prefix = '', array $options = []): array
```

Hakee puun blob-objekteista. Palauttaa yhden arvon `['path' => string, 'line' => int, 'content' => string]` kutakin vastaavaa riviä kohti. Valinnat: `regex` (käsittelee mallia PCRE-kuviona) ja `ignore_case`. Virheellinen säännöllinen lauseke aiheuttaa virheen `InvalidArgumentException`.

```php
use Pitmaster\Graph\Grep;

$grep = new Grep($repo->objectDatabase());
$matches = $grep->grep($repo->head()->tree, 'TODO', '', ['ignore_case' => true]);
```

### `Pitmaster\Ref\Notes`

```php
public function get(ObjectId $commitId, string $notesRef = 'refs/notes/commits'): ?string
public function set(ObjectId $commitId, string $noteContent, string $notesRef = 'refs/notes/commits'): void
public function remove(ObjectId $commitId, string $notesRef = 'refs/notes/commits'): void
public function listAll(string $notesRef = 'refs/notes/commits'): array
public function merge(string $sourceRef, string $targetRef = 'refs/notes/commits'): void
```

Lukee ja kirjoittaa viitehaaran alle tallennettuja git-muistiinpanoja. `listAll()` palauttaa sitoumuksen tiivisteen ja muistiinpanon sisällön.

```php
use Pitmaster\Ref\Notes;

$notes = new Notes($repo->objectDatabase(), $repo->refDatabase());
$notes->set($repo->resolve('HEAD'), "Reviewed\n");
echo $notes->get($repo->resolve('HEAD'));
```
