تخطَّ إلى المحتوى

الفروع في Git: branch و switch و merge

الدرس 4 من 10 · Git و GitHub

موقعك يعمل جيداً على الفرع main، وتريد إضافة صفحة جديدة. لكن ماذا لو كسرت شيئاً أثناء العمل؟ أو احتجت إصلاح خطأ عاجل في منتصف عملك على الصفحة؟ الحل: الفروع (Branches). كل فرع خط عمل مستقل، تجرّب فيه بحرية، ثم تدمجه في الخط الأساسي عندما يجهز. وهذه أكثر ميزة يحبها المبرمجون في Git.

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

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

نكمل على مستودع my-site من الدرس السابق:

نافذة طرفيّة
git branch
الناتج
* main

النجمة * تشير للفرع الحالي. لننشئ فرعاً لصفحة «اتصل بنا»:

نافذة طرفيّة
git branch contact-page
git branch
الناتج
contact-page
* main

الفرع أُنشئ، لكننا ما زلنا على main.

التنقل بين الفروع: git switch

Section titled “التنقل بين الفروع: git switch”
نافذة طرفيّة
git switch contact-page
الناتج
Switched to branch 'contact-page'

الآن ننشئ contact.html ونحفظه:

نافذة طرفيّة
git add contact.html
git commit -m "إضافة صفحة اتصل بنا"

ثم نعود لـ main:

نافذة طرفيّة
git switch main
ls
الناتج
README.md
index.html

أين ذهب contact.html؟! إنه موجود بأمان في فرع contact-page. عند التنقل بين الفروع، يغيّر Git الملفات في مجلدك لتطابق الفرع الذي انتقلت إليه. هذا هو الاستقلال الحقيقي بين الفروع.

اختصار مفيد: git switch -c dark-mode تنشئ الفرع وتنتقل إليه في خطوة واحدة.

صفحة «اتصل بنا» جاهزة، فلندمجها في main. انتقل أولاً للفرع الذي تريد الدمج فيه، ثم ادمج:

نافذة طرفيّة
git switch main
git merge contact-page
الناتج
Updating 1af0b70..2d680ed
Fast-forward
contact.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 contact.html

Fast-forward (تقديم سريع): بما أن main لم يتغير منذ التفرّع، اكتفى Git بتحريك مؤشر main للأمام ليشمل النقاط الجديدة. أبسط أنواع الدمج.

لكن ماذا لو تغيّر الفرعان معاً؟ في فرع dark-mode أضفنا ملف style.css، وفي نفس الوقت تقدّم main بدمج صفحة الاتصل. الآن:

نافذة طرفيّة
git merge dark-mode -m "دمج الوضع الليلي"
git log --oneline --graph
الناتج
* beb7ec5 دمج الوضع الليلي
|\
| * a9d945f إضافة الوضع الليلي
* | 2d680ed إضافة صفحة اتصل بنا
|/
* 1af0b70 تجاهل الملفات السرية
* 4abe678 إضافة فقرة ترحيب
* c8ef559 إضافة الصفحة الرئيسية وملف README

هنا أنشأ Git نقطة دمج (Merge Commit) جديدة تجمع الخطين. و --graph يرسم التاريخ: ترى الخطين يفترقان ثم يلتقيان. جمال Git: كل فرع عدّل ملفات مختلفة، فدمجهما آلياً دون أي مشكلة.

نافذة طرفيّة
git branch -d contact-page
الناتج
Deleted branch contact-page (was 2d680ed).

الفرع أدى مهمته، وتعديلاته أصبحت في main، فلا داعي لبقائه. والخيار -d آمن: يرفض حذف فرع لم يُدمج بعد.

ماذا لو عدّل فرعان نفس السطر في نفس الملف بطريقتين مختلفتين؟ في فرع title-a غيّرنا العنوان إلى «موقعي الجديد»، وفي main غيّرناه إلى «موقع سارة»:

نافذة طرفيّة
git merge title-a
الناتج
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git لا يستطيع أن يقرر بدلاً منك أي عنوان هو الصحيح! فيضع العلامات في الملف ويطلب منك القرار:

index.html
<<<<<<< HEAD
<h1>موقع سارة</h1>
=======
<h1>موقعي الجديد</h1>
>>>>>>> title-a
<p>أهلاً بك</p>
  • بين <<<<<<< HEAD و =======: نسخة الفرع الحالي (main).
  • بين ======= و >>>>>>> title-a: نسخة الفرع القادم.

لحل التعارض:

  1. افتح الملف، واحذف العلامات الثلاث، واترك النص الصحيح. يمكنك اختيار إحدى النسختين، أو كتابة نسخة جديدة تجمع الاثنتين، مثل «موقع سارة الجديد».
  2. احفظ الملف، ثم git add index.html.
  3. أنهِ الدمج بـ git commit -m "حل التعارض في العنوان".

تخيّل التعارض مثل محررَين عدّلا نفس الجملة في كتاب بطريقتين مختلفتين: لا بد أن يقرر رئيس التحرير الصيغة النهائية. و VS Code يعرض التعارض بألوان وأزرار مثل «Accept Current» و«Accept Incoming» تسهّل عليك الاختيار.

  1. في مستودعك، أنشئ فرعاً اسمه about-page وانتقل إليه بأمر واحد.
  2. أضف صفحة about.html واحفظها، ثم عد إلى main ولاحظ اختفاءها.
  3. ادمج الفرع في main، واحذفه.
  4. اصنع تعارضاً عن قصد: أنشئ فرعين يعدّلان نفس السطر بطريقتين، وادمجهما، ثم حل التعارض.
  5. اعرض التاريخ بـ git log --oneline --graph.
  • الدمج وأنت على الفرع الخطأ: git merge تدمج في الفرع الحالي. انتقل لـ main أولاً.
  • نسيان العلامات في الملف بعد حل التعارض: تبقى <<<<<<< في الكود فيتعطل. ابحث عنها قبل الحفظ.
  • التنقل بين الفروع مع تعديلات غير محفوظة: قد يرفض Git أو تنتقل التعديلات معك. احفظها بـ commit قبل التنقل.

سؤال

أي أمر ينشئ فرعاً جديداً اسمه feature وينتقل إليه مباشرة؟

سؤال

متى يحدث التعارض (Conflict) عند الدمج؟

  • الفرع خط عمل مستقل وخفيف، تجرّب فيه دون التأثير على main.
  • git branch يعرض وينشئ، و git switch ينقلك، و git switch -c ينشئ وينقل.
  • git merge يدمج فرعاً في الفرع الحالي: تقديم سريع، أو نقطة دمج جديدة.
  • git branch -d يحذف الفرع المدمج بأمان.
  • التعارض: Git يضع العلامات، وأنت تختار النتيجة، ثم add و commit.