Git وتدفقات العمل التعاونية

مشروع: تصميم سير عمل Git لفريق

18 دقيقة الدرس 10 من 28

مشروع: تصميم سير عمل Git لفريق

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

الفريق النموذجي

أنت كبير مهندسي DevOps في شركة Nexora، شركة منتج تضم 40 موظفاً تتوزعون على ثلاثة فرق: Platform (8 مهندسين)، وGrowth (10 مهندسين)، وCore API (12 مهندساً)، إضافةً إلى فريق SRE الصغير المؤلف من 4 أشخاص. يشحنون منتجاً SaaS عدة مرات يومياً. الوضع الراهن مؤلم: فروع ميزات طويلة الأمد، وتعارضات دمج تستغرق ساعات لحلها، وعملية مراجعة غير متسقة، وإصدارات تعيق بعضها البعض.

الخطوة الأولى — اختيار نموذج التفريع المناسب

وضع Nexora — فرق متعددة، ونشر متكرر — يجعله مرشحاً مثالياً لنهج التطوير القائم على الجذع (TBD) مع فروع ميزات قصيرة الأمد (بحد أقصى يومين). نموذج Git Flow مستبعد صراحةً: فروع develop وrelease الطويلة ستجعل آلام الدمج الحالية أشد، لا أخف.

اتفاقية التفريع بسيطة لكنها صارمة:

  • main — الجذع. دائماً قابل للنشر. محمي. لا دفع مباشر.
  • feature/{ticket-id}-short-description — مثل feature/NX-412-user-invites. الحد الأقصى للعمر: يومان. إذا استغرقت الميزة وقتاً أطول، تُشحن خلف علم ميزة.
  • fix/{ticket-id}-short-description — إصلاحات الأخطاء، نفس قواعد فروع الميزات.
  • hotfix/{ticket-id}-short-description — حوادث الإنتاج فقط. يُدمج مباشرةً في main بعد مراجعة طارئة.
قاعدة اليومين هي أهم انضباط على الإطلاق. الفرع الذي يتجاوز يومين هو عبء: يتباعد عن main كل ساعة، مما يجعل تعارضات الدمج أشد تعقيداً بصورة أسية. إذا لم تكن الميزة جاهزة، أخفِها خلف علم وادمج الكود على أي حال. الفرع يُشحن، لكن واجهة المستخدم لا.

الخطوة الثانية — حماية الفروع ومتطلبات الدمج

فرّض النموذج على مستوى المنصة. على GitHub، اضبط ما يلي لفرع main مُرمَّزاً كـ Terraform حتى لا يستطيع أحد إضعافه بهدوء:

# terraform/github-branch-protection.tf resource "github_branch_protection" "main" { repository_id = github_repository.nexora.node_id pattern = "main" required_pull_request_reviews { required_approving_review_count = 2 dismiss_stale_reviews = true require_code_owner_reviews = true } required_status_checks { strict = true # يجب أن يكون الفرع محدّثاً قبل الدمج contexts = [ "ci/lint", "ci/unit-tests", "ci/integration-tests", "security/snyk", ] } enforce_admins = true # حتى مالك المنظمة لا يستطيع التجاوز allows_force_pushes = false allows_deletions = false require_linear_history = true # squash أو rebase فقط — لا merge commits على main }

علامة require_linear_history حرجة. تجبر كل طلب سحب على الدمج بالضغط أو إعادة التأسيس، مما يبقي تاريخ main خطاً نظيفاً قابلاً للمسح الثنائي. دمج الالتزامات ذات الآباء المتعددة يُعقّد git bisect وتوليد سجل التغييرات تلقائياً كثيراً.

تعيين المراجعين تلقائياً عبر CODEOWNERS:

# .github/CODEOWNERS # النمط المالك(ون) * @nexora/platform-leads /app/Http/Controllers/Api/ @nexora/core-api /app/Services/Billing/ @nexora/core-api @nexora/finance-approval /resources/js/ @nexora/growth /database/migrations/ @nexora/platform-leads @nexora/sre /.github/ @nexora/sre /Dockerfile @nexora/sre /terraform/ @nexora/sre
لا تتجاهل قاعدة CODEOWNER للترحيلات أبداً. ترحيل يحذف عموداً أو يزيل فهرساً هو تغيير يعتمد على ترتيب النشر ويمكنه إسقاط الإنتاج بصمت. اشتراط موافقة SRE على كل ملف ترحيل من أرخص الضمانات المتاحة.

الخطوة الثالثة — اتفاقية طلب السحب

طلب السحب هو أداة تواصل، ليس مجرد آلية تسليم كود. تُوحّد Nexora وصف الطلب بقالب مخزن في المستودع. كل حقل إلزامي — يفشل CI إذا حُذفت أقسام القالب:

# .github/pull_request_template.md ## ماذا يفعل هذا الطلب؟ <!-- فقرة واحدة. أرفق التذكرة: Closes NX-412 --> ## كيف جرى الاختبار؟ <!-- محلياً: اختبارات الوحدات، الخطوات اليدوية. CI: فحوصات الحالة المتوقع أن تكون خضراء. --> ## تأثير الترحيل <!-- لا يوجد | إضافة متوافقة مع الإصدار السابق | يتطلب ترتيب نشر (اشرح) --> ## علم الميزة <!-- لا ينطبق | اسم العلم: feature.user_invites — افتراضياً مُطفأ --> ## خطة التراجع <!-- كيف تتراجع إذا أعطب هذا الإنتاج خلال أول 30 دقيقة. -->

الخطوة الرابعة — مخطط سير العمل الشامل

يوضح المخطط التالي الدورة الحياتية الكاملة للميزة من إنشاء التذكرة إلى وسم الإنتاج. يمكن لكل مهندس في Nexora الرجوع إلى هذه الصورة الواحدة عند الشك.

Nexora Git workflow: ticket to production Engineer Pull ticket Create branch feature/NX-xxx-… Commit + rebase daily onto main Open PR CI & Review Lint · Tests Security scan 2 approvals CODEOWNER review Squash-merge into main Delete branch auto on merge Release Deploy to staging auto on main push Smoke tests + QA sign-off Auto-tag vX.Y.Z (semver) Deploy to prod on tag push Hotfix Path (incident only) hotfix/NX-xxx Emergency review Merge to main Tag + deploy prod
سير عمل Git في Nexora: من التذكرة إلى الإنتاج، مع مسار الإصلاح الطارئ.

الخطوة الخامسة — اتفاقية الإصدار والإصدار الدلالي

يُفرض الإصدار الدلالي تلقائياً. تشغّل خطوة CI أداة semantic-release على كل دفعة إلى main، تقرأ الالتزامات التقليدية لتحديد ما إذا كان الرفع رئيسياً أو ثانوياً أو ترقيعياً:

  • feat: … — رفع ثانوي (1.4.0 → 1.5.0)
  • fix: … — رفع ترقيعي (1.5.0 → 1.5.1)
  • feat!: … أو تذييل BREAKING CHANGE: — رفع رئيسي (1.5.1 → 2.0.0)

يُنشئ روبوت الإصدار إصداراً على GitHub مع سجل تغييرات مُوَلَّد، ويدفع وسم git، ويُشغّل خط أنابيب نشر الإنتاج. لا أحد بحاجة لتذكر وسم إصدار — انضباط رسائل الالتزام يفعل ذلك تلقائياً.

فرض صياغة رسائل الالتزام: ثبّت commitlint كخطاف commit-msg في Git حتى يرى المهندسون خطأً فورياً عند كتابة رسالة غير متوافقة، قبل أن تصل إلى الخادم البعيد. أضفه إلى .husky/commit-msg:

npx --no -- commitlint --edit "$1"

هذا لا يكلف شيئاً ويمنع بأكمله حوادث "عطل رسالتي روبوت الإصدار".

الخطوة السادسة — تشغيل سير العمل فعلياً

وثيقة سير عمل لا يجدها أحد لا قيمة لها. تجعل Nexora سير العمل مفروضاً ذاتياً على كل طبقة:

  1. تسمية الفروع عبر خطاف — خطاف pre-push على جهاز كل مطوّر يرفض الدفع من فروع لا تطابق ^(main|feature|fix|hotfix|release)/. يُثبَّت عبر سطر واحد في نص setup.sh التمهيدي للمستودع.
  2. حماية الفروع عبر Terraform — إعدادات GitHub هي كود. يتطلب طلب السحب لإضعافها موافقة اثنين من SRE.
  3. التعيين التلقائي عبر CODEOWNERS — لا يحتاج المهندسون لتذكّر من يضيفونه مراجعاً؛ GitHub يفعل ذلك عند فتح الطلب.
  4. الحقول الإلزامية في قالب الطلب — يفحص CI نص الطلب بحثاً عن عناوين القالب عبر GitHub API ويفشل إذا كان أي قسم فارغاً.
  5. روبوت الفروع القديمة — يعمل إجراء GitHub ليلاً، يعلّق على فروع أعمر من يومين، ويغلقها عند خمسة أيام. لا يمكن للمهندسين نسيان فروعهم الطويلة لأن الروبوت سيذكّرهم بصوت عالٍ.
  6. نظافة أعلام الميزات — كل علم له تاريخ remove_by في إعداد الأعلام. يعمل فحص الأعلام القديمة أسبوعياً وينشئ تذاكر Jira تلقائياً للإزالات المتأخرة.
اكتب وثيقة سير العمل مرة، وفرّضها بالأدوات إلى الأبد. وثيقة في Confluence لا يقرأها أحد هي مسرح توثيق. ملف Terraform وخطاف Git يرفضان السلوك غير المتوافق هما فرض حقيقي. على النطاق الكبير، السياسات الوحيدة التي تصمد هي تلك التي يفرضها النظام تلقائياً.

تسليم وثيقة التصميم

نتيجتك النهائية لهذا المشروع هي ملف CONTRIBUTING.md مُلتزم به في جذر المستودع. يجب أن يشمل:

  • اتفاقية تسمية الفروع مع أمثلة
  • قاعدة عمر الفرع يومين وما تفعله بدلاً من ذلك (أعلام الميزات)
  • كيفية فتح طلب سحب: حقول القالب، من يُعيَّن تلقائياً، الفحوصات المطلوبة
  • استراتيجية الدمج (squash في main) والسبب
  • تنسيق رسالة الالتزام (الالتزامات التقليدية) مع أمثلة
  • عملية الإصدار: كيف يقرر semantic-release الإصدار
  • عملية الإصلاح الطارئ: خطوة بخطوة، من تُخطر، اتفاقية مستوى الخدمة
  • كيفية التصعيد إذا كانت قاعدة فرع محمي تعيق عملاً طارئاً مشروعاً

إيداع هذا الملف في main يُغلق الحلقة: سير العمل مُنسخ، قابل للمقارنة بين الإصدارات، ومكتشف من كل مهندس يستنسخ المستودع. مقرون بحماية الفروع عبر Terraform والخطافات المثبّتة بواسطة setup.sh، يصبح سير العمل موثقاً ومفروضاً معاً — الخاصيتان اللتان تجعلان أي سير عمل Git يعمل فعلاً على نطاق الفريق.