
# PHP API

## `Pitmaster\Pitmaster`

فئة `Pitmaster\Pitmaster` هي نقطة الدخول الثابتة. وتوفر طرقًا لإنشاء كائنات لفتح المستودعات وإنشائها واستنساخها، إلى جانب أدوات مساعدة لاكتشافها.

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

### `open`

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

افتح مستودعًا موجودًا في `$path`. ينبغي أن يكون المسار جذر شجرة العمل (الذي يحتوي على `.git/`). كما يدعم أشجار العمل المرتبطة (حيث يكون `.git` ملفًا يحتوي على `gitdir: <path>`) والمستودعات المجردة (حيث يكون `$path` هو دليل `.git` نفسه).

يقبل `$options` قيمتين منطقيتين، وتكون كلتاهما `true` افتراضيًا:

- `hooks`: تشغيل نصوص `.git/hooks`. مرّر `false` لتخطيها لهذا المقبض.
- `processes`: السماح بكل ما يبدأ عملية أو يفتح نقلًا عبر الشبكة. مرّر `false` لتعطيل الخطافات وخطاف fsmonitor والاستنساخ والجلب والدفع ونقل عمليات 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
```

استنساخ مستودع بعيد. يهيئ مستودعًا جديدًا، ويكتشف المراجع البعيدة، ويجلب ملف الحزمة، ويعد فروع تتبع البعيد، وينشئ شجرة العمل. تستخدم عناوين SSH (`ssh://...` أو `user@host:path`) نقل SSH؛ أما العناوين الأخرى فتستخدم HTTP الذكي، وتعود إلى HTTP غير الذكي عند فشل التبادل الذكي. مرّر `$depth` لإجراء استنساخ سطحي.

يطرح `RuntimeException` عندما يكون `$options['processes']` هو `false`. إذا فشل الاستنساخ ولم يكن `$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/`)، وأشجار العمل المرتبطة (ملف `.git`)، والمستودعات العارية (عند وجود ملف `HEAD`).

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

### `isWorktree`

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

