الدمج وإعادة الأساس

7 دقيقة

جدول المحتويات


1 — جمع فرعين: الحاجة

عملت على فرع feature، والشفرة جاهزة. يجب الآن إعادة دمجها في main. يوفّر Git آليتين لذلك: الدمج (merge) وإعادة الأساس (rebase).

كلاهما يبلغ الغاية نفسها — جمع العمل — لكن بـ شكل سجل مختلف. هذا جوهر الدرس.

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

قبل أي دمج، نتأكد من أحدث نسخة:

bash
git switch main
git pull origin main

↑ العودة إلى الأعلى


2 — الدمج (merge)

الأمر git merge يجمع فرعاً في فرع آخر. هناك حالتان.

الحالة 1 — دمج سريع (fast-forward) : إذا لم يتحرك main منذ إنشاء الفرع، يتقدّم Git بالمؤشر فقط. لا يُنشأ أي إيداع دمج.

الحالة 2 — دمج ثلاثي (three-way merge) : إذا استقبل main إيداعات جديدة في الأثناء، ينشئ Git إيداع دمج له والدان.

bash
# الانتقال إلى الفرع الهدف ثم الدمج
git switch main
git merge feature/panier

# فرض إيداع دمج حتى لو كان fast-forward ممكناً
git merge --no-ff feature/panier
الخيارالأثر
git merge featureدمج (fast-forward إن أمكن)
git merge --no-ff featureإنشاء إيداع دمج دائماً (يترك أثر الفرع)
git merge --abortإلغاء دمج جارٍ بسبب تعارض

الدمج يحفظ التاريخ الحقيقي: نرى متى وكيف التقت الفروع. هذا صادق، لكن السجل قد يصبح كثيفاً مع كثرة إيداعات الدمج.

تمرين مصغّر — تريد دمج feature/panier في main مع فرض إنشاء إيداع دمج، حتى لو كان fast-forward ممكناً. اكتب الأمر.

عرض الحل

git merge --no-ff feature/panier — يبقي --no-ff أثراً صريحاً للفرع المدمَج.

↑ العودة إلى الأعلى


3 — إعادة الأساس (rebase)

ينقل git rebase إيداعات فرعك لـ يعيد تشغيلها فوق رأس فرع آخر. النتيجة: سجل خطي، كأنك بدأت العمل بعد آخر إيداعات main.

قبل إعادة الأساس :

بعد git rebase main (يُعاد تشغيل الإيداعين B و C بعد D) :

bash
# على فرع feature، إعادة التشغيل فوق main
git switch feature/panier
git rebase main

# ثم دمج fast-forward نظيف في main
git switch main
git merge feature/panier
ميزة إعادة الأساسالاحتياط
سجل خطي وقابل للقراءةيعيد كتابة الإيداعات (SHA جديدة)
بلا إيداعات دمج طفيليةلا تعِد الأساس أبداً لفرع دُفع ومشترَك
مثالية قبل طلب سحبتعارضات تُحَل إيداعاً بإيداع

القاعدة الذهبية لإعادة الأساس : لا تعِد أساس إيداعات منشورة ويستخدمها آخرون. أنت تعيد كتابة التاريخ، وهذا يكسر مستودعاتهم. إعادة الأساس لـ عملك المحلي غير المشترَك.

تمرين مصغّر — أنت على فرعك feature/panier. اكتب الأمر لإعادة تشغيل إيداعاتك فوق رأس main (سجل خطي).

عرض الحل

git rebase main (وأنت على feature/panier).

↑ العودة إلى الأعلى


4 — حل التعارضات

يحدث تعارض عندما لا يستطيع Git القرار تلقائياً: فرعان عدّلا السطر نفسه في الملف نفسه. يتوقف Git ويطلب منك الحسم.

يدرج Git علامات تعارض في الملف :

text
<<<<<<< HEAD
prix = 10   # version de main
=======
prix = 12   # version de feature
>>>>>>> feature/panier

