دمج الأكواد (Git Merge vs Rebase) وحل التعارضات (Merge Conflicts)

دقائق القراءة: 5

مقدمة

عند العمل ضمن فرق تطوير تعتمد على Git، فإن السؤال المتكرر ليس فقط كيف نحفظ التغييرات، بل كيف ندمجها دون إفساد تاريخ المشروع أو تعطيل خط النشر. وهنا يظهر الفرق الجوهري بين Merge وRebase، وهما من أكثر العمليات تأثيراً على جودة التعاون داخل المستودع.

فهم هذا الفرق ليس قضية نظرية فقط، بل له أثر مباشر على مراجعات الكود، سرعة حل التعارضات، ودقة عمل أنظمة CI/CD. وإذا كنت قد قرأت مقال ما هو DevOps؟ ولماذا تدفع الشركات ثروات لمهندسي الأتمتة السحابية؟ فستعرف أن انضباط تاريخ الشيفرة جزء أساسي من ثقافة الأتمتة وليس مجرد تفضيل شخصي.

ما الفرق المعماري بين Git Merge وGit Rebase؟

كيف يعمل Merge

عملية Merge تقوم بضم تاريخ فرعين كما هو، مع إنشاء merge commit عند الحاجة. هذا الأسلوب يحافظ على السجل الحقيقي لتفرع العمل وتقاطعه، ولذلك يكون مناسباً للمشاريع التي تريد توثيق مسار التطوير كما حدث فعلاً.

النتيجة أن تاريخ المستودع قد يصبح أكثر تشعباً، لكنه واضح من ناحية معرفة متى تم دمج فرع ميزة، ومن قام بذلك، وما هي النقطة التي دخل فيها التغيير إلى الفرع الرئيسي.

كيف يعمل Rebase

أما Rebase فيعيد كتابة التاريخ عبر نقل التزامات فرعك فوق آخر نقطة من الفرع الهدف. عملياً، يبدو السجل وكأن العمل تم بناؤه فوق أحدث إصدار منذ البداية، ما ينتج تاريخاً خطياً ونظيفاً وسهل القراءة.

هذا مفيد جداً عند تجهيز feature branch قبل فتح pull request، لكنه يتطلب حذراً لأنك تغيّر معرفات الالتزامات نفسها.

متى نستخدم كل أسلوب في بيئات الفرق وعمليات النشر؟

في المشاريع الصغيرة أو الفرق التي تعطي أولوية للبساطة والتتبع، يكون Merge خياراً ممتازاً. أما في الفرق التي تعتمد مراجعات صارمة وتريد سجلاً خطياً يسهل تحليله في أنظمة Pipelines وتقارير الإصدار، فغالباً تفضّل Rebase.

القرار هنا يجب أن يكون سياسة فريق لا اجتهاداً فردياً. وهذا يرتبط مباشرة بإدارة الفروع، وهي فكرة توسعنا فيها في مقال ما وراء الالتزام (Commit): كيف تدير فروع المشروع (Branches) باحترافية؟.

  • استخدم Merge إذا أردت الاحتفاظ بسجل التعاون الحقيقي بين الفروع.
  • استخدم Rebase إذا أردت تاريخاً خطياً ونظيفاً قبل الدمج النهائي.
  • لا تستخدم Rebase على فرع مشترك يعمل عليه أكثر من مطور دون اتفاق واضح.

أوامر الدمج وإعادة البناء عملياً

تنفيذ Merge

git checkout main
git pull origin main
git merge feature/payment-api
git push origin main

هذا السيناريو يدمج فرع feature/payment-api داخل main. إذا لم توجد تعارضات فسيتم الدمج مباشرة، وقد يُنشأ merge commit تلقائياً.

تنفيذ Rebase

git checkout feature/payment-api
git fetch origin
git rebase origin/main
git checkout main
git merge feature/payment-api
git push origin main

في هذا الأسلوب، نقوم أولاً بتحديث فرع الميزة فوق آخر نسخة من main. وبعدها يصبح الدمج النهائي بسيطاً وغالباً خطياً. كثير من الفرق تستخدم هذا النمط قبل تشغيل اختبارات البناء الخاصة بتطبيقات Docker أو نشر خدمات Kubernetes.

ما هي Merge Conflicts ولماذا تحدث؟

تعارضات الدمج تظهر عندما يكتشف Git أن فرعين قاما بتعديل نفس السطور أو نفس البنية بطريقة لا يمكن حسمها تلقائياً. هذا يحدث كثيراً في ملفات الإعداد مثل deployment.yaml أو Dockerfile أو ملفات سير العمل الخاصة بـ GitHub Actions.

