
# PHP API

## `Pitmaster\Pitmaster`

Η κλάση `Pitmaster\Pitmaster` είναι το στατικό σημείο εισόδου. Παρέχει μεθόδους factory για το άνοιγμα, τη δημιουργία και την κλωνοποίηση αποθετηρίων, καθώς και βοηθητικές μεθόδους εντοπισμού.

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

### `open`

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

Ανοίγει ένα υπάρχον αποθετήριο στη θέση `$path`. Η διαδρομή πρέπει να είναι η ρίζα του working tree (που περιέχει το `.git/`). Υποστηρίζει επίσης συνδεδεμένα worktrees (όπου το `.git` είναι αρχείο που περιέχει το `gitdir: <path>`) και γυμνά αποθετήρια (όπου το `$path` είναι ο ίδιος ο κατάλογος `.git`).

Το `$options` δέχεται δύο boolean τιμές, και οι δύο `true` από προεπιλογή:

- `hooks`: εκτελεί scripts `.git/hooks`. Περάστε `false` για να τα παραλείψετε για αυτό το handle.
- `processes`: επιτρέπει οτιδήποτε εκκινεί διεργασία ή ανοίγει μεταφορά δικτύου. Περάστε `false` για να απενεργοποιήσετε τα hooks, το hook fsmonitor, το clone, το fetch, το push και τη μεταφορά διεργασίας SSH. Οι τοπικές αναγνώσεις και εγγραφές εξακολουθούν να λειτουργούν.

Προκαλεί `InvalidArgumentException` αν η διαδρομή δεν είναι αποθετήριο git.

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

Αρχικοποιεί ένα νέο αποθετήριο στη θέση `$path`. Δημιουργεί τη δομή καταλόγου `.git` με τα `objects/`, `refs/heads/`, `refs/tags/`, `hooks/`, `info/`, `HEAD` (που δείχνει στο `refs/heads/main`) και ένα προεπιλεγμένο `config`.

Το `$objectFormat` είναι `'sha1'` ή `'sha256'`. Ένα αποθετήριο SHA-256 λαμβάνει τα `repositoryformatversion = 1` και `extensions.objectformat = sha256` στις ρυθμίσεις του. Κάθε άλλη τιμή προκαλεί `InvalidArgumentException`. Το `$options` δέχεται τα ίδια κλειδιά με το `open()`.

Προκαλεί `RuntimeException` αν υπάρχει ήδη αποθετήριο στη διαδρομή.

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

Κλωνοποιεί ένα απομακρυσμένο αποθετήριο. Αρχικοποιεί ένα νέο αποθετήριο, εντοπίζει απομακρυσμένα refs, ανακτά το αρχείο pack, ρυθμίζει κλάδους παρακολούθησης απομακρυσμένων και δημιουργεί το working tree. Οι διευθύνσεις URL SSH (`ssh://...` ή `user@host:path`) χρησιμοποιούν τη μεταφορά SSH· οι υπόλοιπες διευθύνσεις URL χρησιμοποιούν smart HTTP και επιστρέφουν σε dumb HTTP όταν αποτύχει η smart ανταλλαγή. Περάστε το `$depth` για ρηχό clone.

Προκαλεί `RuntimeException` όταν το `$options['processes']` είναι `false`. Αν το clone αποτύχει και το `$path` δεν υπήρχε προηγουμένως, ο κατάλογος που δημιουργήθηκε εν μέρει αφαιρείται.

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

Επιστρέφει `['processes' => false, 'hooks' => false]`, για περιβάλλοντα εκτέλεσης που δεν πρέπει να εκκινούν διεργασίες του συστήματος. Περάστε το στο `open()` ή στο `init()`.

### `isRepository`

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

Ελέγχει αν μια διαδρομή είναι αποθετήριο git. Επιστρέφει `true` για κανονικά αποθετήρια (κατάλογος `.git/`), συνδεδεμένα worktrees (αρχείο `.git`) και γυμνά αποθετήρια (υπάρχει το αρχείο `HEAD`).

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

### `isWorktree`

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

