DanLevy.net

صراع: Git Rebase مقابل Merge

سؤال خالد...

Hero image for صراع: Git Rebase مقابل Merge

مباراة حاسمة: Git Rebase مقابل (Squash) Merge!

هل يجب علي استخدام Rebase؟ أم Squash Merge؟

لماذا يثير هذا الموضوع حماسة دينية؟

بعض المهندسين يستخدمون معرفة git (والطرفية) كإشارة لمستوى مهاراتهم النسبي. وأي ممارسة مرتبطة بهويتنا/أنايتنا يمكن أن تكون من المستحيل تحليلها بنزاهة، ناهيك عن تغييرها.

عوامل أخرى تشمل على الأرجح الألفة وتحيز البقاء والتي يمكن أن تزيد من غموض تقييمنا وافتراضاتنا.

سؤال رئيسي: ما هو الغرض من git commit؟

  1. هل تقوم بالالتزام مبكرًا وبشكل متكرر؟ باستخدام عقلية “نقطة تفتيش” أو نسخ احتياطي؟
    • حيث يتم تسجيل كل شيء، حتى البدايات الخاطئة والتجارب؟ (مثل git commit -am "Updated deps" && git push، كرر بانتظام)
    • ربما رسائل الالتزام أقل أهمية من الكود بالنسبة لك؟
  2. أم أن التزاماتك هي عمل فني منظم ومنحوت بعناية؟
    • ربما كل التزام هو وحدة عمل مستقلة وذرية؟ (مثل git add package.json && git commit -m "Updated deps")
    • أو ببساطة لا تتحمل سجلات الالتزام “الفوضوية”؟
    • هل تتضمن مراجعات PR الخاصة بك غالبًا مراجعة التزامًا تلو الآخر؟

| 💡 ما هي النماذج العقلية الأخرى التي تحدد كيف ترى الالتزامات؟ من فضلك أخبرني @justsml!

هل تفكر في git بطريقة تحقق أقصى قيمة لك، لفريقك، ولمؤسستك؟

نظرًا لوجود عقليات مختلفة جدًا حول استراتيجية الالتزام، فلا عجب في وجود الكثير من الارتباك حول الطريقة “الصحيحة” لاستخدام git.

السيناريو: إنشاء علامة إصدار منقحة

دعنا نقارن عملية إنشاء علامة إصدار مع استبعاد بعض الالتزامات الأخيرة على main.

إصدار علامة Git من main مع فرعين للميزات

طريقة Rebase

النموذج العقلي: “أريد إنشاء نسخة بديلة من تاريخ موجود. (على سبيل المثال، ارتكبت خطأً قبل 16 دمجًا، وقد أحتاج إلى تحكم دقيق لتصحيحه. أيضًا، قد أعلق في دورة لا نهائية من التعارض و --continue.)”

  1. احصل على آخر التحديثات: git checkout main && git pull
  2. أنشئ فرعًا جديدًا: git checkout -b release/hot-newness-and-stuff
  3. ابدأ rebase تفاعليًا وقم بتضمين مرجع git للمكان الذي تريد العودة إليه في الوقت. git rebase -i HEAD~6 (ملاحظة: HEAD~6 هو اختصار ‘git ref’ لـ 6 التزامات مضت)
  4. أسقط الالتزام (الالتزامات) المطلوب عن طريق تغيير بادئتها إلى drop. احفظ وأغلق المحرر.
  5. أصلح تعارضات الدمج، git add . && git rebase --continue (لا تقم بـ git commit).
  6. كرر الخطوة السابقة حتى الاكتمال.
  7. ضع علامة/ادفع باستخدام العملية الحالية. مثال git tag -a v1.2.3 -m 'Release v1.2.3' && git push --tags

الإيجابيات

السلبيات

طريقة الدمج (السكواش)

النموذج الذهني: “أريد إصدارًا مخصصًا، يبدأ من نقطة معينة، ويتضمن أي فرع (فروع) مرغوب فيه.”

  1. احصل على آخر التحديثات: git checkout main && git pull
  2. أنشئ فرعًا جديدًا: git checkout -b release/hot-newness-and-stuff
  3. ادمج الفروع و/أو الالتزامات المرغوبة: git merge --no-ff feature/hot-newness bug/fix-123 (استخدم العلامة --no-ff حيثما أمكن.)
  4. أصلح أي تعارض دمج (إذا ظهر.)
  5. ضع علامة/ادفع باستخدام العملية الحالية. مثال git tag -a v1.2.3 -m 'Release v1.2.3' && git push --tags

الإيجابيات

السلبيات

الخلاصة

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

على الرغم من أن المستخدمين لإعادة الأساس لديهم بالفعل طرق لحل (أو تجنب) مشاكلهم، تبقى الحقيقة: ستحتاج في النهاية إلى حزام أسود في git fu. (على سبيل المثال، حتى git push البسيط يمكن أن يواجه تعقيدًا إضافيًا: هل كان git push --force أم git push --force-with-lease؟ لماذا تتعامل مع ذلك على الإطلاق؟)

هناك سبب آخر يجعل إعادة الأساس لإنشاء تاريخ منقح ستكون دائمًا في وضع غير مؤات مقارنة بـ git merge .... يسمح git merge لواجهة git CLI بتطبيق خوارزميات متقدمة لتجنب التعارضات من خلال تحليل HEAD لكل فرع.

يمكن أن يكون هذا أكثر ذكاءً لأن كل عملية دمج تهتم فقط بأحدث حالة لكل فرع مرغوب. بينما يجب على إعادة الأساس إعادة تشغيل (أو إسقاط) تاريخ الالتزامات بالتسلسل المحدد. هذا يحد من قدرة git على تحسين الدمج لأنه يقارن فقط التزامين في كل مرة.

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

الملخص