حتى عند مقارنة الملفين أنفسهم، قد تختلف النتيجة باختلاف خوارزمية diff. كل النتائج «صحيحة»، لكنها تختلف في الأسطر التي تعدّها متطابقة، ولذلك تختلف سهولة قراءتها. يوفّر git أربعة خيارات عبر --diff-algorithm.
| القيمة | الوصف في وثائق git | الخصائص |
|---|---|---|
myers (default) | الخوارزمية الجشعة (greedy) الأساسية، وهي الافتراضية حاليًا | سريعة ونتيجتها غالبًا قريبة من الأصغرية |
minimal | تقضي وقتًا إضافيًا لإنتاج أصغر diff ممكن | أصغرية دائمًا، وقد تكون بطيئة مع المدخلات الكبيرة |
patience | خوارزمية patience diff | تتخذ الأسطر الفريدة نقاط ارتكاز |
histogram | توسّع patience لتدعم العناصر المشتركة النادرة | تتخذ الأسطر النادرة نقاط ارتكاز |
توجد أيضًا صيغ مختصرة مثل git diff --patience وgit diff --histogram، ويمكن تغيير القيمة الافتراضية بالأمر git config diff.algorithm histogram.
Myers: القيمة الافتراضية التي تبحث عن أقل تحرير
تبحث خوارزمية مايرز عن المسار الذي يقلّل عدد عمليات الحذف والإضافة إلى الحد الأدنى (المبدأ في مقال كيف يعمل diff). تظهر المشكلة عندما توجد عدة خيارات للأسطر التي تُعد متطابقة. في الكود أسطر شائعة جدًا مثل } و{ والأسطر الفارغة وreturn، فقد تقرن الخوارزمية أسطرًا لا علاقة بينها في المعنى ويبقى عدد التعديلات أصغريًا مع ذلك.
تغيير واحد ونتيجتان
لنفترض أنك أضفت دالة جديدة h بين الدالتين f وg. في كلا الـ diff أدناه 4 أسطر مضافة، أي أن عدد التعديلات متساوٍ.
@@ -1,6 +1,10 @@ int f() { return 1; }++int h() {+ return 3;+} int g() { return 2;
@@ -1,5 +1,9 @@ int f() { return 1;+}++int h() {+ return 3; } int g() {
في الأول تظهر الدالة الجديدة كاملة، أما في الثاني فقد عُدّ قوس الإغلاق الخاص بالدالة القائمة f قوسًا للدالة الجديدة، فانقطع الجزء المضاف بشكل غير طبيعي. ينشأ هذا الشكل بسبب ترتيب البحث، ويصحّح git الحديث جزءًا كبيرًا منه باستدلال ينقل حدود المقطع المتغير بالنظر إلى المسافات البادئة ليصبح أسهل قراءة (--indent-heuristic، مفعّل افتراضيًا).
Patience: مطابقة الأسطر الفريدة أولًا
اقترح برام كوهين (Bram Cohen) خوارزمية patience diff، وهي تبحث أولًا عن الأسطر التي تظهر مرة واحدة بالضبط في كل ملف، لأن السطر الفريد مثل تعريف الدالة int h() { يكون قرينه مؤكدًا. من بين هذه الأسطر الفريدة تُختار أطول قائمة متسقة الترتيب (أطول متتالية جزئية متزايدة) لتكون نقاط ارتكاز، ثم تُعاد مقارنة المقاطع الصغيرة الواقعة بينها فقط.
- الميزة: لا تنجرّ وراء الأسطر الشائعة مثل
}أو الأسطر الفارغة، فتظهر التغييرات على مستوى الدوال والفقرات كتلًا متماسكة. - العيب: مع المدخلات التي تكاد تخلو من الأسطر الفريدة (بيانات تتكرر فيها الأسطر، أو السجلات) لا تجد نقاط ارتكاز، فلا تختلف عن diff العادي، بل قد تظهر النتيجة كتلًا كبيرة مدمجة.
Histogram: الأولوية للأسطر النادرة
طُوّرت خوارزمية histogram في JGit (تطبيق git بلغة جافا) ثم أُدخلت في git. وعلى عكس patience التي لا تنظر إلا إلى «الأسطر التي تظهر مرة واحدة بالضبط»، فإن histogram تحصي عدد مرات ظهور كل سطر وتختار الأقل ظهورًا نقاطًا للارتكاز. لذلك يمكنها الارتكاز على أسطر نادرة نسبيًا حتى لو لم توجد أسطر فريدة. تصفها وثائق git بأنها «توسّع خوارزمية patience لتدعم العناصر المشتركة قليلة الظهور». وفي الممارسة العملية كثيرًا ما تنتج مثل patience نتيجة تحافظ على بنية الكود جيدًا.
أيّها تستخدم؟
- مراجعة الكود اليومية: القيمة الافتراضية كافية. إذا بدت النتيجة مقطوعة بشكل غريب فأعد العرض باستخدام
--histogram. - إعادة هيكلة كبيرة نُقلت فيها دوال أو أُضيفت عدة دوال:
--histogramأو--patienceتحافظان على الكتل جيدًا. - عندما يجب أن يكون عدد الأسطر المتغيرة أصغريًا بدقة:
--minimal. - ملفات البيانات كثيرة التكرار: قد يكون الترتيب والتوحيد أهم من الخوارزمية. إذا كانت بصيغة JSON فراجع مقارنة JSON.
أيًّا كانت الخوارزمية، يُستعاد الملف الناتج بالشكل نفسه. الذي يختلف هو الشكل الذي يقرؤه الإنسان فقط.
في هذه الأداة
يقارن هذا الموقع الأسطر بخوارزمية من عائلة Myers، ثم يقرن الأسطر المتغيرة بحسب تشابه محتواها بوصفها «معدَّلة» ويعيد مقارنة ما بداخلها. لذلك حتى لو انقطعت النتيجة على مستوى السطر بشكل غريب قليلًا، ترى فورًا أي كلمة تغيّرت. أدخل المثال أعلاه في مقارنة النصوص وقارن كيف يبدو في العرض الموحّد والعرض المتجاور. وطريقة قراءة النتيجة مشروحة في مقال كيف تقرأ unified diff.