Ελέγχει αν μια διαδρομή είναι συνδεδεμένο worktree (όχι το κύριο αποθετήριο). Επιστρέφει `true` μόνο αν το `.git` είναι αρχείο που περιέχει αναφορά `gitdir:`.

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

### `commonGitDir`

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

Επιλύει τον κοινό κατάλογο git από οποιαδήποτε διαδρομή checkout. Για κανονικά αποθετήρια, είναι ο κατάλογος `.git`. Για συνδεδεμένα worktrees, είναι ο κοινόχρηστος κατάλογος git που περιέχει τα αντικείμενα, τις ρυθμίσεις και τα packed-refs. Επιστρέφει `null` αν η διαδρομή δεν είναι αποθετήριο.

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

---

## `Pitmaster\Repository`

Η κλάση `Pitmaster\Repository` είναι το κύριο handle για όλες τις λειτουργίες git. Αποκτήστε ένα μέσω των `Pitmaster::open()`, `Pitmaster::init()` ή `Pitmaster::clone()`.

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

### Accessors διαδρομών

#### `gitDir`

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

Επιστρέφει τον κατάλογο git ανά worktree. Για κανονικά αποθετήρια είναι το `.git/`. Για συνδεδεμένα worktrees, είναι το `.git/worktrees/<name>/`.

#### `commonGitDir`

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

Επιστρέφει τον κοινόχρηστο κατάλογο git. Για κανονικά αποθετήρια είναι το ίδιο με το `gitDir()`. Για συνδεδεμένα worktrees, είναι ο κατάλογος `.git/` του κύριου αποθετηρίου (όπου βρίσκονται τα αντικείμενα, οι ρυθμίσεις και τα packed-refs).

#### `workDir`

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

Επιστρέφει τη διαδρομή της ρίζας του working tree.

#### `isLinkedWorktree`

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

Επιστρέφει `true` αν αυτό το handle αποθετηρίου είναι συνδεδεμένο worktree.

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

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

Αναφέρει αν το αποθετήριο δεν έχει working tree και ποιες από τις επιλογές `hooks` / `processes` ισχύουν για αυτό το handle. Το `hooksEnabled()` είναι `false` όποτε οι διεργασίες είναι απενεργοποιημένες.

---

### Αντικείμενα

#### `readObject`

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

Διαβάζει οποιοδήποτε αντικείμενο με το πλήρες δεκαεξαδικό hash του (40 χαρακτήρες ή 64 σε αποθετήριο SHA-256). Δεν γίνονται δεκτά συντομευμένα hash. Επιστρέφει μια παρουσία `Blob`, `Tree`, `Commit` ή `Tag`. Αναζητά πρώτα στα loose objects και έπειτα στα αρχεία pack.

Προκαλεί `ObjectNotFoundException` αν δεν βρεθεί το hash.

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

#### `writeObject`

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

Γράφει ένα αντικείμενο στο αποθετήριο loose objects. Επιστρέφει το υπολογισμένο `ObjectId`.

