
# الدمج

تنفذ Pitmaster دمج الفروع بدمج ثلاثي الاتجاهات، مثل `git merge`. وتكتشف فرص التقديم السريع، وتحسب قواعد الدمج، وتنفذ عمليات الدمج على مستوى الشجرة والمحتوى، وتنشئ علامات التعارض القياسية عند تعارض الملفات.

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

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

if ($result->clean) {
    echo "Merged successfully: {$result->commitId->hex}\n";
} else {
    echo "Conflicts:\n";
    foreach ($result->conflictPaths as $path) {
        echo "  {$path}\n";
    }
}
```

## MergeResult

الفئة `MergeResult` كائن قيمة للقراءة فقط:

```php
use Pitmaster\Merge\MergeResult;

$result->clean;           // bool: true if merge completed without conflicts
$result->commitId;        // ?ObjectId: the merge commit (null if conflicts)
$result->conflictPaths;   // array: list of file paths with conflicts
$result->mergedContents;  // array: path => content with conflict markers (if conflicts)
```

عندما يتوقف الدمج بسبب التعارضات، تُكتب حالة التعارض في الفهرس وشجرة العمل. حلّ الملفات، و`add()`ها، ثم استدعِ `$repo->mergeContinue()`، أو استدعِ `$repo->mergeAbort()` لاستعادة الحالة السابقة للدمج.

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

## عمليات الدمج بالتقديم السريع

عندما يكون HEAD الحالي سلفًا للفرع المستهدف، تنفذ Pitmaster دمجًا بالتقديم السريع: تنقل HEAD ببساطة إلى الالتزام المستهدف دون إنشاء التزام دمج.

```
Before:         After fast-forward:

A---B (main)    A---B---C---D (main)
     \
      C---D (feature)
```

```php
$result = $repo->merge('feature');
// $result->clean === true
// $result->commitId points to D
// No merge commit created
```

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

## الدمج الثلاثي

عندما تتباعد الفروع، تنفذ Pitmaster دمجًا ثلاثي الاتجاهات:

1. العثور على قاعدة الدمج (أدنى سلف مشترك)
2. مقارنة الأساس بما لدينا وبما لديهم على مستوى الشجرة
3. تنفيذ دمج على مستوى المحتوى لكل ملف تغيّر في كلا الفرعين
4. إنشاء التزام دمج بأبوين

```
Before:              After merge:

      C---D (feature)         C---D
     /                       /     \
A---B---E---F (main)   A---B---E---F---G (main)
```

## قاعدة الدمج

قاعدة الدمج هي أحدث سلف مشترك لالتزامين. تعثر Pitmaster عليها بالتنقل عبر رسم الالتزامات. وعندما توجد قواعد دمج متعددة (في سجل متقاطع)، تدمجها `merge()` أولًا وتستخدم النتيجة أساسًا.

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

if ($base !== null) {
    echo "Common ancestor: {$base->hex}\n";
}
```

للوصول المباشر إلى خوارزمية `MergeBase`:

```php
use Pitmaster\Merge\MergeBase;

$finder = new MergeBase($repo->objectDatabase());
$base = $finder->find($commitA, $commitB);

// All merge bases (criss-cross histories can have more than one)
$bases = $finder->findAll($commitA, $commitB);

// Check ancestry
$isAncestor = $finder->isAncestor($oldCommit, $newCommit);
```

## التحقق من دمج الفروع

```php
if ($repo->isBranchMerged('feature/done')) {
    // All commits in feature/done are reachable from default branch
    $repo->deleteBranch('feature/done');
}

// Check against a specific target
if ($repo->isBranchMerged('feature/done', 'develop')) {
    // Merged into develop
}
```

## علامات التعارض

عندما يُعدّل الملف في كلا الفرعين وتتداخل التغييرات، تنشئ Pitmaster علامات التعارض القياسية. وتضع `merge()` التسميات `HEAD` والاسم المدمج للفرع على الجانبين:

```
<<<<<<< HEAD
    return $this->value + 1;
=======
    return $this->value * 2;
>>>>>>> feature
```

تُحيط الفئة `ConflictMarker` بإصدارين بعلامات:

```php
use Pitmaster\Merge\ConflictMarker;

$marked = ConflictMarker::mark($oursContent, $theirsContent, 'HEAD', 'feature');

// diff3 style, with the base section
$marked = ConflictMarker::mark($oursContent, $theirsContent, 'HEAD', 'feature', $baseContent, 'base');
```

## دمج ثلاثي الاتجاهات على مستوى المحتوى

تدمج الفئة `ThreeWayMerge` محتوى blob (وليس الملفات):

```php
use Pitmaster\Merge\ThreeWayMerge;

$result = ThreeWayMerge::merge($baseContent, $oursContent, $theirsContent, 'HEAD', 'feature');

$result['content'];   // merged text, with conflict markers if needed
$result['clean'];     // true when nothing conflicted
$result['conflicts']; // number of conflict regions
```

تأخذ ثلاث سلاسل (الإصدار الأساسي وإصدارنا وإصدارهم) بالإضافة إلى تسميات اختيارية ونمط للتعارض (`'merge'` افتراضيًا، أو `'diff3'` لتضمين القسم الأساسي).

## استراتيجيات الدمج

### الدمج التكراري

الاستراتيجية الافتراضية (`$repo->merge($branch)`)، وتتعامل مع سجلات الدمج المتقاطعة ذات قواعد الدمج المتعددة. تقبل CLI أيضًا `-s ort` و`-s recursive` لتنفيذها.

### دمج ما لدينا

يسجل التزام دمج يُبقي شجرة HEAD كما هي. يفيد في الحفاظ على سجل الفروع دون إدماج التغييرات.

```php
$result = $repo->merge('feature/old', 'ours');
```

### دمج الأخطبوط

يدمج فرعين أو أكثر في التزام دمج واحد. إذا تعارض أي فرع، يعيد نتيجة غير نظيفة دون كتابة حالة الدمج أو إنشاء التزام.

```php
$result = $repo->mergeOctopus(['feature/a', 'feature/b', 'feature/c']);
```

الفئات `RecursiveMerge` و`OursMerge` و`OctopusMerge` في `Pitmaster\Merge` أدوات مساعدة للدمج على مستوى المحتوى؛ أما `Repository` فينفذ الاستراتيجيات أعلاه بنفسه.

## Rerere (إعادة استخدام الحل المسجل)

تتضمن Pitmaster فئة مستقلة `Rerere` تخزّن الحلول بتنسيق `rr-cache` الخاص بـ git:

```php
use Pitmaster\Merge\Rerere;

$rerere = new Rerere($repo->gitDir());

if ($rerere->isEnabled()) {                     // rerere.enabled = true in .git/config
    $rerere->record($conflicted, $resolved);    // remember a resolution
    $resolved = $rerere->resolve($conflicted);  // replay it, or null
}
```

لا تستدعيها `merge()`: لا يُسجّل الحل ولا يُعاد تطبيقه إلا عندما ينفذ الكود ذلك. تبحث `isEnabled()` عن النص الحرفي `rerere.enabled = true` في `.git/config` ولا تتعرف على القسم `[rerere]` الذي تكتبه `git config rerere.enabled true` ([#20](https://github.com/inline0/pitmaster/issues/20)).

## تدفق الدمج على مستوى الشجرة

عملية الدمج كاملةً:

1. تحدد `MergeBase::findAll()` الأسلاف المشتركين
2. تُقارن أشجار الأساس وما لدينا وما لديهم مسارًا بمسار
3. تُعتمد تغييرات الملفات التي تغيّرت في فرع واحد فقط
4. بالنسبة إلى الملفات التي تغيّرت في كلا الفرعين:
   - إذا تغيّرت بالطريقة نفسها، يُعتمد أي منهما (فهما متطابقان)
   - إذا اختلفت التغييرات، يُشغّل `ThreeWayMerge::merge()` على المحتوى
5. إذا كانت كل عمليات الدمج نظيفة، تُنشأ الشجرة المدمجة ويُنشأ التزام دمج
6. إذا وُجدت تعارضات، يُعاد `MergeResult` مع `clean = false` ومسارات الملفات المتعارضة

## استخدام CLI

```bash
./vendor/bin/pitmaster merge feature/login
```

المخرجات عند النجاح:
```
Merge successful.
```

المخرجات عند وجود تعارض:
```
CONFLICT in: src/File.php, src/Other.php
```