تحقّق مما إذا كان المسار شجرة عمل مرتبطة (وليست المستودع الرئيسي). يعيد `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 المشترك انطلاقًا من أي مسار تسجيل خروج. في المستودعات العادية، يكون هذا هو مجلد `.git`. وفي أشجار العمل المرتبطة، يكون مجلد git المشترك الذي يحتوي على الكائنات والإعدادات وpacked-refs. يعيد `null` إذا لم يكن المسار مستودعًا.

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

---

## `Pitmaster\Repository`

الفئة `Pitmaster\Repository` هي المقبض الرئيسي لجميع عمليات git. احصل على نسخة منها عبر `Pitmaster::open()` أو `Pitmaster::init()` أو `Pitmaster::clone()`.

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

### موفّرات المسارات

#### `gitDir`

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

يعيد مجلد git الخاص بشجرة العمل. في المستودعات العادية يكون `.git/`. أما في أشجار العمل المرتبطة فهو `.git/worktrees/<name>/`.

#### `commonGitDir`

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

يعيد مجلد git المشترك. وهو نفسه `gitDir()` في المستودعات العادية. أما في أشجار العمل المرتبطة فهو مجلد `.git/` للمستودع الرئيسي (حيث توجد الكائنات والإعدادات وpacked-refs).

#### `workDir`

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

يعيد مسار جذر شجرة العمل.

#### `isLinkedWorktree`

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

يعيد `true` إذا كان مقبض هذا المستودع لشجرة عمل مرتبطة.

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

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

يوضح ما إذا كان المستودع بلا شجرة عمل، وأيٌّ من الخيارين `hooks` / `processes` ساري على هذا المقبض. تكون `hooksEnabled()` هي `false` دائمًا عند تعطيل العمليات.

---

### الكائنات

#### `readObject`

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

اقرأ أي كائن باستخدام تجزئته السداسية الكاملة (40 حرفًا، أو 64 في مستودع SHA-256). لا تُقبل التجزئات المختصرة. يعيد نسخة من `Blob` أو `Tree` أو `Commit` أو `Tag`. يبحث أولًا في الكائنات المنفصلة، ثم في ملفات الحزم.

يطرح `ObjectNotFoundException` إذا لم يُعثر على التجزئة.

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

#### `writeObject`

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

اكتب كائنًا في مخزن الكائنات المنفصلة. يعيد `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
```

تحقّق مما إذا كان الكائن موجودًا في المستودع (منفصلًا أو ضمن حزمة).

#### `listObjects`

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

أدرج كل تجزئات الكائنات في المستودع. يعيد مصفوفة من السلاسل السداسية.

---

### المراجع

#### `head`

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

يعيد إيداع HEAD الحالي. ويتبع المراجع الرمزية (HEAD -> refs/heads/main -> تجزئة الإيداع).

يطرح `RuntimeException` إذا لم يكن HEAD يشير إلى إيداع صالح (e.g، مستودع فارغ).

#### `branch`

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

من دون وسيطات، يعيد اسم الفرع الحالي (e.g، `'main'`)، أو `null` إذا كان HEAD منفصلًا.

عند تمرير اسم فرع، يحلّه إلى تجزئة إيداعه (سلسلة سداسية) أو يعيد `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`. يدعم ما يلي:
- التجزئات السداسية الكاملة (40 حرفًا، أو 64 في SHA-256). لا تُحل التجزئات المختصرة مثل `abc1234`.
- `HEAD`
- أسماء الفروع (`main`، `feature/login`)
- أسماء الوسوم (`v1.0.0`)
- مسارات المراجع الكاملة (`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
```

يعيد جميع المراجع في مصفوفة ترابطية تربط اسم المرجع بتجزئته السداسية.

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

#### `updateRef`

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

حدّث مرجعًا ليشير إلى هدف جديد.

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

#### `createBranch`

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

أنشئ فرعًا جديدًا. إذا كانت `$from` خالية، يُنشأ الفرع انطلاقًا من HEAD الحالي.

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

#### `deleteBranch`

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

احذف فرعًا بالاسم. يطرح `RuntimeException` إذا كان الفرع قيد تسجيل الخروج أو غير موجود. بخلاف `git branch -d`، لا يتحقق مما إذا كان الفرع قد دُمج.

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

#### `createLightweightTag`

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

أنشئ وسمًا خفيفًا. إذا كانت `$target` خالية، يضع الوسم مباشرة على 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` خالية، يضع الوسم على 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` المشترك انطلاقًا من مجموعة المراجع المنفصلة الحالية، واحذف المراجع المنفصلة المشتركة المقابلة. في أشجار العمل المرتبطة، يكتب ذلك في مجلد git المشترك.

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

#### `defaultBranch`

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

حلّ الفرع الافتراضي للمستودع. يتحقق أولًا من مرجع 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 والفهرس وشجرة العمل. تكون `$target` اسم فرع أو وسمًا أو تجزئة كاملة أو تعبير مراجعة؛ وأي قيمة ليست فرعًا تفصل HEAD.

يطرح `RuntimeException` إذا وُجد تغيير محلي (مُدرج في الفهرس أو غير مُدرج) أو ملف غير متتبع في مسار يختلف بين الشجرة الحالية والشجرة المستهدفة.

لا تُنقل التغييرات غير المودعة في الملفات الأخرى المتتبعة: يُعاد إنشاء الفهرس وشجرة العمل من الشجرة المستهدفة، لذا تُفقد التعديلات على الملفات المتطابقة في الجانبين، بينما يحتفظ بها git ([#2](https://github.com/inline0/pitmaster/issues/2)). أودعها أو خزّنها مؤقتًا أولًا. تعيد `merge()` و`cherryPick()` و`revert()` و`rebase()` وطرق bisect إنشاء شجرة العمل بالطريقة نفسها.

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

---

### الفهرس

#### `index`

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

اقرأ الفهرس الحالي (منطقة التجهيز) من `.git/index` وأعده.

#### `add`

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

أدرج الملفات في الفهرس. يقرأ كل ملف من شجرة العمل، وينشئ كائن blob، ويحدّث الفهرس. يجب أن تكون كل وسيطة مسار ملف (أو رابط رمزي) نسبةً إلى جذر شجرة العمل؛ لا تُوسّع المجلدات وأنماط 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
```

أزل المسارات المتتبعة من الفهرس وشجرة العمل معًا. يدعم `--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
```