```php
use Pitmaster\Object\Blob;

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

#### `catFile`

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

Επιστρέφει το ακατέργαστο περιεχόμενο ενός αντικειμένου, ισοδύναμο με το `git cat-file -p`.

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

#### `objectExists`

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

Ελέγχει αν υπάρχει ένα αντικείμενο στο αποθετήριο (loose ή packed).

#### `listObjects`

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

Παραθέτει όλα τα hash αντικειμένων στο αποθετήριο. Επιστρέφει έναν πίνακα από δεκαεξαδικές συμβολοσειρές.

---

### Αναφορές

#### `head`

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

Επιστρέφει το τρέχον commit του HEAD. Ακολουθεί συμβολικά refs (HEAD -> refs/heads/main -> hash commit).

Προκαλεί `RuntimeException` αν το HEAD δεν δείχνει σε έγκυρο commit (π.χ. e.g, κενό αποθετήριο).

#### `branch`

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

Χωρίς ορίσματα, επιστρέφει το όνομα του τρέχοντος κλάδου (π.χ. e.g, `'main'`) ή `null` αν το HEAD είναι αποσυνδεδεμένο.

Με όνομα κλάδου, το επιλύει στο hash commit του (δεκαεξαδική συμβολοσειρά) ή επιστρέφει `null` αν ο κλάδος δεν υπάρχει.

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

#### `branches`

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

Επιστρέφει έναν ταξινομημένο πίνακα με όλα τα ονόματα κλάδων (χωρίς το πρόθεμα `refs/heads/`).

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

#### `tags`

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

Επιστρέφει έναν ταξινομημένο πίνακα με όλα τα ονόματα ετικετών (χωρίς το πρόθεμα `refs/tags/`).

#### `resolve`

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

Επιλύει μια έκφραση αναθεώρησης σε `ObjectId`. Υποστηρίζει:
- Πλήρη δεκαεξαδικά hash (40 χαρακτήρες ή 64 για SHA-256). Δεν επιλύονται συντομευμένα hash όπως το `abc1234`.
- `HEAD`
- Ονόματα κλάδων (`main`, `feature/login`)
- Ονόματα ετικετών (`v1.0.0`)
- Πλήρεις διαδρομές ref (`refs/heads/main`)
- Εκφράσεις αναθεώρησης (`HEAD~3`, `main^2`)

Προκαλεί `RuntimeException` αν δεν είναι δυνατή η επίλυση της αναθεώρησης.

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

#### `allRefs`

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

Επιστρέφει όλα τα refs ως συσχετιστικό πίνακα από όνομα ref σε δεκαεξαδικό hash.

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

#### `updateRef`

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

Ενημερώνει ένα ref ώστε να δείχνει σε νέο στόχο.

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

#### `createBranch`

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

Δημιουργεί έναν νέο κλάδο. Αν το `$from` είναι null, δημιουργεί κλάδο από το τρέχον HEAD.

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

#### `deleteBranch`

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

Διαγράφει έναν κλάδο με βάση το όνομά του. Προκαλεί `RuntimeException` αν ο κλάδος έχει γίνει checkout ή δεν υπάρχει. Σε αντίθεση με το `git branch -d`, δεν ελέγχει αν ο κλάδος έχει συγχωνευθεί.

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

#### `createLightweightTag`

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

Δημιουργεί μια ελαφριά ετικέτα. Αν το `$target` είναι null, προσθέτει ετικέτα απευθείας στο τρέχον HEAD.

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

Δημιουργεί μια σχολιασμένη ετικέτα. Αν το `$target` είναι null, προσθέτει ετικέτα στο τρέχον HEAD. Επιστρέφει το `ObjectId` του αντικειμένου ετικέτας.

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

#### `deleteTag`

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

Διαγράφει μια ετικέτα με βάση το όνομά της.

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

#### `packRefs`

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

Επανεγγράφει το κοινόχρηστο αρχείο `packed-refs` από το τρέχον σύνολο loose refs και αφαιρεί τα αντίστοιχα κοινόχρηστα loose refs. Για συνδεδεμένα worktrees, γράφει στον κοινό κατάλογο git.

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

#### `defaultBranch`

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

Επιλύει τον προεπιλεγμένο κλάδο του αποθετηρίου. Ελέγχει πρώτα το συμβολικό ref του απομακρυσμένου HEAD, έπειτα το τοπικό HEAD και τέλος καταφεύγει στο `main` ή στο `master`.

#### `isBranchMerged`

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

Ελέγχει αν ένας κλάδος έχει συγχωνευθεί πλήρως σε άλλον κλάδο (από προεπιλογή, στον προεπιλεγμένο κλάδο).

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

#### `checkout`

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

Αλλάζει κλάδο ή αποσυνδέει το HEAD. Ενημερώνει τα HEAD, index και working tree. Το `$target` είναι όνομα κλάδου, ετικέτα, πλήρες hash ή έκφραση αναθεώρησης· οτιδήποτε δεν είναι κλάδος αποσυνδέει το HEAD.

Προκαλεί `RuntimeException` όταν μια τοπική αλλαγή (σε στάδιο ή όχι) ή ένα αρχείο που δεν παρακολουθείται βρίσκεται σε διαδρομή που διαφέρει ανάμεσα στο τρέχον και το στοχευόμενο δέντρο.

Οι μη υποβληθείσες αλλαγές σε άλλα αρχεία που παρακολουθούνται δεν διατηρούνται: το index και το working tree αναδημιουργούνται από το δέντρο-στόχο, επομένως οι επεξεργασίες σε αρχεία που είναι ίδια και στις δύο πλευρές χάνονται, ενώ το git θα τις διατηρούσε ([#2](https://github.com/inline0/pitmaster/issues/2)). Κάντε πρώτα commit ή stash τις αλλαγές. Τα `merge()`, `cherryPick()`, `revert()`, `rebase()` και οι μέθοδοι bisect αναδημιουργούν το working tree με τον ίδιο τρόπο.

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

---

### Ευρετήριο

#### `index`

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

Διαβάζει και επιστρέφει το τρέχον index (περιοχή σταδιοποίησης) από το `.git/index`.

#### `add`

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

Σταδιοποιεί αρχεία. Διαβάζει κάθε αρχείο από το working tree, δημιουργεί ένα αντικείμενο blob και ενημερώνει το index. Κάθε όρισμα πρέπει να είναι διαδρομή αρχείου (ή συμβολικού συνδέσμου) σχετική με τη ρίζα του working tree· οι κατάλογοι και τα glob δεν επεκτείνονται, ενώ αν λείπει κάποιο αρχείο προκαλείται `RuntimeException`.

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

#### `remove`

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

Αφαιρεί διαδρομές που παρακολουθούνται τόσο από το index όσο και από το working tree. Υποστηρίζει τα `--cached` και `-r` / `--recursive` στη λίστα ορισμάτων για συμπεριφορά τύπου Git.

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

Μετακινεί/μετονομάζει ένα αρχείο τόσο στο working tree όσο και στο index.

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

---

### Υποβολές αλλαγών

#### `commit`

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

Δημιουργεί ένα commit από το τρέχον index. Δημιουργεί μια ιεραρχία δέντρων από τις εγγραφές του index, δημιουργεί το αντικείμενο commit με γονέα το HEAD (αν υπάρχει) και ενημερώνει το HEAD. Επιστρέφει το `ObjectId` του νέου commit.

Το `$message` μπορεί να είναι `null` μόνο όταν μια συγχώνευση, επιλογή commit, αναίρεση ή αναδιάταξη έχει σταματήσει λόγω διένεξης· τότε χρησιμοποιείται το προετοιμασμένο μήνυμα. Διαφορετικά, ένα μήνυμα `null` προκαλεί `RuntimeException('Commit message required')`. Το commit προκαλεί επίσης σφάλμα όταν το index περιέχει μη συγχωνευμένες διαδρομές, όταν το index είναι κενό σε αποθετήριο χωρίς commits και όταν το δέντρο δεν έχει αλλάξει από το HEAD.

Η παράμετρος `$author` είναι μια πλήρης συμβολοσειρά συντάκτη git (`Name <email> timestamp timezone`). Αν είναι null, επιλύεται από μεταβλητές περιβάλλοντος, σταθερές και το `.git/config`, με τη σειρά που περιγράφεται στην ενότητα [Έναρξη](https://pitmaster.inline0.dev/el/docs/getting-started).

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

#### `show`

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

Εμφανίζει ένα commit-ish και τις διαφορές του από τον πρώτο γονέα. Όταν η αναθεώρηση επιλύεται σε σχολιασμένη ετικέτα, η τιμή επιστροφής περιλαμβάνει επίσης το `['tag' => Tag]` και το `commit` είναι το commit-στόχος μετά την αποσυσκευασία της ετικέτας.

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

Επαναφέρει το HEAD σε ένα commit. Λειτουργίες:
- `'soft'`: μετακινεί μόνο το HEAD
- `'mixed'`: μετακινεί το HEAD και επαναφέρει το index (προεπιλογή)
- `'hard'`: μετακινεί το HEAD, επαναφέρει το index και επαναφέρει το working tree

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

Επαναφέρει μια διαδρομή από το index ή από συγκεκριμένη αναθεώρηση πηγής. Αν δεν έχει οριστεί καμία από τις δύο σημαίες, το Pitmaster επαναφέρει το worktree από το index (ή από το `$source`, αν δοθεί). Το `staged: true` επαναφέρει το index από το HEAD (ή από το `$source`) και αφήνει το worktree ανέπαφο· περάστε το `staged: true, worktree: true` για να επαναφέρετε και τα δύο.

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

Εφαρμόζει ένα commit ως νέο commit στον τρέχοντα κλάδο, διατηρώντας τον αρχικό συντάκτη. Αν η λειτουργία σταματήσει λόγω διενέξεων, επιλύστε τις, σταδιοποιήστε τις διαδρομές και έπειτα καλέστε το `cherryPickContinue()` ή το `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
```

Δημιουργεί ένα commit που αναιρεί άλλο commit. Αν η αναίρεση σταματήσει λόγω διενέξεων, επιλύστε τις, σταδιοποιήστε τις διαδρομές και έπειτα καλέστε το `revertContinue()` ή το `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
```

Αναδιατάσσει τον τρέχοντα κλάδο πάνω σε άλλη αναθεώρηση. Το Pitmaster καλύπτει προς το παρόν γραμμικές αναδιατάξεις με κατάσταση διακοπής τύπου Git για διενέξεις, καθώς και συνέχιση, ακύρωση και παράλειψη. Το HEAD πρέπει να δείχνει σε κλάδο.

Τα `rebase()`, `rebaseContinue()` και `rebaseSkip()` επιστρέφουν `['success' => bool, 'commits' => int, 'conflicts' => list<string>]`: αν ολοκληρώθηκε η αναδιάταξη, πόσα commits εφαρμόστηκαν και ποιες διαδρομές είχαν διενέξεις όταν σταμάτησε.

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

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

---

### Κατάσταση

#### `status`

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

Υπολογίζει την κατάσταση του working tree. Επιστρέφει έναν πίνακα από αντικείμενα `StatusEntry`, καθένα από τα οποία περιέχει:
- `path`: τη διαδρομή αρχείου
- `index`: enum `FileStatus` για αλλαγές από HEAD προς index
- `worktree`: enum `FileStatus` για αλλαγές από index προς worktree
- `origPath`, `renameScore`: ορίζονται για μετονομασμένες εγγραφές, διαφορετικά `null`

Τα αρχεία που δεν παρακολουθούνται έχουν `FileStatus::Untracked` και στις δύο στήλες. Τα αρχεία που αγνοούνται δεν αναφέρονται.

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

#### `statusPorcelainV2`

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

Έξοδος κατάστασης σε μορφή αναγνώσιμη από μηχανές, σύμφωνα με τη μορφή porcelain v2 του git.

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

---

### Διαφορές

#### `diff`

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

Συγκρίνει το working tree με το index (αλλαγές που δεν έχουν σταδιοποιηθεί). Επιστρέφει έναν πίνακα από αντικείμενα `DiffResult`. Το `$pathspec` φιλτράρει βάσει μίας ακριβούς διαδρομής αρχείου. Το `$algorithm` είναι `'myers'` (προεπιλογή), `'patience'`, `'histogram'` ή `'minimal'`· οποιαδήποτε άλλη τιμή προκαλεί `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
```

Συγκρίνει το index με το HEAD (σταδιοποιημένες αλλαγές). Επιστρέφει `DiffResult[]`, με εντοπισμό μετονομασιών μεταξύ διαγραμμένων και προστεθειμένων αρχείων.

Το όρισμα `$pathspec` αγνοείται προς το παρόν, επομένως επιστρέφεται κάθε σταδιοποιημένο αρχείο, ενώ η μέθοδος επιστρέφει κενό πίνακα πριν από το πρώτο commit ([#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
```

Συγκρίνει δύο δέντρα με βάση το `ObjectId` τους. Επιστρέφει `DiffResult[]`. Περάστε αναγνωριστικά δέντρων, όχι αναγνωριστικά commit: ένα αναγνωριστικό commit δεν διαβάζεται ως δέντρο και έχει ως αποτέλεσμα κενό.

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

---

### Αρχείο καταγραφής

#### `log`

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

Διατρέχει το ιστορικό commit, με πρώτο το νεότερο βάσει της χρονοσφραγίδας του συντάκτη. Επιστρέφει `Commit[]`. Αν το `$from` είναι null, ξεκινά από το HEAD. Επιστρέφει κενό πίνακα αν το HEAD δεν έχει ακόμη commit.

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

#### `logAll`

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

Διατρέχει τα commit που είναι προσβάσιμα από κάθε ref και το HEAD, με πρώτο το νεότερο. Επιστρέφει `Commit[]`.

#### `logOneline`

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

Επιστρέφει γραμμές αρχείου καταγραφής σε μορφή `git log --oneline` (`abc1234 Subject`), από το HEAD, από όλα τα refs (`$all`) ή φιλτραρισμένες βάσει διαδρομής.

#### `logPath`

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

Φιλτράρει το αρχείο καταγραφής με βάση διαδρομή αρχείου. Επιστρέφει μόνο commit των οποίων η διαφορά από τον πρώτο γονέα προσθέτει, τροποποιεί, διαγράφει ή μετονομάζει το συγκεκριμένο αρχείο. Οι διαδρομές καταλόγων δεν αντιστοιχίζονται.

