صراع: Git Rebase مقابل Merge
سؤال خالد...
مباراة حاسمة: Git Rebase مقابل (Squash) Merge!
هل يجب علي استخدام Rebase؟ أم Squash Merge؟
- هل هو تفضيل شخصي؟
- الإجابة: ليس عندما تكون هناك فريق واحد أو أكثر! أي خيار سيؤثر على قابلية الاستخدام للآخر!
لماذا يثير هذا الموضوع حماسة دينية؟
بعض المهندسين يستخدمون معرفة git (والطرفية) كإشارة لمستوى مهاراتهم النسبي. وأي ممارسة مرتبطة بهويتنا/أنايتنا يمكن أن تكون من المستحيل تحليلها بنزاهة، ناهيك عن تغييرها.
عوامل أخرى تشمل على الأرجح الألفة وتحيز البقاء والتي يمكن أن تزيد من غموض تقييمنا وافتراضاتنا.
سؤال رئيسي: ما هو الغرض من git commit؟
- هل تقوم بالالتزام مبكرًا وبشكل متكرر؟ باستخدام عقلية “نقطة تفتيش” أو نسخ احتياطي؟
- حيث يتم تسجيل كل شيء، حتى البدايات الخاطئة والتجارب؟ (مثل
git commit -am "Updated deps" && git push، كرر بانتظام) - ربما رسائل الالتزام أقل أهمية من الكود بالنسبة لك؟
- حيث يتم تسجيل كل شيء، حتى البدايات الخاطئة والتجارب؟ (مثل
- أم أن التزاماتك هي عمل فني منظم ومنحوت بعناية؟
- ربما كل التزام هو وحدة عمل مستقلة وذرية؟ (مثل
git add package.json && git commit -m "Updated deps") - أو ببساطة لا تتحمل سجلات الالتزام “الفوضوية”؟
- هل تتضمن مراجعات PR الخاصة بك غالبًا مراجعة التزامًا تلو الآخر؟
- ربما كل التزام هو وحدة عمل مستقلة وذرية؟ (مثل
| 💡 ما هي النماذج العقلية الأخرى التي تحدد كيف ترى الالتزامات؟ من فضلك أخبرني @justsml!
هل تفكر في git بطريقة تحقق أقصى قيمة لك، لفريقك، ولمؤسستك؟
نظرًا لوجود عقليات مختلفة جدًا حول استراتيجية الالتزام، فلا عجب في وجود الكثير من الارتباك حول الطريقة “الصحيحة” لاستخدام git.
السيناريو: إنشاء علامة إصدار منقحة
دعنا نقارن عملية إنشاء علامة إصدار مع استبعاد بعض الالتزامات الأخيرة على main.
طريقة Rebase
النموذج العقلي: “أريد إنشاء نسخة بديلة من تاريخ موجود. (على سبيل المثال، ارتكبت خطأً قبل 16 دمجًا، وقد أحتاج إلى تحكم دقيق لتصحيحه. أيضًا، قد أعلق في دورة لا نهائية من التعارض و --continue.)”
- احصل على آخر التحديثات:
git checkout main&&git pull - أنشئ فرعًا جديدًا:
git checkout -b release/hot-newness-and-stuff - ابدأ rebase تفاعليًا وقم بتضمين مرجع git للمكان الذي تريد العودة إليه في الوقت.
git rebase -i HEAD~6(ملاحظة:HEAD~6هو اختصار ‘git ref’ لـ6 التزامات مضت) - أسقط الالتزام (الالتزامات) المطلوب عن طريق تغيير بادئتها إلى
drop. احفظ وأغلق المحرر. - أصلح تعارضات الدمج،
git add .&&git rebase --continue(لا تقم بـgit commit). - كرر الخطوة السابقة حتى الاكتمال.
- ضع علامة/ادفع باستخدام العملية الحالية. مثال
git tag -a v1.2.3 -m 'Release v1.2.3'&&git push --tags
الإيجابيات
- 🔌 قوة مطلقة. يمكنك تغيير التاريخ.
السلبيات
- 😰 قوة مطلقة. يمكنك تغيير التاريخ. (حسنًا، إيجابية وسلبية…)
- 🔂 قد ينتهي بك الأمر في دورة لا نهائية من التعارضات و
—-continue. (أحيانًا حتى معgit rerere) - 🙀 يكسر ميزات التعاون الرئيسية: تعليقات PR المفقودة/اليتيمة. وقاحة.
- 🖇️ الروابط الدائمة قد لا تكون دائمة جدًا.
طريقة الدمج (السكواش)
النموذج الذهني: “أريد إصدارًا مخصصًا، يبدأ من نقطة معينة، ويتضمن أي فرع (فروع) مرغوب فيه.”
- احصل على آخر التحديثات:
git checkout main&&git pull - أنشئ فرعًا جديدًا:
git checkout -b release/hot-newness-and-stuff - ادمج الفروع و/أو الالتزامات المرغوبة:
git merge --no-ff feature/hot-newness bug/fix-123(استخدم العلامة--no-ffحيثما أمكن.) - أصلح أي تعارض دمج (إذا ظهر.)
- ضع علامة/ادفع باستخدام العملية الحالية. مثال
git tag -a v1.2.3 -m 'Release v1.2.3'&&git push --tags
الإيجابيات
- 💪 عملية أقل، تعارضات أقل بشكل عام، ويستخدم المعرفة الحالية بأوامر git.
- 🚀 يتيح لك التفكير على مستوى PR/فرع أعلى، متجاهلاً التفاصيل الدقيقة لمستوى الالتزام (إلا إذا لزم الأمر.)
- 🦺 غير مدمر. يمكنك العودة و/أو إنشاء فروع جديدة في أي وقت.
- 🎥 يترك الالتزامات والرسائل الحالية كما هي، مما يؤدي إلى تقليل ضوضاء ‘اللوم’.
السلبيات
- 🔏 أصعب في تغيير رسائل الالتزام.
- 🤐 أصعب في إخفاء عملك.
الخلاصة
في النهاية، العملية الأبسط ذات المخاطر الأقل هي التي يجب أن تنتصر.
على الرغم من أن المستخدمين لإعادة الأساس لديهم بالفعل طرق لحل (أو تجنب) مشاكلهم، تبقى الحقيقة: ستحتاج في النهاية إلى حزام أسود في git fu. (على سبيل المثال، حتى git push البسيط يمكن أن يواجه تعقيدًا إضافيًا: هل كان git push --force أم git push --force-with-lease؟ لماذا تتعامل مع ذلك على الإطلاق؟)
هناك سبب آخر يجعل إعادة الأساس لإنشاء تاريخ منقح ستكون دائمًا في وضع غير مؤات مقارنة بـ git merge .... يسمح git merge لواجهة git CLI بتطبيق خوارزميات متقدمة لتجنب التعارضات من خلال تحليل HEAD لكل فرع.
يمكن أن يكون هذا أكثر ذكاءً لأن كل عملية دمج تهتم فقط بأحدث حالة لكل فرع مرغوب. بينما يجب على إعادة الأساس إعادة تشغيل (أو إسقاط) تاريخ الالتزامات بالتسلسل المحدد. هذا يحد من قدرة git على تحسين الدمج لأنه يقارن فقط التزامين في كل مرة.
في النهاية، تعني إعادة الأساس أنك ستجد نفسك أحيانًا تعيد تجربة التزامات وتعقيدات قديمة غير ذات صلة - حتى لو كنت تعلم أنها قد أزيلت أو حُلت منذ ذلك الحين.
الملخص
- 💃 الإجابة: دمج الضغط لطلبات السحب الخاصة بك على
main.- سيكون تاريخ فرعك موجودًا إذا لزم الأمر، وسيبقى
main“نظيفًا” نسبيًا.
- سيكون تاريخ فرعك موجودًا إذا لزم الأمر، وسيبقى
- 🔤 كن دائمًا ملتزمًا!
- في أكثر من 95% من المشاريع المؤسسية، “عقلية النسخ الاحتياطي” أفضل من “عقلية الفن المنحوت”. مع مرور الوقت، سيتلاشى معنى رسائل الالتزام الخاصة بك، بشكل أسرع بكثير من الكود الذي ستحافظ منطقه واختباراته على أهميته.