
# قراءة المستودعات

تقرأ Pitmaster مستودعات git بتحليل التنسيقات الموجودة على القرص مباشرةً: الكائنات المنفصلة (ملفات مضغوطة بـ zlib في `.git/objects/`)، وملفات الحزم (`.git/objects/pack/`)، والمراجع (ملفات في `.git/refs/` و`packed-refs`)، والفهرس (`.git/index`).

## فتح مستودع

```php
use Pitmaster\Pitmaster;

$repo = Pitmaster::open('/path/to/project');
```

تدعم Pitmaster ثلاثة تنسيقات للمستودعات:

1. **المستودعات العادية**: يكون `.git` مجلدًا في جذر المشروع.
2. **أشجار العمل المرتبطة**: يكون `.git` ملفًا يحتوي على `gitdir: <path>` يشير إلى `.git/worktrees/<name>/`.
3. **المستودعات العارية**: يحتوي المسار نفسه على `HEAD` و`objects/` وغيرهما.

```php
// Detection helpers
Pitmaster::isRepository('/path');  // true for any of the above
Pitmaster::isWorktree('/path');    // true only for linked worktrees
```

## قراءة الكائنات

تُخزّن كل قطعة بيانات في مستودع git ككائن يُعرّف بتجزئته: SHA-1 (40 محرفًا سداسيًا عشريًا) افتراضيًا، أو SHA-256 (64 محرفًا سداسيًا عشريًا) في المستودعات المنشأة باستخدام `Pitmaster::init($path, 'sha256')`. هناك أربعة أنواع من الكائنات: blob وtree وcommit وtag.

تتطلب الطرق التالية المعتمدة على التجزئة التجزئة السداسية العشرية كاملة؛ ولا تُقبل التجزئات المختصرة.

### readObject

```php
use Pitmaster\Object\Blob;
use Pitmaster\Object\Tree;
use Pitmaster\Object\Commit;
use Pitmaster\Object\Tag;

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

match (true) {
    $object instanceof Blob   => handleBlob($object),
    $object instanceof Tree   => handleTree($object),
    $object instanceof Commit => handleCommit($object),
    $object instanceof Tag    => handleTag($object),
};
```

يُبحث عن الكائنات أولًا في التخزين المنفصل، ثم في ملفات الحزم. تستخدم عمليات البحث في ملفات الحزم جدول التوزيع `.idx` لإجراء بحث ثنائي عن O(log n).

### catFile

لاسترجاع المحتوى ببساطة دون التحقق من النوع:

```php
$content = $repo->catFile('a1b2c3d4e5f6...');
echo $content;
```

### objectExists

```php
if ($repo->objectExists('a1b2c3d4e5f6...')) {
    // Object is in the repository
}
```

### listObjects

```php
$hashes = $repo->listObjects();
// ['a1b2c3d4...', 'f6e5d4c3...', ...]
```

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

## العمل مع blobs

يحتوي blob على محتوى الملف الخام.

```php
$blob = $repo->readObject($hash);
echo $blob->content;     // Raw file bytes
echo $blob->size();      // Content length
echo $blob->id->hex;     // Object hash
```

## العمل مع الأشجار

الشجرة هي قائمة بمحتويات مجلد. يتضمن كل مدخل نمطًا واسمًا وتجزئة.

```php
$tree = $repo->readObject($hash);

foreach ($tree->entries as $entry) {
    echo "{$entry->mode} {$entry->name} {$entry->hash->hex}\n";
    // 100644 README.md abc123...
    // 40000 src def456...
    // 100755 deploy.sh 789012...

    if ($entry->isTree()) {
        // Recurse into subdirectory (mode 40000)
    } elseif ($entry->isExecutable()) {
        // Executable file (mode 100755)
    } elseif ($entry->isBlob()) {
        // Regular file (any 10xxxx mode, so executables match too)
    } elseif ($entry->isSymlink()) {
        // Symbolic link (mode 120000)
    } elseif ($entry->isGitlink()) {
        // Submodule (mode 160000)
    }
}
```

## العمل مع الالتزامات

يربط الالتزام لقطة شجرة بأسلافها وبياناتها الوصفية.

```php
$commit = $repo->head();

echo $commit->id->hex;      // Full object hash
echo $commit->tree->hex;    // Tree object hash
echo $commit->author;       // "Name <email> timestamp tz"
echo $commit->committer;    // "Name <email> timestamp tz"
echo $commit->message;      // Full commit message

// Parent commits
foreach ($commit->parents as $parentId) {
    $parent = $repo->readObject($parentId->hex);
}

// Merge detection
if ($commit->isMerge()) {
    // Two or more parents
}
```

## العمل مع العلامات

العلامات المشروحة كائنات تتضمن هدفًا ونوعًا واسمًا ومنشئ العلامة ورسالة.

```php
$tag = $repo->readObject($hash);

echo $tag->object->hex;           // Target object hash
echo $tag->objectType->value;     // 'commit', 'tree', 'blob', or 'tag'
echo $tag->name;            // Tag name
echo $tag->tagger;          // "Name <email> timestamp tz"
echo $tag->message;         // Tag message
```

## قراءة المراجع

### HEAD الحالي

```php
$commit = $repo->head();
```

تحلّ HEAD (باتباع المراجع الرمزية مثل `HEAD -> refs/heads/main -> commit hash`) وتعيد كائن الالتزام.

### الفرع الحالي

```php
$branch = $repo->branch();  // 'main' or null if detached
```

### سرد الفروع والعلامات

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

### كل المراجع

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

### حلّ المراجعات

```php
$id = $repo->resolve('HEAD');
$id = $repo->resolve('main');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('HEAD~3');
$id = $repo->resolve('main^2');
$id = $repo->resolve('3f2c1e0b9d6a4f8e7c5b2a1d0e9f8c7b6a5d4e3f');
```

يدعم محلل المراجعات معاملي `~N` (السلف) و`^N` (الأب)، ويمكن ربطهما بأي عدد. يجب إدخال التجزئات كاملة.

## التنقل عبر سجل الالتزامات

### السجل

تُعرض الالتزامات من الأحدث إلى الأقدم، بترتيب الطابع الزمني لمنفّذ الالتزام.

```php
// Last 20 commits from HEAD
$commits = $repo->log(20);

foreach ($commits as $commit) {
    $short = substr($commit->id->hex, 0, 7);
    echo "{$short} {$commit->message}\n";
}
```

### السجل بدءًا من التزام محدد

```php
$from = $repo->resolve('feature/login');
$commits = $repo->log(10, $from);
```

### السجل المصفّى حسب مسار الملف

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

يعرض الالتزامات التي تغيّر فيها الملف المحدد فقط (بالإضافة أو التعديل أو الحذف أو إعادة التسمية) مقارنةً بالأب الأول. يجب أن يكون المسار مسار ملف محددًا؛ ولا تطابق المجلدات. ولا تُفحص إلا أحدث `5 * $limit` التزامات، لذا قد لا تظهر نتائج أقدم ([#7](https://github.com/inline0/pitmaster/issues/7)).

### عرض

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

echo "Author: {$commit->author}\n";
echo "Message: {$commit->message}\n\n";

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

## اكتشاف الفرع الافتراضي

```php
$default = $repo->defaultBranch();
// Checks: remote HEAD symref -> local HEAD -> main/master fallback
```

عندما يكون `remote.origin.url` مضبوطًا وتكون العمليات مفعّلة، يجري الفحص الأول طلبًا ذكيًا من HTTP إلى الجهة البعيدة. يتم تجاهل أخطاء الشبكة، ثم تُجرى الفحوص المحلية.

## أسلاف الدمج

```php
// Is feature fully merged into main?
$merged = $repo->isBranchMerged('feature/done', 'main');

// Find the merge base of two commits
$base = $repo->mergeBase(
    $repo->resolve('main'),
    $repo->resolve('feature/login'),
);
```