Εξετάζονται μόνο τα νεότερα `5 * $limit` commit, επομένως παλαιότερα commit που επηρεάζουν το αρχείο μπορεί να λείπουν από το αποτέλεσμα ([#7](https://github.com/inline0/pitmaster/issues/7)).

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

---

### Συγχώνευση

#### `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
```

Συγχωνεύει έναν κλάδο (ή οποιαδήποτε αναθεώρηση) στο HEAD. Εντοπίζει αυτόματα τις συγχωνεύσεις fast-forward. Για συγχωνεύσεις που δεν είναι fast-forward, εκτελεί εντοπισμό διενέξεων σε επίπεδο δέντρου και δημιουργεί commit συγχώνευσης αν δεν υπάρχουν διενέξεις. Αν προκύψουν διενέξεις, η διαδικασία σταματά και γράφει την κατάσταση συγχώνευσης τύπου Git στο index και στο worktree· επιλύστε τις διαδρομές, σταδιοποιήστε τις και έπειτα καλέστε το `mergeContinue()` ή το `mergeAbort()`.

Το `$strategy` `'ours'` καταγράφει ένα commit συγχώνευσης που διατηρεί το δέντρο του HEAD· οποιαδήποτε άλλη τιμή χρησιμοποιεί την προεπιλεγμένη αναδρομική συγχώνευση. Το `mergeOctopus()` συγχωνεύει δύο ή περισσότερους κλάδους σε ένα commit. Αν οποιοσδήποτε κλάδος έχει διενέξεις, επιστρέφει αποτέλεσμα με διενέξεις, χωρίς να γράψει κατάσταση συγχώνευσης ή να δημιουργήσει commit.

Η συγχώνευση ενός κλάδου που περιλαμβάνεται ήδη στο HEAD δημιουργεί άλλο ένα commit συγχώνευσης αντί να εμφανίσει «Already up to date» ([#6](https://github.com/inline0/pitmaster/issues/6)). Οι μη δεσμευμένες αλλαγές σε παρακολουθούμενα αρχεία αντικαθίστανται, όπως περιγράφεται στην ενότητα `checkout()`.

Επιστρέφει ένα `MergeResult` με:
- `clean`: αν η συγχώνευση ολοκληρώθηκε χωρίς διενέξεις
- `commitId`: το ID του commit συγχώνευσης (αν ολοκληρώθηκε καθαρά)
- `conflictPaths`: πίνακα διαδρομών αρχείων με διενέξεις (αν δεν ολοκληρώθηκε καθαρά)
- `mergedContents`: αντιστοίχιση διαδρομής με το περιεχόμενο του αρχείου που περιέχει δείκτες διένεξης (αν δεν ολοκληρώθηκε καθαρά)

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

Εντοπίζει τη βάση συγχώνευσης (τον χαμηλότερο κοινό πρόγονο) δύο commit. Επιστρέφει null αν δεν υπάρχει κοινός πρόγονος.

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

### Δυαδική αναζήτηση

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

Εκτελεί δυαδική αναζήτηση για το commit που εισήγαγε μια αλλαγή. Το `bisectStart()` καταγράφει τις κακές και καλές αναθεωρήσεις, κάνει checkout του πρώτου υποψηφίου και τον επιστρέφει. Τα `bisectGood()` και `bisectBad()` ορίζουν το τρέχον HEAD (ή το `$revision`) και κάνουν checkout του επόμενου υποψηφίου, τον οποίο και επιστρέφουν. Όταν απομείνει ένας μόνο ύποπτος, επιστρέφεται αυτό το commit και παραμένει ο υποψήφιος: είναι το πρώτο κακό commit. Το `bisectReset()` τερματίζει τη συνεδρία και επιστρέφει στον κλάδο ή στο commit από όπου ξεκίνησε.

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

---

### Δίκτυο

#### `fetch`

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

Κάνει λήψη από απομακρυσμένο αποθετήριο. Κατεβάζει νέα αντικείμενα και ενημερώνει τις αναφορές παρακολούθησης απομακρυσμένων κλάδων. Περάστε το `$depth` για να επεκτείνετε ή να περιορίσετε το ρηχό ιστορικό.

Οι μέθοδοι `fetch()` και `push*()` προκαλούν `RuntimeException` σε handle που ανοίχτηκε με `['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
```

Στέλνει τον τρέχοντα κλάδο (ή έναν καθορισμένο κλάδο) σε απομακρυσμένο αποθετήριο. Διατίθενται οι παραλλαγές force-with-lease, atomic και mirror για αυστηρότερες ή ευρύτερες ενημερώσεις αναφορών.

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

---

### Δέντρα εργασίας

#### `addWorktree`

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

Προσθέτει ένα συνδεδεμένο worktree. Δημιουργεί τον κλάδο αν δεν υπάρχει, ρυθμίζει τα μεταδεδομένα του worktree και δημιουργεί τα αρχεία του δέντρου εργασίας. Περάστε το `$name` όταν χρειάζεστε ένα ντετερμινιστικό slug μεταδεδομένων διαφορετικό από το βασικό όνομα του καταλόγου checkout.

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

Αφαιρεί ένα συνδεδεμένο worktree. Χρησιμοποιήστε το `$force = true` για αφαίρεση ακόμη κι αν είναι κλειδωμένο.

#### `worktrees`

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

Εμφανίζει όλα τα worktree (κύριο και συνδεδεμένα). Επιστρέφει `Worktree[]`.

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

---

### Ρυθμίσεις

#### `config`

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

Πρόσβαση στη διαμόρφωση git του αποθετηρίου. Ανάγνωση και εγγραφή τιμών διαμόρφωσης.

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

---

### Εσωτερική πρόσβαση

Αυτές οι μέθοδοι παρέχουν πρόσβαση σε εσωτερικά στοιχεία για προχωρημένες περιπτώσεις χρήσης.

#### `objectDatabase`

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

Πρόσβαση στην ακατέργαστη βάση δεδομένων αντικειμένων (χαλαρές και pack αποθήκες).

#### `refDatabase`

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

Πρόσβαση στην ακατέργαστη βάση δεδομένων αναφορών (χαλαρές και συσκευασμένες αναφορές).

---

## Κλάσεις χαμηλότερου επιπέδου

Αυτές οι κλάσεις δεν περιβάλλονται από το `Repository` και δημιουργούνται από τα εσωτερικά στοιχεία του.

### `Pitmaster\Graph\Blame`

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

Επιστρέφει μία εγγραφή ανά γραμμή του `$path` στο `$headId`: `['line' => int, 'hash' => string, 'author' => string, 'content' => string]`. Το `author` είναι η πλήρης συμβολοσειρά ταυτότητας (`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
```

Αναζητά στα blobs ενός δέντρου. Επιστρέφει `['path' => string, 'line' => int, 'content' => string]` ανά γραμμή που ταιριάζει. Επιλογές: `regex` (αντιμετωπίζει το μοτίβο ως μοτίβο PCRE) και `ignore_case`. Μη έγκυρη κανονική έκφραση προκαλεί `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
```

Διαβάζει και γράφει σημειώσεις git αποθηκευμένες σε αναφορά σημειώσεων. Το `listAll()` επιστρέφει αντιστοίχιση από κατακερματισμό commit σε περιεχόμενο σημείωσης.

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