الوحدة 2 · الفروع والدمج
حلّ تعارضات الدمج خطوة بخطوة
17 دقراءة 4 درتّب الخطوات
الدرس في لمحة
اقرأ تعارض الدمج بهدوء، وحرّر علامات التعارض حتى تصل إلى النتيجة التي تريدها، وعلّم الملفات بأنها حُلّت وأكمل الدمج، أو ألغِه وابدأ من جديد.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
عاجلًا أو آجلًا سيغيّر فرعان السطر نفسه. تغيّر سطر التعريف (tagline) على main إلى “Front-end developer in Lagos.”، بينما فرعك tagline الذي بدأته في وقت سابق أعاد كتابة السطر نفسه إلى “Front-end developer who loves accessible UI.”. لا يستطيع Git أن يعرف أيهما الصحيح، فيتوقّف ويسأل. هذا كل ما في تعارض الدمج (merge conflict): سؤال. ساعدت مئات الأشخاص في تعارضهم الأول، والذعر يأتي دائمًا من العلامات غير المألوفة، لا من المشكلة نفسها.
ما يخبرك به Git
git switch main
git merge taglineAuto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.أنت الآن في منتصف دمج. الملفات التي اندمجت بلا مشكلة مجهّزة أصلًا. شغّل git status لترى البقية:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")اقرأ هذا الناتج؛ ففيه الإجراء كاملًا. أصلح التعارضات، وعلّم كل ملف بأنه حُلّ بـ git add، ثم git commit. أو ألغِ الدمج.
قراءة العلامات
افتح index.html. كتب Git النسختين كلتيهما في الملف، محاطتين بعلامات:
<h1>Maya Okafor</h1>
<<<<<<< HEAD
<p>Front-end developer in Lagos.</p>
=======
<p>Front-end developer who loves accessible UI.</p>
>>>>>>> tagline- النصف العلوي، من العلامة الافتتاحية التي تحمل الاسم
HEADحتى=======، هو طرفك: الفرع الذي أنت عليه، وهو هناmain. - النصف السفلي، من
=======حتى العلامة الختامية التي تحمل الاسمtagline، هو طرفهم: الفرع الذي تدمجه.
كل ما هو خارج العلامات اندمج دون مشكلة. وقد يحتوي الملف عدة كتل من هذا النوع، فابحث في الملف عن العلامة الافتتاحية (سبعة رموز < متتالية) حتى لا يبقى منها شيء.
الحلّ خطوة بخطوة
1. قرّر ما يجب أن تكون عليه النتيجة. ليس «أيّ الطرفين يفوز» كردّ فعل تلقائي، بل ما الذي يجب أن تقوله الصفحة فعلًا؟ غالبًا تكون النتيجة مزيجًا. وهنا المعلومتان كلتاهما جيدتان:
<h1>Maya Okafor</h1>
<p>Front-end developer in Lagos who loves accessible UI.</p>2. أزل كل العلامات. يجب أن تختفي أسطر العلامات الثلاثة. لا يقرأ Git الملف ليتحقّق؛ هذه مهمّتك أنت.
3. افحص النتيجة. افتح الصفحة في المتصفّح، وشغّل اختباراتك (npm test حين تصبح للموقع اختبارات)، وشغّل:
git diff --checkينبّهك إلى أي علامات تعارض متبقّية. خمس ثوانٍ في محلّها.
4. علّمه بأنه حُلّ وأكمل.
git add index.html
git status # "All conflicts fixed but you are still merging."
git commit # editor opens with "Merge branch 'tagline'"; save and closeالأمر git merge --continue يفعل ما يفعله git commit الأخير هذا. والـ merge commit الآن له أبوان، كأي merge commit آخر.
وإن كنت تعرف أن أحد الطرفين يجب أن يفوز في ملف كامل، فتجاوز التحرير: git restore --ours index.html يحتفظ بنسخة فرعك، و git restore --theirs index.html يحتفظ بالنسخة القادمة. ثم نفّذ git add كالمعتاد.
الانسحاب
إن كان التعارض أكبر مما توقّعت، أو دمجت الفرع الخطأ، تستطيع دائمًا التراجع:
git merge --abortيعود فرعك والـ index وملفاتك تمامًا إلى ما كانت عليه قبل git merge. لا يضيع شيء. وكثيرًا ما يكون من الحكمة أن تلغي، ثم تحدّث الفرع أو ترتّبه، وتحاول من جديد بذهن صافٍ.
العلامات نفسها وروتين «أصلِح ثم add ثم أكمل» نفسه يظهران كلما جمع Git نسختين من سطر واحد: أثناء الـ rebase، وحين تطبّق stash، وحين يدمج git pull عمل شخص آخر في عملك. تعلّم الروتين مرة واحدة هنا، وسيبدو كل تعارض لاحق في هذا الكورس مألوفًا. ما يتغيّر فقط هو الأمر الذي تستخدمه للإكمال أو الإلغاء.
جعل التعارضات أسهل في القراءة
افتراضيًا ترى الطرفين فقط. اطلب من Git أن يعرض الأسطر الأصلية أيضًا:
git config --global merge.conflictStyle zdiff3الآن لكل تعارض قسم ثالث بين ||||||| و ======= يعرض الـ merge base. رؤية ما كان عليه السطر قبل أيّ من التغييرين تجعل الجواب الصحيح واضحًا في الغالب: ترى ما قصده كل طرف، لا ما انتهى إليه فقط.
المحرّرات تساعد أيضًا. يميّز VS Code كل كتلة بأزرار مثل Accept Current Change و Accept Incoming Change و Accept Both Changes، إضافة إلى محرّر دمج ثلاثي. استخدمها، لكن اقرأ النتيجة؛ فـ Accept Both كثيرًا ما ينتج وسمَي <p> حيث أردت واحدًا.
الدمج طريقة واحدة لجمع السجلّات. في الدرس التالي ستتعرّف على الطريقة الأخرى، الـ rebase، والقاعدة الوحيدة التي تُبقيه آمنًا.
أهم النقاط
- التعارض يعني أن الفرعين غيّرا الأسطر نفسها منذ الـ merge base، فيطلب منك Git أن تختار؛ لا شيء ضاع ولا شيء تعطّل.
- ما بين
<<<<<<<و=======هو فرعك الحالي (HEAD)؛ وما بين=======و>>>>>>>هو الفرع الذي يُدمج. - تحلّ التعارض بتحرير الملف إلى شكله النهائي، وإزالة كل العلامات، ثم
git addللملف وgit commit. git merge --abortيعيد كل شيء تمامًا كما كان قبل بدء الدمج.- ضبط
merge.conflictStyleعلىzdiff3يعرض الأسطر الأصلية أيضًا، وهذا يجعل الحكم على معظم التعارضات سهلًا.