الحل خطوة بخطوة :

  1. افتح الملف واختر (أو ادمج) النسخة الصحيحة.
  2. احذف العلامات <<<<<<< و ======= و >>>>>>>.
  3. علّم الملف محلولاً بـ git add.
  4. أنهِ العملية.
bash
# عرض الملفات المتعارضة
git status

# بعد التحرير اليدوي
git add fichier-en-conflit.py

# إنهاء دمج
git commit

# إنهاء إعادة أساس
git rebase --continue

# عند الذعر: إلغاء الكل
git merge --abort      # أو : git rebase --abort
أداة مساعدةالاستخدام
git statusسرد الملفات المتعارضة
git diffعرض الفروقات المتعارضة
git mergetoolتشغيل أداة رسومية للحل
VS Codeأزرار Accept Current / Incoming / Both

التعارض ليس خطأ: Git يقول بصراحة «لا أعلم أيهما أبقي، القرار لك». الهدوء وقراءة العلامات يكفي في 99 % من الحالات.

تمرين مصغّر — حرّرت الملف app.py لحل تعارض وقع أثناء إعادة أساس. أي أمرين ينهيان العملية؟

عرض الحل
bash
git add app.py
git rebase --continue

(لدمج، يكون git add app.py ثم git commit.)

↑ العودة إلى الأعلى


5 — الدمج أو إعادة الأساس: ماذا نختار؟

كلاهما يجمع العمل، لكنهما ينتجان سجلاً مختلفاً. الاختيار غالباً اتفاق فريق.

الجانبالدمجإعادة الأساس
السجلأمين، متفرعخطي، نظيف
إيداع دمجنعم (إن لم يكن fast-forward)لا
يعيد كتابة التاريخلانعم (SHA جديدة)
آمن على فرع مشترَكنعملا
مقروئية logأكثفأوضح

الممارسة الموصى بها الأكثر شيوعاً :

  • أعد أساس فرعك المحلي على main قبل فتح طلب سحب ← سجل نظيف.
  • ادمج طلب السحب في main ← أثر واضح للدمج.
bash
# 1. تنظيف الفرع المحلي قبل طلب السحب
git switch feature/x
git rebase main

# 2. بعد الموافقة على طلب السحب، GitHub ينفّذ الدمج

عبارة للتذكّر: « إعادة الأساس في الخاص، الدمج في العام. » نعيد أساس ما لنا، وندمج ما هو مشترَك.

↑ العودة إلى الأعلى


6 — اختبار — الدمج وإعادة الأساس

السؤال 1: ماذا يفعل git merge feature من main عندما يكون لـ main أيضاً إيداعات جديدة؟

a) يحذف فرع feature

b) ينشئ إيداع دمج بوالدين

c) يمحو السجل

d) يرفض الدمج دائماً

عرض الحل

الإجابة: b) — هذا دمج ثلاثي: ينشئ Git إيداع دمج يجمع التاريخين.


السؤال 2: ما الأثر الرئيسي لـ git rebase main؟

a) إعادة تشغيل إيداعات الفرع فوق main لسجل خطي

b) استنساخ المستودع

c) حذف main

d) إنشاء نسخة احتياطية بعيدة

عرض الحل

الإجابة: a) — تنقل إعادة الأساس إيداعاتك وتعيد تشغيلها فوق رأس main، فتنتج تاريخاً خطياً.


السؤال 3: لماذا لا تجوز إعادة أساس فرع دُفع ومشترَك؟

a) لأن GitHub يمنع ذلك

b) لأنها تعيد كتابة الإيداعات وتكسر مستودعات الآخرين

c) لأن إعادة الأساس أبطأ

d) لأنها تمحو main

عرض الحل

الإجابة: b) — تنشئ إعادة الأساس SHA جديدة. إن كان الآخرون يملكون تلك الإيداعات، يصبح سجلهم غير متسق.


السؤال 4: ماذا تمثّل العلامات <<<<<<< و ======= و >>>>>>>؟

a) تعليقات في الشفرة

b) خطأ صياغة Python

c) مناطق تعارض تُحَل يدوياً

d) نهاية ملف

عرض الحل