انقل ملفًا أو أعد تسميته في شجرة العمل والفهرس معًا.

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

---

### الإيداعات

#### `commit`

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

أنشئ إيداعًا من الفهرس الحالي. ينشئ تسلسلًا هرميًا للشجرة من مدخلات الفهرس، وينشئ كائن الإيداع مع HEAD كأصل (إن وُجد)، ويحدّث HEAD. يعيد `ObjectId` للإيداع الجديد.

لا يجوز أن تكون `$message` هي `null` إلا عند توقف دمج أو انتقاء إيداع أو تراجع أو إعادة تأسيس بسبب تعارض؛ عندها تُستخدم الرسالة المُعدّة. وإلا فإن رسالة `null` تؤدي إلى طرح `RuntimeException('Commit message required')`. ويُطرح أيضًا إذا احتوى الفهرس على مسارات لم تُحل تعارضاتها، أو كان فارغًا في مستودع بلا إيداعات، أو لم تتغير الشجرة عن HEAD.

المعامل `$author` عبارة كاملة عن مؤلف git (`Name <email> timestamp timezone`). إذا كان خاليًا، يُحدّد من متغيرات البيئة والثوابت و`.git/config`، وفق الترتيب الموضح في [البدء](https://pitmaster.inline0.dev/ar/docs/getting-started).

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

#### `show`

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

اعرض إيداعًا أو ما يشبهه والفروق بينه وبين الأصل الأول. عندما تُحل المراجعة إلى وسم مشروح، تتضمن القيمة المعادة أيضًا `['tag' => Tag]`، ويكون `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 إلى إيداع. الأوضاع:
- `'soft'`: نقل HEAD فقط
- `'mixed'`: نقل HEAD وإعادة تعيين الفهرس (افتراضيًا)
- `'hard'`: نقل HEAD وإعادة تعيين الفهرس وشجرة العمل

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

استعد مسارًا من الفهرس أو من مراجعة مصدر محددة. إذا لم يُضبط أي من العلمين، يستعيد Pitmaster شجرة العمل من الفهرس (أو من `$source` عند تمريره). أما `staged: true` فيستعيد الفهرس من HEAD (أو `$source`) ويترك شجرة العمل كما هي؛ مرّر `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
```

طبّق إيداعًا كإيداع جديد على الفرع الحالي مع الحفاظ على المؤلف الأصلي. إذا أوقف التعارض العملية، فحلّه وأدرج المسارات في الفهرس، ثم استدعِ `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
```

أنشئ إيداعًا يلغي إيداعًا آخر. إذا أوقف التعارض التراجع، فحلّه وأدرج المسارات في الفهرس، ثم استدعِ `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>]`: ما إذا كانت إعادة التأسيس قد اكتملت، وعدد الإيداعات المطبّقة، والمسارات المتعارضة عند التوقف.

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

احسب حالة شجرة العمل. يعيد مصفوفة من كائنات `StatusEntry`، يحتوي كل منها على:
- `path`: مسار الملف
- `index`: تعداد `FileStatus` للتغييرات بين HEAD والفهرس
- `worktree`: تعداد `FileStatus` للتغييرات بين الفهرس وشجرة العمل
- `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
```

اعرض الفرق بين شجرة العمل والفهرس (التغييرات غير المدرجة). يعيد مصفوفة من كائنات `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
```

اعرض الفرق بين الفهرس وHEAD (التغييرات المدرجة). يعيد `DiffResult[]` مع اكتشاف إعادة التسمية بين الملفات المحذوفة والمضافة.

يُتجاهل حاليًا المعامل `$pathspec`، لذا تُعاد جميع الملفات المدرجة، وتعيد الطريقة مصفوفة فارغة قبل الإيداع الأول ([#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[]`. مرّر معرّفات الشجرة، لا معرّفات الإيداع: لا يُقرأ معرّف الإيداع على أنه شجرة وينتج عنه نتيجة فارغة.

```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[]`. إذا كانت `$from` خالية، يبدأ من HEAD. يعيد مصفوفة فارغة إذا لم يكن لـ HEAD إيداع بعد.

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

#### `logAll`

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

استعرض الإيداعات التي يمكن الوصول إليها من كل مرجع ومن HEAD، من الأحدث أولًا. يعيد `Commit[]`.