في بيئات البنية التحتية ككود، التعارض أخطر من مجرد مشكلة شكلية؛ لأن اختيار نسخة خاطئة من متغير أو صورة حاوية قد يؤدي إلى فشل النشر أو إلى Downtime فعلي.

لا تتعامل مع تعارضات ملفات البنية التحتية أو إعدادات النشر كأنها مجرد أسطر متنافسة. أي حسم غير مدروس في ملفات YAML أو أسرار البيئة قد يفتح ثغرة أمنية أو يوقف الخدمة على الإنتاج.

خطوات حل التعارضات بشكل احترافي

  1. نفّذ عملية الدمج أو rebase حتى تظهر الملفات المتعارضة.
  2. استخدم الأمر التالي لمعرفة الملفات المتأثرة.
git status

بعدها افتح الملف المتعارض وستجد علامات يضعها Git لتوضيح النسختين.

<<<<<<< HEAD
image: myapp:v2
=======
image: myapp:v3
>>>>>>> feature/update-image

الخطوة الصحيحة ليست حذف العلامات عشوائياً، بل فهم أي نسخة تمثل الحقيقة التشغيلية الحالية. إن كان الفريق قد حدّث إصدار الصورة في فرع لتصحيح ثغرة أمنية، بينما غيّر فرع آخر قيمة قديمة، فيجب الإبقاء على النسخة الأحدث لا النسخة الأسهل.

  1. عدّل الملف يدوياً واختر الصيغة النهائية المتفق عليها.
  2. أضف الملف بعد الحسم.
git add deployment.yaml
  1. أكمل العملية حسب نوعها.
git merge --continue
git rebase --continue

إذا اكتشفت أن التعارضات كثيرة أو أن نقطة الانطلاق كانت خاطئة، يمكنك التراجع بأمان.

git merge --abort
git rebase --abort

مثال مرتبط بملفات النشر والحاويات

لنفترض أن أحد المطورين غيّر نسخة صورة التطبيق، بينما عدّل آخر عدد النسخ التشغيلية داخل ملف نشر خاص بـ Kubernetes. هنا يجب حل التعارض مع الحفاظ على التعديلين معاً، لا اختيار أحدهما فقط.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-api
spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: payment-api
          image: registry.example.com/payment-api:v3

هذه النوعية من الملفات شائعة جداً في فرق تعتمد الحاويات. وإذا كنت تبني بيئات معزولة وتبحث في طريقة توحيد التشغيل بين المطورين والخوادم، فراجع مقال مشكلة “الكود يعمل على جهازي فقط” وكيف يحلها Docker نهائياً؟ لأنه يوضح لماذا يصبح تاريخ الدمج النظيف مهماً عند التعامل مع صور وبيئات متعددة.

أفضل الممارسات لتقليل التعارضات من الأساس

  • حدّث فرعك باستمرار من main بدلاً من الانتظار حتى نهاية الأسبوع.
  • قسّم العمل إلى تغييرات صغيرة وقابلة للمراجعة، فالفروع الطويلة تزيد احتمالات التصادم.
  • افصل بين تعديلات المنطق البرمجي وتعديلات ملفات البنية التحتية متى أمكن.
  • وحّد تنسيق الملفات باستخدام أدوات مثل linters وformatters.
  • اجعل اختبارات CI تعمل بعد الدمج للتأكد من أن الحسم لم يكسر البناء.

إذا كنت تستخدم Rebase على فرع تم دفعه مسبقاً إلى المستودع البعيد، فغالباً ستحتاج إلى git push --force-with-lease وليس --force الأعمى، لتجنب محو عمل زملائك بالخطأ.

الخلاصة

الاختيار بين Git Merge وGit Rebase ليس معركة من هو الأفضل مطلقاً، بل قرار معماري يعتمد على طريقة عمل الفريق ومستوى الانضباط في الفروع والمراجعات. Merge يحافظ على الحقيقة التاريخية، بينما Rebase يمنحك سجلاً أنظف وأسهل في التتبع.

أما تعارضات الدمج، فهي ليست علامة فشل، بل إشارة إلى وجود تغييرات متقاطعة تحتاج فهماً واعياً للسياق البرمجي والتشغيلي. وكلما كانت فروعك قصيرة، وسياساتك واضحة، وربطك مع اختبارات النشر مضبوطاً، أصبح حل التعارضات أسرع وأكثر أماناً على الكود والخوادم معاً.

5 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *