
# الفروق

تحسب Pitmaster الفروق بتنسيق git الموحد. يدعم محرك الفروق خوارزميات متعددة، وتنسيق الفروق الموحد، واكتشاف الملفات الثنائية، والمقارنة التكرارية على مستوى الشجرة.

بالنسبة إلى ملف نصي معدّل بنمط `100644`، تنتج `format()` البايتات نفسها التي تنتجها `git diff`. تُنسّق الحالات الأخرى بطريقة مختلفة حاليًا ([#3](https://github.com/inline0/pitmaster/issues/3)):

- لا تحتوي الملفات الجديدة والمحذوفة على سطر `new file mode` / `deleted file mode` أو سطر `index` أو `/dev/null`: يُشار إلى كلا الجانبين باسم `a/<path>` و`b/<path>`، ويُكتب نطاق مقطع التغيير للجانب الفارغ على هيئة `-1,0` أو `+1,0` حيث يكتب git `-0,0` أو `+0,0`.
- ينتهي سطر `index` دائمًا بـ `100644`، مهما كان نمط الملف.
- لا تنتج تغييرات النمط وحدها (مثل `chmod +x`) أي نتيجة.
- تطبع الملفات الثنائية `Binary files differ` دون سطر `index`، بينما يطبع git `Binary files a/<path> and b/<path> differ`.
- تظهر عمليات إعادة التسمية كمدخل `diff --git a/<old> b/<new>` واحد مع فرق المحتوى، دون أسطر `similarity index` أو `rename from` أو `rename to`.

## عمليات الفروق

### التغييرات غير المرحّلة (شجرة العمل مقابل الفهرس)

```php
$diffs = $repo->diff();

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

تقارن كل ملف في الفهرس بحالته الحالية في شجرة العمل. وتكتشف التعديلات والحذف والملفات الثنائية.

### التغييرات المرحّلة (الفهرس مقابل HEAD)

```php
$diffs = $repo->diffStaged();

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

تقارن الفهرس الحالي بشجرة الالتزام HEAD. وتعرض ما سيُضمّن في الالتزام التالي. تُعرض الملفات المحذوفة والمضافة ذات المحتوى المتشابه كمدخل واحد أُعيدت تسميته. قبل الالتزام الأول، لا يوجد HEAD وتكون النتيجة فارغة ([#5](https://github.com/inline0/pitmaster/issues/5)).

تطابق عملية إقران الملفات المعاد تسميتها حاليًا ملفات غير مرتبطة ذات سطر واحد أيضًا، لأن السطر الفارغ الختامي يُحتسب محتوى مشتركًا ([#4](https://github.com/inline0/pitmaster/issues/4)).

### فروق شجرة إلى شجرة

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

تقارن شجرتين بشكل تكراري. مرّر معرّفات الأشجار: لا تُحوّل معرّفات الالتزام إلى أشجارها، وتنتج نتيجة فارغة. يستخدم المحرك نفسه `TreeDiff` كل من `diffStaged()` و`show()` و`logPath()`.

### التصفية حسب المسار

```php
$diffs = $repo->diff('src/specific-file.php');
```

مواصفة المسار هي مسار ملف محدد. تقبل `diffStaged()` الوسيط نفسه لكنها تتجاهله حاليًا، لذا تعرض دائمًا كل الملفات المرحّلة ([#5](https://github.com/inline0/pitmaster/issues/5)).

### اختيار خوارزمية

```php
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');
```

الأسماء الصالحة هي `myers` (الافتراضي) و`patience` و`histogram` و`minimal`. يؤدي أي اسم آخر إلى رمي `InvalidArgumentException`.

## بنية DiffResult

يمثل كل `DiffResult` الفرق الخاص بملف واحد.

```php
use Pitmaster\Diff\DiffResult;

foreach ($diffs as $diff) {
    echo $diff->oldPath;    // Path in the old tree
    echo $diff->newPath;    // Path in the new tree
    echo $diff->binary;     // true for binary files
    echo $diff->oldHash;    // Hex hash of the old blob (null for added files)
    echo $diff->newHash;    // Hex hash of the new blob (null for deleted files)

    foreach ($diff->hunks as $hunk) {
        echo $hunk->header();  // @@ -1,5 +1,7 @@
        foreach ($hunk->lines as $line) {
            echo $line . "\n"; // ' context', '+added', '-removed'
        }
    }
}
```

### المخرجات المنسّقة

```php
echo $diff->format();
```

ينتج مخرجات الفروق الموحدة. وبالنسبة إلى ملف نصي معدّل، تطابق `git diff`:

```
diff --git a/src/File.php b/src/File.php
index abc1234..def5678 100644
--- a/src/File.php
+++ b/src/File.php
@@ -10,6 +10,8 @@ class File
     private string $name;

+    private int $count;
+
     public function __construct()
     {
```

### التحقق من وجود تغييرات

```php
if ($diff->hasChanges()) {
    // File was modified (or is binary with changes)
}
```

## بنية مقطع التغيير

يمثل كل `Hunk` منطقة متصلة من التغييرات مع أسطر السياق.

```php
use Pitmaster\Diff\Hunk;

$hunk->oldStart;   // Starting line in old file
$hunk->oldCount;   // Number of lines from old file
$hunk->newStart;   // Starting line in new file
$hunk->newCount;   // Number of lines in new file
$hunk->lines;      // Array of diff lines (prefixed with ' ', '+', or '-')
$hunk->header();   // "@@ -10,6 +10,8 @@"
```

## خوارزميات الفروق

تنفذ Pitmaster أربع خوارزميات للفروق. والخوارزمية الافتراضية هي Myers.

### فروق Myers

خوارزمية O(ND) القياسية، وهي نفسها الافتراضية في git. تنتج أقصر تسلسلات التعديلات.

```php
use Pitmaster\Diff\MyersDiff;

$hunks = MyersDiff::diff($oldContent, $newContent);
```

تأخذ طريقة `diff()` سلسلتين وتعيد مصفوفة من كائنات `Hunk`. تقسم المدخلات عند الأسطر الجديدة، وتحسب أقصر تسلسل للتعديلات، ثم تجمع التغييرات في مقاطع مع 3 أسطر من السياق (مطابقةً للإعداد الافتراضي في git).

### فروق Patience

فروق بنيوية أفضل للأكواد. تطابق الأسطر الفريدة أولًا، ثم تملأ ما بينها.

```php
use Pitmaster\Diff\PatienceDiff;

$hunks = PatienceDiff::diff($oldContent, $newContent);
```

### فروق Histogram

صيغة من فروق Patience تتعامل مع الأسطر المتكررة بشكل أفضل. يستخدمها JGit وEclipse.

```php
use Pitmaster\Diff\HistogramDiff;

$hunks = HistogramDiff::diff($oldContent, $newContent);
```

### الحد الأدنى للفروق

تنتج أصغر فرق ممكن (أقل عدد من الأسطر المتغيرة)، مقابل إجراء المزيد من العمليات الحسابية.

```php
use Pitmaster\Diff\MinimalDiff;

$hunks = MinimalDiff::diff($oldContent, $newContent);
```

## اكتشاف الملفات الثنائية

تتعامل Pitmaster مع المحتوى باعتباره ثنائيًا إذا احتوى على بايت NUL ضمن أول 8192 بايتًا (يفحص git أول 8000).

```php
if (MyersDiff::isBinary($content)) {
    // Binary file, skip line-level diff
}
```

تنتج الملفات الثنائية `DiffResult` مع `$binary = true` ومصفوفة `$hunks` فارغة. وتكون المخرجات المنسّقة:

```
diff --git a/image.png b/image.png
Binary files differ
```

## المخرجات الملوّنة

تستخدم CLI `ColorDiff` للمخرجات في الطرفية مع ألوان ANSI.

```php
use Pitmaster\Diff\ColorDiff;

$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
```

- تظهر الأسطر المضافة (`+`) باللون الأخضر
- تظهر الأسطر المحذوفة (`-`) باللون الأحمر
- تظهر عناوين مقاطع التغيير (`@@`) باللون السماوي
- تظهر عناوين الملفات (`diff --git` و`index` و`---` و`+++`) بخط عريض

تضيف `pitmaster diff` الألوان دائمًا، حتى عند توجيه مخرجاتها إلى مسار آخر. ولا تضيف `pitmaster show` الألوان إلا عندما يكون stdout طرفية.

## فروق الأشجار (داخلي)

تقارن الفئة `TreeDiff` كائني شجرة بشكل تكراري، وتنتج `DiffResult` لكل ملف تغيّر.

```php
use Pitmaster\Diff\TreeDiff;

$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);
```

تتعامل فروق الأشجار مع:
- الملفات المضافة (موجودة في الشجرة الجديدة فقط)
- الملفات المحذوفة (موجودة في الشجرة القديمة فقط)
- الملفات المعدّلة (المسار نفسه مع تجزئة blob مختلفة)
- المقارنة التكرارية للأدلة الفرعية
- إقران الملفات المحذوفة والمضافة عند إعادة التسمية (تطابق التجزئة تمامًا أو اشتراك في 50% على الأقل من الأسطر)

يتم تخطي المدخلات التي لم تتغير تجزئتها، لذا لا ينتج عن تغيير النمط وحده أي نتيجة.

## فروق الكلمات

للتغييرات المضمنة على مستوى الكلمات داخل الأسطر.

```php
use Pitmaster\Diff\WordDiff;

$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'
```