#### `logOneline`

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

أعد أسطر السجل بصيغة `git log --oneline` (`abc1234 Subject`)، انطلاقًا من HEAD أو من جميع المراجع (`$all`)، أو مع ترشيحها حسب المسار.

#### `logPath`

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

سجل مرشّح حسب مسار ملف. يعيد الإيداعات التي يضيف فرقها عن الأصل الأول ذلك الملف المحدد أو يعدّله أو يحذفه أو يعيد تسميته فقط. لا تطابق مسارات المجلدات.

يُفحص أحدث `5 * $limit` إيداع فقط، لذا قد لا تظهر في النتيجة الإيداعات الأقدم التي تمس الملف ([#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. يكتشف عمليات الدمج بالتقديم السريع تلقائيًا. أما عمليات الدمج التي لا تتم بالتقديم السريع، فتتحقق من التعارضات على مستوى الشجرة وتنشئ إيداع دمج عند خلوّها من التعارض. عند حدوث تعارض، تحفظ حالة دمج متوافقة مع Git في الفهرس وشجرة العمل؛ حلّ المسارات وأدرجها في الفهرس، ثم استدعِ `mergeContinue()` أو `mergeAbort()`.

يسجل `$strategy` `'ours'` إيداع دمج يحتفظ بشجرة HEAD؛ وأي قيمة أخرى تستخدم الدمج التكراري الافتراضي. يدمج `mergeOctopus()` فرعين أو أكثر في إيداع واحد. إذا تعارض أي فرع، يعيد نتيجة غير نظيفة من دون كتابة حالة الدمج أو إنشاء إيداع.

يؤدي دمج فرع موجود بالفعل ضمن HEAD إلى إنشاء إيداع دمج آخر بدلًا من الإبلاغ عن «محدّث بالفعل» ([#6](https://github.com/inline0/pitmaster/issues/6)). وتُستبدل التغييرات غير المودعة في الملفات المتتبعة كما هو موضح ضمن `checkout()`.

يعيد `MergeResult` مع:
- `clean`: ما إذا نجح الدمج من دون تعارضات
- `commitId`: معرّف إيداع الدمج (إذا كان الدمج نظيفًا)
- `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
```

اعثر على أساس الدمج (أدنى سلف مشترك) لإيداعين. يعيد 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
```

ابحث ثنائيًا عن الإيداع الذي أدخل تغييرًا. يسجل `bisectStart()` المراجعتين السيئة والجيدة، ويسجل خروج المرشح الأول ويعيده. يحدد `bisectGood()` و`bisectBad()` HEAD الحالي (أو `$revision`)، ويسجلان خروج المرشح التالي ويعيدانه. عند بقاء مشتبه به واحد، يُعاد ذلك الإيداع ويبقى مرشحًا؛ فهو أول إيداع سيئ. ينهي `bisectReset()` الجلسة ويعيدك إلى الفرع أو الإيداع الذي بدأت منه.

```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` لزيادة عمق السجل السطحي أو تحديده.

يطرح `RuntimeException` كل من `fetch()` وطرق `push*()` عند استخدام مقبض مفتوح مع `['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
```

ادفع الفرع الحالي (أو فرعًا محددًا) إلى مستودع بعيد. تتوفر خيارات القوة مع lease والذرية والنسخ المتطابق لتحديث المراجع بنطاق أوسع أو بقيود أشد.

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

أضف شجرة عمل مرتبطة. ينشئ الفرع إن لم يكن موجودًا، ويعدّ بيانات الشجرة الوصفية، وينشئ ملفات شجرة العمل. مرّر `$name` عند الحاجة إلى معرّف بيانات وصفية ثابت يختلف عن اسم المجلد الأساسي لتسجيل الخروج.

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

أزل شجرة عمل مرتبطة. استخدم `$force = true` لإزالتها حتى إن كانت مقفلة.

#### `worktrees`

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

أدرج جميع أشجار العمل (الرئيسية والمرتبطة). يعيد `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
```

الوصول إلى قاعدة بيانات الكائنات الخام (المخازن المنفصلة ومخازن الحزم).

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

يبحث في كتل شجرة. يعيد `['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()` تجزئة الإيداع مقابل محتوى الملاحظة.

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