الإجابة: c) — علامات تعارض: فوقها النسخة الحالية (HEAD)، وتحتها النسخة الواردة. نختار ثم نحذفها.


السؤال 5: كيف تلغي دمجاً توقف بسبب تعارضات؟

a) git delete

b) git merge --abort

c) git reset --cloud

d) حذف المجلد .git

عرض الحل

الإجابة: b)git merge --abort (أو git rebase --abort) يعيد المستودع إلى حالته قبل العملية.

↑ العودة إلى الأعلى


7 — تطبيق عملي — حل تعارض دمج

المطلوب

فرعان يعدّلان السطر نفسه في ملف config.txt. أعد إنتاج التعارض، ثم حله مع الإبقاء على المعلومتين مجتمعتين وفق القرار أدناه.

  1. على main، يحتوي الملف port = 8080.
  2. فرع feature/ssl يغيّر هذا السطر إلى port = 443.
  3. في الأثناء، يغيّر main السطر نفسه إلى port = 9090.
  4. ادمج feature/ssl في main، وحل التعارض بالإبقاء على port = 443 (HTTPS)، ثم أنهِ.

التصحيح

bash
# التحضير: إنشاء التعارض
echo "port = 8080" > config.txt
git add config.txt
git commit -m "إعداد أولي"

git switch -c feature/ssl
echo "port = 443" > config.txt
git commit -am "الانتقال إلى HTTPS (المنفذ 443)"

git switch main
echo "port = 9090" > config.txt
git commit -am "تغيير المنفذ إلى 9090"

# محاولة الدمج ← تعارض
git merge feature/ssl

يعرض Git حينها:

text
Auto-merging config.txt
CONFLICT (content): Merge conflict in config.txt
Automatic merge failed; fix conflicts and then commit the result.

يحتوي الملف config.txt:

text
<<<<<<< HEAD
port = 9090
=======
port = 443
>>>>>>> feature/ssl

نحرّر للإبقاء على القيمة الصحيحة فقط:

bash
echo "port = 443" > config.txt   # نحسم لصالح HTTPS

git add config.txt
git commit -m "دمج feature/ssl: الإبقاء على المنفذ 443"

النتيجة المتوقعة :

التحققالأمرالخرج
التعارض محلولgit status« nothing to commit, working tree clean »
المحتوى النهائيcat config.txtport = 443
إيداع الدمجgit log --oneline -1« دمج feature/ssl: الإبقاء على المنفذ 443 »

إن أخطأت أثناء تعارض، يعيد git merge --abort مستودعك سليماً. لا مخاطرة في التجريب.

↑ العودة إلى الأعلى


8 — الخلاصة

النقاط التي يجب تذكّرها

  1. الدمج وإعادة الأساس يجمعان فرعين، لكنهما ينتجان سجلاً مختلفاً.
  2. الدمج يحفظ التاريخ الحقيقي؛ ينشئ إيداع دمج بوالدين (إلا في fast-forward).
  3. إعادة الأساس تعيد تشغيل الإيداعات لسجل خطي ونظيف.
  4. القاعدة الذهبية: إعادة الأساس في الخاص، الدمج في العام — لا تعِد أساس شفرة مشتركة.
  5. التعارض يظهر عندما يُعدَّل السطر نفسه من الجانبين: نحرّر، ننفّذ add، ثم ننهي.
  6. ممارسة جيدة: أعد أساس فرعك قبل طلب السحب، ثم ادمج طلب السحب في main.

ما يلي

تعرف الآن دمج الشفرة تقنياً. الدرس 03 — طلبات السحب يبيّن كيف تطلب مراجعة هذا العمل قبل دمجه، في قلب التعاون على GitHub.

↑ العودة إلى الأعلى


جميع الحقوق محفوظة. يُحظَر نسخ هذه الدورة أو نشرها أو استخدامها أو تكييفها، كلياً أو جزئياً، دون إذن كتابي مسبق من الدكتور هيثم رحومة.

دورة من إعداد الدكتور هيثم رحومة — تطوير ونشر حلول البيانات