
# أشجار العمل

تتيح أشجار عمل Git مشاركة مستودع واحد بين أدلة عمل متعددة. ولكل شجرة عمل عملية سحب خاصة بها (HEAD والفهرس وملفات العمل)، بينما تشارك مخزن الكائنات والإعدادات وpacked-refs مع المستودع الرئيسي. يستطيع Pitmaster إنشاء أشجار العمل المرتبطة وسردها وقفلها وإزالتها، وفتحها كمستودعات. لم تُنفذ عمليات التنقية والنقل والإصلاح لأشجار العمل.

## المفاهيم

يحتوي مستودع git عادي على شجرة عمل واحدة:

```
project/
  .git/          (directory)
  src/
  README.md
```

باستخدام أشجار العمل، يمكنك إجراء عمليات سحب إضافية:

```
project/                          (main worktree)
  .git/                           (the actual git directory)
    worktrees/
      review/                     (metadata for linked worktree)
        HEAD
        commondir
        gitdir

/tmp/review/                      (linked worktree)
  .git                            (file, not directory)
  src/
  README.md
```

يكون `.git` لشجرة العمل المرتبطة ملفًا (لا دليلًا) يحتوي على مسار نسبي إلى شجرة العمل:
```
gitdir: ../../path/to/project/.git/worktrees/review
```

## إنشاء شجرة عمل

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

// Create a linked worktree on a new branch
$wt = $repo->addWorktree('/tmp/review', 'feature/review');

echo $wt->path;        // '/tmp/review'
echo $wt->branch;      // 'feature/review'
echo $wt->gitDir;      // '/path/to/project/.git/worktrees/review'
var_dump($wt->isMain);      // bool(false)
var_dump($wt->isDetached);  // bool(false)
```

ينفذ `addWorktree()` ما يلي:
1. ينشئ الفرع إن لم يكن موجودًا (من HEAD أو من الالتزام `$from` المحدد)
2. ينشئ دليل البيانات الوصفية في `.git/worktrees/<name>/`
3. يكتب ملف `.git` في دليل شجرة العمل
4. يكتب ملفات البيانات الوصفية `HEAD` و`commondir` و`gitdir`
5. يسحب شجرة الفرع إلى دليل شجرة العمل
6. يكتب فهرس شجرة العمل

إذا كان الفرع موجودًا بالفعل، يتم تجاهل `$from`. وعلى خلاف git، لا يرفض `addWorktree()` فرعًا تم سحبه بالفعل في شجرة عمل أخرى، ولا يشغّل الخطاف `post-checkout`.

### باستخدام اسم بيانات وصفية صريح

استخدم الوسيط الاختياري `name` عندما يمكن لأشجار العمل المرتبطة المتعددة مشاركة اسم أساس السحب نفسه.

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

يُستخدم اسم البيانات الوصفية هذا في `.git/worktrees/<name>/` بدلًا من `basename($path)`.

### من التزام محدد

```php
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));
```

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

```php
$worktrees = $repo->worktrees();

foreach ($worktrees as $wt) {
    $type = $wt->isMain ? 'main' : 'linked';
    $branch = $wt->branch ?? 'detached';
    $locked = $wt->isLocked ? ' [locked]' : '';

    echo "{$wt->path} ({$type}) [{$branch}]{$locked}\n";
}
```

تتضمن القائمة دائمًا شجرة العمل الرئيسية أولًا، تليها أشجار العمل المرتبطة. استدعِ `worktrees()` على مقبض المستودع الرئيسي؛ إذ يُظهر الإدخال الرئيسي حاليًا مسار شجرة العمل المرتبطة نفسها عند استخدام مقبض لشجرة عمل مرتبطة ([#14](https://github.com/inline0/pitmaster/issues/14)).

## إزالة شجرة عمل

```php
$repo->removeWorktree('review');          // by metadata name
$repo->removeWorktree('/tmp/review');     // or by worktree path

// Force remove (even if locked)
$repo->removeWorktree('review', force: true);
```

تتضمن إزالة شجرة عمل ما يلي:
1. التحقق مما إذا كانت شجرة العمل مقفلة (تفشل العملية ما لم تكن `$force` true)
2. إزالة الملف `.git` من دليل شجرة العمل
3. إزالة دليل البيانات الوصفية من `.git/worktrees/`

لا تُحذف ملفات شجرة العمل تلقائيًا. ويستمر الفرع في الوجود.

## فتح شجرة عمل مرتبطة

يمكنك فتح شجرة عمل مرتبطة تمامًا كما تفتح أي مستودع:

```php
$repo = Pitmaster::open('/tmp/review');

// Pitmaster detects the .git file and follows the gitdir reference
echo $repo->isLinkedWorktree();  // true
echo $repo->gitDir();            // '/path/to/project/.git/worktrees/review'
echo $repo->commonGitDir();      // '/path/to/project/.git'
echo $repo->workDir();           // '/tmp/review'
```

تحل عمليات المستودع المسارات كما يلي:
- **الكائنات**: تُقرأ من دليل git المشترك وتُكتب فيه (`project/.git/objects/`)
- **الإعدادات**: تُقرأ من دليل git المشترك (`project/.git/config`)
- **Packed-refs**: تُقرأ من دليل git المشترك
- **HEAD**: خاص بكل شجرة عمل (يتتبع كل منها فرعها)، وكذلك `ORIG_HEAD` و`MERGE_HEAD` ومراجع العمليات الأخرى
- **الفهرس**: خاص بكل شجرة عمل (لكل منها منطقة تجهيز خاصة بها)
- **المراجع المنفصلة**: الفروع والوسوم مشتركة في الدليل المشترك (`project/.git/refs/`)
- **الخطافات**: تُقرأ من دليل git الخاص بشجرة العمل، لذا لا تعمل الخطافات المشتركة ([#12](https://github.com/inline0/pitmaster/issues/12))

لا يتعامل التخزين المؤقت مع أشجار العمل المرتبطة حتى الآن: فهو يقرأ الهوية من دليل شجرة العمل، الذي لا يحتوي على إعدادات، ويكتب سجل reflog فيه ([#14](https://github.com/inline0/pitmaster/issues/14)).

## كائن قيمة شجرة العمل

```php
use Pitmaster\Worktree\Worktree;

$wt->name;          // Metadata name (null for the main worktree)
$wt->path;          // Working directory path
$wt->gitDir;        // Per-worktree git dir
$wt->branch;        // Branch name (null if detached)
$wt->head;          // ObjectId of HEAD commit
$wt->isMain;        // true for the main worktree
$wt->isDetached;    // true if HEAD is detached
$wt->isLocked;      // true if worktree is locked
$wt->lockReason;    // Lock reason, or null when there is none (an empty reason is also null)
```

## WorktreeManager

لإدارة أشجار العمل على مستوى منخفض. لا يكتب `WorktreeManager::add()` سوى البيانات الوصفية وملف `.git`: فهو لا ينشئ الفرع ولا يسحب الملفات ولا يكتب فهرسًا. استخدم `$repo->addWorktree()` للحصول على عملية سحب قابلة للاستخدام. يجب أن يكون الفرع موجودًا بالفعل (أو أن يكون اسم مرجع كاملًا مثل `refs/tags/v1.0.0`، ما يؤدي إلى فصل HEAD).

```php
use Pitmaster\Worktree\WorktreeManager;

$manager = new WorktreeManager($repo->commonGitDir(), $mainWorkDir);

// List
$worktrees = $manager->list();

// Add
$wt = $manager->add('/tmp/review', 'feature/review');
$wt = $manager->add('/tmp/review', 'feature/review', 'review-app');

// Remove
$manager->remove('review');
$manager->remove('review', force: true);

// Lock/unlock (metadata name only)
$manager->lock('review', 'Do not delete, code review in progress');
$manager->unlock('review');
```

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

```php
// Lock (prevents removal)
$manager->lock('review', 'Code review in progress');

// Attempt to remove locked worktree
try {
    $manager->remove('review');
} catch (\RuntimeException $e) {
    // "Worktree is locked: review (Code review in progress)"
}

// Force remove ignores the lock
$manager->remove('review', force: true);

// Unlock
$manager->unlock('review');
```

يُخزّن القفل كملف في `.git/worktrees/<name>/locked`. ومحتوى الملف هو سبب القفل (وقد يكون فارغًا).

## اكتشاف أشجار العمل

```php
// Check if a path is a linked worktree
if (Pitmaster::isWorktree('/tmp/review')) {
    echo "This is a linked worktree\n";
}

// Resolve the common git dir from any path
$common = Pitmaster::commonGitDir('/tmp/review');
// '/path/to/project/.git'

// Resolve a .git file to the actual git directory
$gitDir = WorktreeManager::resolveGitFile('/tmp/review');
// '/path/to/project/.git/worktrees/review'
```

## بنية الملفات

### بيانات شجرة العمل الرئيسية الوصفية لأشجار العمل المرتبطة

```
.git/worktrees/<name>/
  HEAD         Per-worktree HEAD (symbolic ref or detached hash)
  commondir    Relative path to the shared git dir ("../..")
  gitdir       Path back to the worktree's .git file, as passed to addWorktree()
  locked       Present if locked (content = reason)
  index        Per-worktree index/staging area
```

### ملف .git لشجرة العمل المرتبطة

```
gitdir: <relative path to>/project/.git/worktrees/<name>
```

### مشاركة الموارد

| المورد | الموقع | مشترك؟ |
|----------|----------|---------|
| الكائنات | `$commonDir/objects/` | نعم |
| الإعدادات | `$commonDir/config` | نعم |
| Packed-refs | `$commonDir/packed-refs` | نعم |
| الخطافات | `$gitDir/hooks/` | لا: لا يشغّل Pitmaster الخطافات المشتركة في أشجار العمل المرتبطة |
| HEAD | `$gitDir/HEAD` | لا (خاص بكل شجرة عمل) |
| الفهرس | `$gitDir/index` | لا (خاص بكل شجرة عمل) |
| المراجع المنفصلة | `$commonDir/refs/` | نعم (HEAD ومراجع العمليات مثل `MERGE_HEAD` خاصة بكل شجرة عمل) |
