| # | القسم |
|---|---|
| 1 | جمع فرعين: الحاجة |
| 2 | الدمج (merge) |
| 3 | إعادة الأساس (rebase) |
| 4 | حل التعارضات |
| 5 | الدمج أو إعادة الأساس: ماذا نختار؟ |
| 6 | اختبار — الدمج وإعادة الأساس |
| 7 | تطبيق عملي — حل تعارض دمج |
| 8 | الخلاصة |
عملت على فرع feature، والشفرة جاهزة. يجب الآن إعادة دمجها في main. يوفّر Git آليتين لذلك: الدمج (merge) وإعادة الأساس (rebase).
كلاهما يبلغ الغاية نفسها — جمع العمل — لكن بـ شكل سجل مختلف. هذا جوهر الدرس.
| الآلية | الفكرة في جملة |
|---|---|
| Merge | ننشئ إيداعاً يربط الفرعين، مع الإبقاء على تاريخهما كما هو. |
| Rebase | نعيد تشغيل إيداعات فرع فوق فرع آخر، كأن العمل بدأ لاحقاً. |
قبل أي دمج، نتأكد من أحدث نسخة:
git switch main
git pull origin mainالأمر git merge يجمع فرعاً في فرع آخر. هناك حالتان.
الحالة 1 — دمج سريع (fast-forward) : إذا لم يتحرك main منذ إنشاء الفرع، يتقدّم Git بالمؤشر فقط. لا يُنشأ أي إيداع دمج.
الحالة 2 — دمج ثلاثي (three-way merge) : إذا استقبل main إيداعات جديدة في الأثناء، ينشئ Git إيداع دمج له والدان.
# الانتقال إلى الفرع الهدف ثم الدمج
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 أثراً صريحاً للفرع المدمَج.
ينقل git rebase إيداعات فرعك لـ يعيد تشغيلها فوق رأس فرع آخر. النتيجة: سجل خطي، كأنك بدأت العمل بعد آخر إيداعات main.
قبل إعادة الأساس :
بعد git rebase main (يُعاد تشغيل الإيداعين B و C بعد D) :
# على فرع 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).
يحدث تعارض عندما لا يستطيع Git القرار تلقائياً: فرعان عدّلا السطر نفسه في الملف نفسه. يتوقف Git ويطلب منك الحسم.
يدرج Git علامات تعارض في الملف :
<<<<<<< HEAD
prix = 10 # version de main
=======
prix = 12 # version de feature
>>>>>>> feature/panierالحل خطوة بخطوة :
<<<<<<< و ======= و >>>>>>>.git add.# عرض الملفات المتعارضة
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 لحل تعارض وقع أثناء إعادة أساس. أي أمرين ينهيان العملية؟
git add app.py
git rebase --continue(لدمج، يكون git add app.py ثم git commit.)
كلاهما يجمع العمل، لكنهما ينتجان سجلاً مختلفاً. الاختيار غالباً اتفاق فريق.
| الجانب | الدمج | إعادة الأساس |
|---|---|---|
| السجل | أمين، متفرع | خطي، نظيف |
| إيداع دمج | نعم (إن لم يكن fast-forward) | لا |
| يعيد كتابة التاريخ | لا | نعم (SHA جديدة) |
| آمن على فرع مشترَك | نعم | لا |
مقروئية log | أكثف | أوضح |
الممارسة الموصى بها الأكثر شيوعاً :
main قبل فتح طلب سحب ← سجل نظيف.main ← أثر واضح للدمج.# 1. تنظيف الفرع المحلي قبل طلب السحب
git switch feature/x
git rebase main
# 2. بعد الموافقة على طلب السحب، GitHub ينفّذ الدمجعبارة للتذكّر: « إعادة الأساس في الخاص، الدمج في العام. » نعيد أساس ما لنا، وندمج ما هو مشترَك.
السؤال 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) يعيد المستودع إلى حالته قبل العملية.
فرعان يعدّلان السطر نفسه في ملف config.txt. أعد إنتاج التعارض، ثم حله مع الإبقاء على المعلومتين مجتمعتين وفق القرار أدناه.
main، يحتوي الملف port = 8080.feature/ssl يغيّر هذا السطر إلى port = 443.main السطر نفسه إلى port = 9090.feature/ssl في main، وحل التعارض بالإبقاء على port = 443 (HTTPS)، ثم أنهِ.# التحضير: إنشاء التعارض
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 حينها:
Auto-merging config.txt
CONFLICT (content): Merge conflict in config.txt
Automatic merge failed; fix conflicts and then commit the result.يحتوي الملف config.txt:
<<<<<<< HEAD
port = 9090
=======
port = 443
>>>>>>> feature/sslنحرّر للإبقاء على القيمة الصحيحة فقط:
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.txt | port = 443 |
| إيداع الدمج | git log --oneline -1 | « دمج feature/ssl: الإبقاء على المنفذ 443 » |
إن أخطأت أثناء تعارض، يعيد
git merge --abortمستودعك سليماً. لا مخاطرة في التجريب.
add، ثم ننهي.main.تعرف الآن دمج الشفرة تقنياً. الدرس 03 — طلبات السحب يبيّن كيف تطلب مراجعة هذا العمل قبل دمجه، في قلب التعاون على GitHub.
جميع الحقوق محفوظة. يُحظَر نسخ هذه الدورة أو نشرها أو استخدامها أو تكييفها، كلياً أو جزئياً، دون إذن كتابي مسبق من الدكتور هيثم رحومة.
دورة من إعداد الدكتور هيثم رحومة — تطوير ونشر حلول البيانات