٥، ١٣، رعاية مشروع
 — دمج المساهمات

عندما يكون كل ما في فرع موضوعك جاهزًا لدمجه في فرع من الفروع العامة، يكون السؤال: كيف؟ ثم ما الأسلوب العام الذي تريده لرعاية مشروعك؟ أمامك عدة خيارات، وسنتناول بضعًا منهم.

أساليب الدمج

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

مثلا لدينا مستودعٌ فرعه الرئيس master وفيه أعمال في فرعين اسمهما ruby_client و php_client مثل شكل تاريخ فيه فرعا موضوعين، فإذا دمجنا ruby_client ثم php_client، سيبدو التاريخ مثل شكل بعد دمج فرعيْ الموضوعين.

تاريخ فيه فرعا موضوعين
شكل ٧٢. تاريخ فيه فرعا موضوعين
بعد دمج فرعيْ الموضوعين
شكل ٧٣. بعد دمج فرعيْ الموضوعين

ربما هذا أيسر أسلوب تطوير. لكنه قد يصعّب الأمور في المشروعات الكبيرة أو شديدة الاستقرار التي تحتاج أن تحرص أشد الحرص قبل أن تدمج شيئا فيها.

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

قبل دمج فرع موضوع
شكل ٧٤. قبل دمج فرع موضوع
بعد دمج فرع موضوع
شكل ٧٥. بعد دمج فرع موضوع
بعد إصدار المشروع
شكل ٧٦. بعد إصدار المشروع

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

أساليب الدمج الكثير

في مشروع مصدر جت أربعة فروع طويلة العمر: master و next و seen (سابقًا pu = «تحديثات مقترحة»)، و maint لحمل الإصلاحات إلى الإصدارات القديمة (backports). عند المساهمة، فإن المساهمات تُجمع في فروع موضوعات في مستودع المشرف بطريقة تشبه ما شرحنا سابقا (انظر إدارة مجموعة كبيرة من المساهمات المتوازية في فروع موضوعات). عندئذٍ تُقيَّم موضوعات المساهمات لتحديد صلاحيتها وصحتها، أم أنها تحتاج عملًا. فإذا كانت صالحة فإنها تدمج في next ويُدفع هذا الفرع إلى المستودع العمومي ليجرب الجميع الموضوعات المدموجة كلها معًا.

إدارة مجموعة كبيرة من المساهمات المتوازية في فروع موضوعات
شكل ٧٧. إدارة مجموعة كبيرة من المساهمات المتوازية في فروع موضوعات

وإذا كانت الموضوعات تحتاج عملًا فإنها تدمج في فرع seen. وعندما يتقرر أنها مستقرة تماما، فإنها تدمج في master. ثم يعاد تأسيس الفرعين next و seen على master الجديد. هذا يعني أن master يتحرك إلى الأمام دائما أو شبه دائما، وأن next يعاد تأسيسه أحيانا، وأن seen يعاد تأسيسه أكثر من ذلك.

دمج مساهمات فروع الموضوعات في فروع دمج طويلة الأمد
شكل ٧٨. دمج مساهمات فروع الموضوعات في فروع دمج طويلة الأمد

عندما يُدمج فرع موضوع في master أخيرًا، فإنه يحذف من المستودع. وكذلك في مشروع مصدر جت فرع maint، الذي يُشتقّ من آخر إصدارة ليتيح رُقَع للإصدارات القديمة إن دعت الحاجة إلى إصدارة صيانة. لذا فإنك عندما تستنسخ مستودع جت فإنك تجد أربعة فروع يمكنك سحبها لفحص المشروع في حالاته المختلفة من التطوير، حسب حماسك للأحدث أو حسب رغبتك في المساهمة. وللمشرف أسلوب منظم يساعده في تدقيق المساهمات الجديدة. لمشروع جت أسلوب تطوير مخصص. لتفهمه بوضوح أشد، انظر دليل مشرف جت (بالإنجليزية).

أساليب الاصطفاء وإعادة التأسيس

يحب مشرفون آخرون إعادة تأسيس المساهمات (rebase) على فرعهم الرئيس أو اصطفائها (cherry-pick)، بدلًا من دمجها فيه، ليبقوا تاريخ الإيداعات خطيًّا قدر الإمكان. فإذا عملت في فرع موضوع ورأيت أن تدمجه، فانتقل إلى هذا الفرع ونفّذ أمر إعادة التأسيس فيه لإعادة صناعة إيداعاته على الفرع الرئيس. فإذا تم هذا بنجاح، فيمكنك تسريع فرعك الرئيس، وسيكون تاريخ مشروعك خطيًّا.

والطريقة الأخرى لنقل تغييرات من فرع إلى آخر هي باصطفائه (cherry-pick). فالاصطفاء في جت هو مثل إعادة التأسيس لكن لإيداع وحيد. فإنه يتناول رقعة إيداع سابق ويحاول تطبيقها على الفرع الحالي. يفيد هذا إذا كان لديك عددٌ من الإيداعات في فرع موضوع وتريد دمج واحدٍ فقط منها، أو عندك إيداعٌ واحد فقط في فرع موضوع وترى أن اصطفاءه خيرٌ من إعادة تأسيسه. للمثال، قل إن لديك مشروعا مثل هذا:

مثال تاريخ قبل الاصطفاء (cherry-pick)
شكل ٧٩. مثال تاريخ قبل الاصطفاء (cherry-pick)

فإذا أردت جذب الإيداع e43a6 إلى فرع master، فيمكنك تنفيذ هذا وأنت في الفرع الهدف master:

$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
 3 files changed, 17 insertions(+), 3 deletions(-)

هذا يجذب تغييرات الإيداع e43a6 نفسها، لكن بإيداع جديد وبصمة جديدة لأن تاريخ تطبيقها مختلف. عندئذٍ سيبدو تاريخك هكذا:

التاريخ بعد اصطفاء إيداع من فرع موضوع
شكل ٨٠. التاريخ بعد اصطفاء إيداع من فرع موضوع

يمكنك عندئذٍ إزالة فرع الموضوع وهجر إيداعاته التي لم تردها.

معاودة مصالحة مسجلة (rerere)

إذا كنت كثير الدمج وإعادة التأسيس، أو فروع موضوعاتك طويلة العمر، ففي جت وسيلة نافعة اسمها ‪“rerere”‬.

إن ‪“rerere”‬ اختصار ‪“reuse recorded resolution”‬ أي «إعادة تطبيق الحل المسجل للنزاع». وهي لتقليل الجهد اليدوي في حل النزاعات. فعند تمكينها، سيلتقط جت صورة من المشروع عند حدوث نزاع وصورة بعد حله، وإن لمح جت هذا النزاع مرة أخرى فسيصلحه لك من نفسه كما أصلحته أنت أول مرة تماما.

هذه الميزة جزءان: إعداد تهيئة، وأمر. فأما الإعداد فهو rerere.enabled، وهو صغير ويسهل إضافته إلى تهيئة جت العامة في نظامك:

$ git config --global rerere.enabled true

فمن الآن، وقتما واجهت نزاع دمج وحللته وأودعت، فسيسجل جت الحل إن احتجته في المستقبل.

وإن احتجت التعامل مع ذاكرة «مُعاودة المُصالحات المُسجلة»، فاستعمل الأمر git rerere. فعند تنفيذه منفردًا (بغير معاملات)، فإن جت ينظر في ذاكرة حلول النزاعات ويبحث عن ما يطابق النزاع الحالي ويحله (ولكن هذا يحدث تلقائيا إذا كان rerere.enabled بـ true). ولهذا الأمر أوامر فرعية لرؤية ما سيسجل، ولحذف حل نزاع معين، ولمسح ذاكرة الحلول كلها. سنفصّل الحديث عن هذا كله في فصل معاودة مصالحة مسجلة (rerere) في الباب السابع.