دليل Git الجزء الثاني: القاعدة الذهبية وأساسيات الريبس

دعنا نرى ما يحدث عند تشغيل gase rebase ولماذا تحتاج إلى توخي الحذر. 

هذا هو الثاني و الثالث جزء من دليل جيت من بيير دي وولف بلوق ترجمها Mail.ru سحابة حلول فريق . يمكن قراءة الجزء الأول هنا .

جوهر ريبس


كيف يحدث ريبس بالضبط:


يمكنك القول أن rebase هو إلغاء تثبيت الفرع الذي تريد نقله وربطه بفرع آخر. هذا التعريف صحيح ، ولكن حاول أن تبدو أعمق قليلاً. إذا نظرت إلى الوثائق ، فإليك ما تقوله عن rebase: "تطبيق الأوامر على فرع آخر (إعادة التقديم فوق نصيحة أساسية أخرى)".

الكلمة الرئيسية هنا هي التطبيق ، لأن rebase ليس مجرد نسخ ولصق الفروع إلى فرع آخر. يأخذ Rebase بالتتابع جميع عمليات التنفيذ من الفرع المحدد ويعيد تطبيقها إلى الفرع الجديد.

يؤدي هذا السلوك إلى نقطتين:

  1. من خلال إعادة تطبيق عمليات التنفيذ ، ينشئ Git عمليات تنفيذ جديدة. حتى إذا كانت تحتوي على نفس التغييرات ، فإن Git تعتبر التزامات جديدة ومستقلة.
  2. يلغي git rebase عمليات الإلتزام ولا يحذف تلك القديمة. هذا يعني أنه بعد اكتمال عملية إعادة التشغيل ، سيستمر تخزين عملياتك القديمة في المجلد الفرعي / gjects للمجلد .git. إذا كنت لا تفهم تمامًا كيف يخزن Git وينظر في ارتكابها ، اقرأ الجزء الأول من هذه المقالة.

فيما يلي تفسير أكثر دقة لما يحدث أثناء إعادة التدريب:


كما ترى ، يحتوي فرع الميزات على عمليات جديدة تمامًا. كما ذكرنا سابقًا ، نفس المجموعة من التغييرات ، ولكن كائنات جديدة تمامًا من وجهة نظر Git. 

وهذا يعني أيضًا أنه لم يتم تدمير الالتزامات القديمة. أصبحوا يتعذر الوصول إليهم مباشرة. إذا كنت تتذكر ، فإن الفرع هو مجرد رابط لالتزام. وبالتالي ، إذا لم يكن أي فرع أو علامة تشير إلى تنفيذ ، فلا يمكن الوصول إليه باستخدام Git ، على الرغم من استمرار وجوده على القرص.

الآن دعونا نناقش القاعدة الذهبية.

قاعدة ريبس الذهبية


قاعدة ريبس الذهبية هي: " لا تقم أبداً بإعادة إنشاء فرع مشترك! ". يشير الفرع المشترك إلى الفرع الموجود في مستودع الشبكة والذي يمكن للأشخاص الآخرين العمل معه باستثناءك.

غالبًا ما يتم تطبيق هذه القاعدة دون الفهم الصحيح ، لذلك ، سنقوم بتحليل سبب ظهورها ، خاصة أنها ستساعد على فهم عمل Git بشكل أفضل.

دعونا نلقي نظرة على موقف يكسر فيه المطور القاعدة الذهبية ، وما يحدث في هذه الحالة.

لنفترض أن بوب وآنا يعملان معًا في مشروع. فيما يلي كيف تبدو مستودعات بوب وآنا والمستودع الأصلي على جيثب:


جميع المستخدمين لديهم مستودعات متزامنة مع GitHub.

الآن ، بوب ، يكسر القاعدة الذهبية ، يقوم بعمل استرداد ، وفي نفس الوقت ، تعمل آنا ، التي تعمل في فرع الميزة ، على إنشاء التزام جديد:


هل ترى ماذا سيحدث؟

يحاول بوب تنفيذ تنفيذ دفع ؛ يحصل على رفض شيء من هذا القبيل:


لم يكن Git ناجحًا لأن Git لم يكن يعرف كيفية دمج فرع ميزة Bob مع فرع ميزة GitHub.

الحل الوحيد الذي يسمح لـ Bob بالدفع هو استخدام مفتاح القوة ، الذي يخبر مستودع GitHub لإزالة فرع الميزة وقبول الفرع الذي يدفعه Bob لهذا الفرع. بعد ذلك نحصل على الموقف التالي:


الآن تريد آنا إطلاق تغييراتها ، وهنا ما سيحدث:


هذا أمر طبيعي ، أخبرت جيت آنا أنها ليس لديها نسخة متزامنة من فرع الميزة ، أي أن إصدارها من الفرع وإصدار الفرع في GitHub مختلفان. يجب على آنا إكمال السحب. بنفس الطريقة التي يقوم بها Git بدمج فرع محلي مع فرع في المستودع عند الدفع ، يحاول Git دمج الفرع في المستودع مع فرع محلي عند السحب.

قبل تنفيذ عمليات السحب في الفروع المحلية وفروع GitHub تبدو كما يلي:

A--B--C--D'   origin/feature // GitHub
A--B--D--E    feature        // Anna

عند السحب ، يدمج Git للقضاء على الاختلاف في المستودعات. وهكذا ، ما الذي يؤدي إليه هذا:


Commit M هو التزام دمج. أخيرًا ، تم دمج الفروع المميزة لـ Anna و GitHub بالكامل. تنفست آنا الصعداء ، تم حل جميع النزاعات ، يمكنها أداء دفعة. 

بوب يسحب الآن كل شيء متزامن:


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

إحدى الفوائد العديدة لـ Git هي أنه يمكنك التراجع دون أي مشاكل في أي وقت. ولكن كلما ارتكبت أخطاء أكثر ، كما هو موضح ، كلما كان من الصعب القيام بذلك.

لاحظ أيضًا أن عمليات التكرار المكررة تظهر في مستودع الشبكة. في حالتنا ، D و D '، تحتوي على نفس البيانات. في الواقع ، يمكن أن يكون عدد عمليات التكرار المكررة كبيرًا مثل عدد عمليات التنفيذ في فرعك المعاد إصلاحه.

إذا كنت لا تزال غير مقتنع ، دعنا نقدم Emma ، المطور الثالث. تعمل في فرع الميزة قبل أن يرتكب بوب خطأه ويريد حاليًا الدفع. لنفترض أنه بحلول الوقت الذي دفعت فيه البرنامج النصي الصغير السابق ، تكون قد اكتملت بالفعل. إليك ما يخرج:


أوه ، هذا بوب !!!!

قد يجعلك هذا النص تعتقد أنه يتم استخدام rebase فقط لنقل فرع واحد إلى أعلى فرع آخر. هذا اختياري - يمكنك إعادة التسعير في نفس الفرع.

جمال سحب rebase


كما رأيت أعلاه ، كان من الممكن تجنب مشاكل آنا إذا استخدمت سحب rebase. دعونا ننظر في هذا السؤال بمزيد من التفصيل.

لنفترض أن بوب يعمل في فرع يغادر عن السيد ، فقد تبدو قصته على النحو التالي:




يقرر بوب أن الوقت قد حان للسحب ، الأمر الذي ، كما فهمت بالفعل ، سيؤدي إلى بعض الارتباك. نظرًا لأن مستودع Bob كان يتحرك بعيدًا عن GitHub ، سيسألك Git عما إذا تم الدمج ، وستكون النتيجة على النحو التالي:


يعمل هذا الحل ويعمل بشكل جيد ، ومع ذلك ، قد يكون من المفيد بالنسبة لك معرفة أن هناك حلول أخرى للمشكلة. واحد منهم هو سحب rebase.

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

يبدو الأمر معقدًا ، لذلك نوضح:

  1. يهتم Git فقط بالالتزامات الموجودة في مستودعك والشبكة:

    يبدو وكأنه استنساخ محلي لمستودع GitHub.
  2. الالتزامات المحلية لـ Git rebase:


كما تتذكر ، عندما يقوم تطبيق rebase Git بتنفيذ واحد تلو الآخر ، أي في هذه الحالة يتم تطبيق الالتزام الرئيسي E ، ثم F. إلى نهاية الفرع. والنتيجة هي rebase لنفسه. تبدو جيدة ، ولكن السؤال الذي يطرح نفسه - لماذا تفعل ذلك؟

في رأيي ، أكبر مشكلة في دمج الفروع هي أن تاريخ الالتزامات ملوث. لذلك ، فإن سحب الريباس هو حل أكثر أناقة. سأذهب أبعد من ذلك وأقول أنه عندما تحتاج إلى تنزيل أحدث التغييرات على الفرع الخاص بك ، يجب عليك دائمًا استخدام سحب rebase. ولكن عليك أن تتذكر: نظرًا لأن rebase يطبق كل عمليات التنفيذ بدوره ، عندما تقوم بإعادة ضبط 20 عملية ، فقد تضطر إلى حل 20 تعارضًا واحدًا تلو الآخر. 

بشكل عام ، يمكنك استخدام النهج التالي: تغيير واحد كبير تم إجراؤه منذ وقت طويل هو الدمج ، وتغييران صغيران تم إجراؤهما مؤخرًا عبارة عن سحب للخلف.

قوة ريبس على


لنفترض أن سجل الالتزام يبدو كما يلي:




لذلك تريد إعادة تسمية فرع الميزة 2 إلى الفرع الرئيسي. إذا قمت بإجراء عملية استرداد عادية في الفرع الرئيسي ، فاحصل على هذا:


من غير المنطقي وجود التزام D في كلا الفرعين: في الميزة 1 والميزة 2. إذا قمت بنقل فرع الميزة 1 إلى نهاية الفرع الرئيسي ، فقد اتضح أن الالتزام D سيتم تطبيقه مرتين.

لنفترض أنك بحاجة إلى الحصول على نتيجة مختلفة:


لتنفيذ مثل هذا السيناريو ، git rebase في هو بالضبط ما هو المقصود.

أولاً ، اقرأ الوثائق:

SYNOPSIS
       git rebase [-i | --interactive] [<options>] [--exec <cmd>]
               [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
       git rebase [-i | --interactive] [<options>] [--exec <cmd>] 
[--onto <newbase>]
               --root [<branch>]
       git rebase (--continue | --skip | --abort | --quit | --edit-todo 
| --show-current-patch)


نحن مهتمون بهذا:

OPTIONS
       --onto <newbase>
          Starting point at which to create the new commits. If the 
--onto option is not specified, the starting point is <upstream>. May be 
any valid commit, and not just an existing branch name.


استخدم هذا الخيار للإشارة عند أي نقطة لإنشاء عمليات تنفيذ جديدة.

إذا لم يتم تحديد هذا الخيار ، فسيصبح المنبع نقطة البداية.

من أجل الفهم ، سأعطي صورة أخرى:

A--B--C        master
    \
     D--E      feature1
         \
          F--G feature2

Here we want to rebase feature2 to master beginning from feature1
                           |                                |
                        newbase                         upstream


أي أن الفرع الرئيسي هو newbase ، والفرع 1 ميزة هو المنبع.

وبالتالي ، إذا كنت ترغب في الحصول على النتيجة كما في الشكل الأخير ، فيجب عليك تشغيل git rebase --onto master feature1 في فرع feature2.

حظا طيبا وفقك الله

تمت الترجمة بدعم من Mail.ru Cloud Cloud Solutions .

ماذا تقرأ عن هذا الموضوع :

  1. الجزء الأول من دليل Git.
  2. سنتي الثانية كمطور مستقل .
  3. قناة برقية لدينا حول التحول الرقمي


All Articles