أفضل ممارسات Git للالتزامات النظيفة والتعاون داخل الفرق

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

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

يجمع هذا الدليل عادات Git العملية للمطورين الأفراد والفرق. ويركز على الالتزامات النظيفة، وانضباط الفروع، والتعاون، وأمان المستودع، ومراجعة الشيفرة، وCI/CD، والاستعادة، والصيانة، وجودة السجل على المدى الطويل.

ما الذي ستتعلمه؟

  • كيفية تصميم التزامات مركزة وقابلة للمراجعة.

  • كيفية كتابة رسائل التزام مفيدة.

  • كيفية وضع التغييرات في staging بصورة مقصودة.

  • كيفية اختيار أسماء منطقية للفروع ومدد حياة مناسبة لها.

  • كيفية الحفاظ على صحة الفرع الافتراضي.

  • كيفية مراجعة التغييرات ودمجها بأمان.

  • متى تستخدم merge أوsquash أوrebase أوrevert أوcherry-pick.

  • كيفية حماية الأسرار والإعدادات الحساسة.

  • كيفية استخدام .gitignore و.gitattributes بصورة صحيحة.

  • كيفية تجنب الأخطاء المدمرة في السجل.

  • كيفية استخدام hooks وCI وحماية الفروع والأتمتة بفاعلية.

  • كيفية صيانة المستودعات الكبيرة والملفات الثنائية.

  • كيفية بناء سياسة Git للفريق تبقى مفهومة.

أفضل ممارسة 1: افهم حالة المستودع قبل تنفيذ أي إجراء

تبدأ أخطاء Git كثيرة بتشغيل أمر من دون فهم الفرع الحالي أو التغييرات staged أو الملفات untracked.

ابدأ العمليات المهمة بالأوامر التالية:

git status
git branch --show-current
git log -1 --oneline

قبل تنفيذ commit أوmerge أوrebase أوpull أوreset أوحذف فرع، تحقق من:

  • أن الفرع الحالي هو الفرع الصحيح.

  • أن working tree يحتوي فقط على التغييرات المتوقعة.

  • أن staging area يحتوي على اللقطة المقصودة.

  • أن أي عمل غير مكتمل لن يُستبدل أو يُفقد.

  • أن المستودع متزامن وفق مسار عمل الفريق.

الأمر git status ليس للمبتدئين فقط. يستخدمه المطورون ذوو الخبرة باستمرار لأنه يقدم ملخصًا آمنًا قبل العمليات التي تغيّر الحالة.

أفضل ممارسة 2: اجعل الالتزامات مركزة

ينبغي أن يمثل الالتزام تغييرًا منطقيًا واحدًا.

أمثلة جيدة:

  • إضافة التحقق من البريد الإلكتروني إلى التسجيل.

  • إصلاح إنشاء الفواتير المكررة.

  • إعادة تسمية interfaces الخاصة بخدمة الدفع.

  • توثيق إعداد البيئة المحلية.

  • إضافة اختبارات لرموز إعادة تعيين كلمة المرور المنتهية الصلاحية.

قد يجمع الالتزام السيئ بين:

  • إصلاح خطأ.

  • إعادة تنسيق.

  • تحديث dependency.

  • تغييرات في التوثيق.

  • شيفرة debug مؤقتة.

الالتزامات المركزة أسهل في:

  • المراجعة.

  • الاختبار.

  • التراجع.

  • cherry-pick.

  • الفهم بعد أشهر.

  • الاستخدام أثناء تصحيح الأخطاء وعمليات bisect.

ينبغي تقييم حجم الالتزام وفق غرضه المنطقي، لا وفق عدد ثابت من الأسطر المتغيرة. قد يلمس database migration متماسك عدة ملفات. وقد يظل تغيير من سطر واحد خطيرًا ويستحق التزامًا مستقلًا.

أفضل ممارسة 3: ضع التغييرات في Staging بصورة مقصودة

يفصل مسار الالتزام الاحترافي بين التحرير وتصميم الالتزام.

راجع العمل unstaged:

git diff

ضع المسارات المحددة في staging:

git add src/OrderService.php
git add tests/OrderServiceTest.php

أو اختر الأجزاء المحددة:

git add -p

راجع الالتزام المقترح:

git diff --staged

ثم أنشئ الالتزام:

git commit -m "منع إنشاء الطلبات المكررة"

تجنب التعامل مع git add . بوصفه أول خطوة تلقائية. فهو مريح، لكنه قد يضم تعديلات غير مرتبطة، وملفات محلية، وبيانات اعتماد، ومخرجات مولدة، أوتغييرات debug.

النمط الأكثر أمانًا:

git status
git diff
git add -p
git diff --staged
git commit

أفضل ممارسة 4: اكتب رسائل التزام مفيدة

ينبغي أن تشرح رسالة الالتزام غرض التغيير.

عناوين ضعيفة:

تحديث
إصلاح
تغييرات
نهائي
شيفرة جديدة

عناوين أقوى:

رفض رموز إعادة تعيين كلمة المرور المنتهية
منع معالجة webhook المكررة
إضافة فهرس بحث لعناوين المهام
توثيق إعداد queue worker

صيغة عملية للرسالة:

عنوان مختصر

نص اختياري يشرح سبب الحاجة إلى التغيير،
والقيود المهمة، والمقايضات، وملاحظات الاختبار.

تشمل عادات الرسائل الجيدة:

  • استخدم عنوانًا واضحًا وموجهًا نحو الفعل.

  • صف الغرض، لا اسم الملف فقط.

  • اشرح السبب عندما لا يستطيع diff ذلك.

  • سجّل تفاصيل التوافق أوmigration المهمة.

  • أشر إلى issues وفق اتفاقات الفريق.

  • تجنب المعلومات الحساسة في رسائل الالتزام.

يعرض diff ما تغيّر. ويجب أن تحفظ الرسالة سبب التغيير.

أفضل ممارسة 5: استخدم اتفاقًا ثابتًا لرسائل الالتزام

تستفيد الفرق من أسلوب ثابت للرسائل.

قد يستخدم اتفاق بسيط:

أضف ...
أصلح ...
أزل ...
أعد الهيكلة ...
وثّق ...
اختبر ...

تستخدم بعض المشاريع Conventional Commits:

feat: إضافة فلاتر بحث المهام
fix: منع إنشاء الفواتير المكررة
docs: شرح إعداد queue المحلي
refactor: فصل سياسة إعادة محاولة الدفع
test: تغطية رموز إعادة التعيين المنتهية

يمكن أن يدعم ذلك إنشاء changelog تلقائيًا وأدوات الإصدارات، لكنه ليس متطلبًا من Git.

استخدم اتفاقًا منظمًا فقط عندما:

  • يفهمه الفريق.

  • تستفيد منه الأدوات.

  • تكون القواعد موثقة.

  • لا يصبح التحقق متصلبًا بلا حاجة.

أفضل ممارسة 6: لا تسجل حالات منطقية معطلة أو غير مكتملة

كلما كان ذلك عمليًا، ينبغي أن يترك كل التزام المشروع في حالة قابلة للاختبار.

لا ينبغي أن يحتوي الالتزام عمدًا على:

  • أخطاء في الصياغة.

  • علامات تعارض غير محلولة.

  • اختبارات معروفة الفشل من دون تفسير.

  • Migrations غير مكتملة تجعل التطبيق غير قابل للاستخدام.

  • مراجع إلى ملفات لا تُضاف إلا في التزام لاحق.

هذا مهم لأن الالتزامات الفردية قد:

  • يجري checkout لها أثناء تصحيح الأخطاء.

  • تُستخدم بواسطة git bisect.

  • تُنقل إلى فرع آخر باستخدام cherry-pick.

  • تُراجع بصورة مستقلة.

  • تُنشر بالخطأ عبر الأتمتة.

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

أفضل ممارسة 7: افصل إعادة الهيكلة عن تغييرات السلوك

ينبغي لإعادة الهيكلة أن تحافظ على السلوك قدر الإمكان. أما الميزة أو إصلاح الخطأ فيغيّر السلوك.

الجمع بين الاثنين في التزام كبير واحد يجعل المراجعة صعبة، لأن المراجعين لا يستطيعون بسهولة التمييز بين الحركة البنيوية والمنطق الوظيفي.

فضّل:

الالتزام 1: فصل خدمة التحقق من الفواتير
الالتزام 2: رفض معرّفات الفواتير المكررة

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

عندما يستحيل الفصل، اشرح العلاقة بوضوح في نص الالتزام أو وصف pull request.

أفضل ممارسة 8: استخدم أسماء فروع وصفية

ينبغي أن يوضح اسم الفرع الغرض.

أمثلة جيدة:

feature/task-search
fix/payment-timeout
hotfix/duplicate-invoice
docs/local-setup
refactor/order-service
release/3.2.0

أمثلة سيئة:

new
test
final
branch2
adnan-work
changes

قد تتضمن سياسة تسمية الفروع:

  • بادئة تدل على النوع.

  • وصفًا قصيرًا.

  • معرّف issue عندما يكون مفيدًا.

  • كلمات صغيرة الأحرف مفصولة بصورة ثابتة.

مثال:

feature/APP-142-task-search

تجنب استخدام الأسماء الشخصية بوصفها الهوية الأساسية للفرع. ينبغي للفروع وصف العمل، لا الملكية.

أفضل ممارسة 9: اجعل الفروع قصيرة العمر

كلما بقي الفرع مفتوحًا مدة أطول، ازداد تباعده عن الفرع الهدف.

تنشئ الفروع طويلة العمر:

  • تعارضات دمج أكبر.

  • مفاجآت معمارية متأخرة.

  • دورات مراجعة طويلة.

  • عملًا مكررًا.

  • أحداث دمج خطرة.

  • صعوبة في معرفة ما إذا كان الفرع ما يزال نشطًا.

فضّل زيادات صغيرة قابلة للمراجعة تُدمج خلال ساعات أو بضعة أيام عندما يسمح المشروع بذلك.

بالنسبة إلى الميزات الكبيرة:

  • استخدم feature flags.

  • استخدم branch by abstraction.

  • قسّم العمل إلى زيادات مستقلة وآمنة.

  • ادمج البنية التحتية قبل التفعيل.

أفضل ممارسة 10: أنشئ الفروع من Base الصحيحة

قبل إنشاء فرع:

git switch main
git fetch origin
git merge --ff-only origin/main
git switch -c feature/task-search

يعتمد أمر التحديث الدقيق على مسار العمل، لكن المبدأ ثابت: ابدأ من base الحالية والمقصودة.

قد يؤدي إنشاء فرع من فرع قديم أو خاطئ إلى التزامات غير مرتبطة، وإصلاحات مفقودة، وفروقات pull request مربكة.

أفضل ممارسة 11: حافظ على صحة الفرع الافتراضي

ينبغي أن تكون للفرع الافتراضي حالة محددة بوضوح.

تشمل التوقعات الشائعة:

  • أن يكون قابلًا للنشر دائمًا.

  • أن يكون قابلًا للإصدار دائمًا.

  • أن يجتاز الاختبارات المطلوبة دائمًا.

  • أن يمثل دائمًا أحدث حالة تطوير مدمجة.

احمِ الفرع الافتراضي عبر:

  • اشتراط pull requests أوmerge requests.

  • منع عمليات الدفع المباشر.

  • اشتراط الفحوص الآلية.

  • اشتراط الموافقات.

  • منع force pushes.

  • تقييد الحذف.

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

أفضل ممارسة 12: راجع فرق الفرع قبل فتح Pull Request

ينبغي للمطورين مراجعة عملهم بأنفسهم قبل طلب المراجعة.

أوامر مفيدة:

git log --oneline main..HEAD
git diff --stat main...HEAD
git diff main...HEAD

تحقق من:

  • الملفات غير المرتبطة.

  • تعليمات debug.

  • الأسرار.

  • الملفات المولدة.

  • ضوضاء التنسيق.

  • الاختبارات المفقودة.

  • الحذف غير المقصود.

  • تغييرات قاعدة البيانات من دون معالجة migration.

توفر pull request خضعت للمراجعة الذاتية وقت المراجعين وتحسن التعاون.

أفضل ممارسة 13: اجعل Pull Requests صغيرة

تقلل pull requests الكبيرة جودة المراجعة.

المراجع الذي يواجه آلاف الأسطر المتغيرة يكون أكثر عرضة لأن:

  • يفوّت العيوب.

  • يركز على الأسلوب بدل التصميم.

  • يؤخر المراجعة.

  • يوافق من دون فهم كامل.

  • يطلب إعادة كتابة كاملة في مرحلة متأخرة.

Pull requests الصغيرة:

  • تحصل على ملاحظات أسرع.

  • تنتج تعارضات أقل.

  • يسهل اختبارها.

  • يسهل التراجع عنها.

  • تشجع التصميم التدريجي.

عندما يكون التغيير الكبير حتميًا، افصل التغييرات الميكانيكية، وتحضير schema، والبنية التحتية لرايات الميزات، وتفعيل السلوك إلى مراحل.

أفضل ممارسة 14: استخدم المراجعات Draft مبكرًا

تكون draft pull request أوmerge request مفيدة عندما:

  • تحتاج المعمارية إلى ملاحظات مبكرة.

  • يؤثر التغيير في عدة فرق.

  • يريد المطور تحقق CI قبل الاكتمال.

  • قد يبقى الفرع معزولًا فترة طويلة بخلاف ذلك.

المراجعة المبكرة أكثر قيمة من المراجعة المتأخرة بعد أن تصبح كل قرارات التصميم مكلفة في التغيير.

لا ينبغي أن تصبح حالة draft دائمة. استمر في تقسيم العمل الكبير إلى زيادات قابلة للدمج.

أفضل ممارسة 15: اختر سياسة دمج واحدة وواضحة

ينبغي للفرق تحديد طرق الدمج المسموح بها.

Merge Commit

يحافظ على بنية الفروع والالتزامات الفردية.

Squash Merge

يجمع pull request في التزام جديد واحد على الفرع الهدف.

Rebase and Merge

يعيد تطبيق الالتزامات على سجل الهدف من دون merge commit.

يعتمد الاختيار الصحيح على ما يقدره الفريق:

  • حدود دمج صريحة.

  • التزام واحد لكل pull request.

  • سجل خطي.

  • الحفاظ على التزامات فرع الميزة.

تجعل طرق الدمج غير المتسقة السجل أصعب في التفسير. وثّق الطريقة الافتراضية والاستثناءات.

أفضل ممارسة 16: استخدم Rebase فقط عندما يكون آمنًا

يعيد rebase كتابة الالتزامات بإنشاء التزامات بديلة فوق base جديدة.

يفيد في:

  • تنظيف سجل فرع ميزة خاص.

  • تحديث فرع محلي قبل المراجعة.

  • دمج fixup commits.

  • الحفاظ على سجل خطي عندما يطلب الفريق ذلك.

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

قاعدة عملية:

  • يمكن إعادة كتابة السجل المحلي الخاص بحرية.

  • ينبغي إعادة كتابة السجل العام المشترك باتفاق صريح فقط.

أفضل ممارسة 17: فضّل force-with-lease على Force Push العشوائي

عندما يجب تحديث فرع أُعيدت كتابة سجله على remote، تجنب:

git push --force

وفضّل:

git push --force-with-lease

يضيف --force-with-lease فحص أمان. ويرفض الكتابة فوق الفرع البعيد عندما تختلف حالة remote عما يتوقعه المستودع المحلي.

لا يجعل ذلك force push بلا ضرر. بل يقلل فقط خطر حذف عمل أحدث لمطور آخر.

لا تنفذ force push على الفروع المشتركة المحمية مثل main إلا إذا تطلبت عملية طوارئ موثقة ذلك.

أفضل ممارسة 18: استخدم Revert مع السجل المشترك

عندما يكون الالتزام السيئ قد جرت مشاركته بالفعل، أنشئ التزامًا جديدًا يعكسه:

git revert <commit>

يحافظ ذلك على السجل التاريخي.

استخدم reset أساسًا للسجل المحلي أو الخاص:

git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1

لأوضاع reset تأثيرات مختلفة في الفرع وindex وworking tree. وقد يدمر --hard العمل غير المسجل.

القاعدة العامة:

  • استخدم revert للتراجع عن الالتزامات المنشورة.

  • استخدم reset لإعادة تنظيم السجل الخاص عندما تفهم النتائج.

أفضل ممارسة 19: استخدم Cherry-Pick بصورة مقصودة

ينسخ git cherry-pick التغيير الذي قدمته التزامات محددة إلى الفرع الحالي.

تشمل الاستخدامات المفيدة:

  • نقل إصلاح خطأ إلى إصدار أقدم.

  • تطبيق تغيير واحد معتمد على فرع إصدار.

  • استعادة التزام مفيد من فرع متروك.

مثال:

git switch release/2.5
git cherry-pick -x abc1234

يسجل الخيار -x معرّف الالتزام الأصلي داخل الرسالة الجديدة عندما يكون ذلك مناسبًا، ما يحسن قابلية التتبع.

لا تستخدم cherry-pick بديلًا افتراضيًا للدمج الطبيعي للفروع. فهو يكرر التغييرات من دون تسجيل علاقة دمج بين الفروع.

أفضل ممارسة 20: احمِ الأسرار قبل أن تدخل السجل

لا تسجل أبدًا:

  • كلمات المرور.

  • مفاتيح API.

  • الرموز الخاصة.

  • بيانات اعتماد الخدمات السحابية.

  • مفاتيح SSH الخاصة.

  • ملفات بيئة الإنتاج.

  • نسخ قواعد بيانات تحتوي على بيانات عملاء حقيقية.

  • الشهادات الخاصة.

استخدم:

  • متغيرات البيئة.

  • مديري الأسرار.

  • مخازن أسرار CI/CD.

  • ملفات إعداد محلية مستبعدة من Git.

  • ملفات أمثلة تحتوي قيمًا بديلة.

مثال:

.env
.env.*
!.env.example

إذا سُجل سر:

  1. ألغِه أو دوّره فورًا.

  2. أزله من الملفات الحالية.

  3. قيّم ما إذا كانت إعادة كتابة السجل مطلوبة.

  4. نسق مع جميع المساهمين وأنظمة النشر.

  5. حدّث المراقبة وسجلات الحوادث.

حذف السر في التزام لاحق لا يزيله من السجل السابق.

أفضل ممارسة 21: استخدم .gitignore بصورة صحيحة

ينبغي أن يحتوي ملف .gitignore على مستوى المستودع على قواعد المشروع المشتركة.

تشمل الإدخالات الشائعة:

# ملفات البيئة
.env
.env.*

# الاعتماديات
vendor/
node_modules/

# مخرجات البناء
dist/
build/

# السجلات
*.log
storage/logs/

# ملفات المحرر ونظام التشغيل
.DS_Store
Thumbs.db

مبادئ مهمة:

  • يؤثر .gitignore في الملفات untracked.

  • لا يوقف تتبع ملف سبق تسجيله.

  • قواعد التجاهل المطلوبة للمشروع تنتمي إلى المستودع.

  • قد تنتمي أنماط المحرر الشخصية إلى ملف تجاهل عام.

لإيقاف تتبع ملف مع الاحتفاظ به محليًا:

git rm --cached .env

ثم سجّل الإزالة ودوّر أي أسرار مكشوفة.

أفضل ممارسة 22: استخدم .gitattributes لقواعد الملفات على مستوى المستودع

يحدد .gitattributes سلوك المسارات عبر كل clone.

مثال:

* text=auto

*.sh text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf

*.png binary
*.jpg binary
*.pdf binary

استخدمه من أجل:

  • توحيد نهايات الأسطر.

  • تعريف الملفات الثنائية.

  • برامج diff مخصصة.

  • سلوك الدمج.

  • إعدادات التصدير.

  • قواعد مسارات Git LFS.

تكون attributes على مستوى المستودع أكثر موثوقية من افتراض أن كل مطور يملك الإعدادات العامة نفسها.

أفضل ممارسة 23: تجنب الملفات الثنائية غير الضرورية

يعمل Git بأفضل صورة مع الملفات النصية لأنه يستطيع مقارنتها ودمجها بكفاءة.

تنشئ الملفات الثنائية الكبيرة مشكلات:

  • تصبح عمليات clone للمستودع كبيرة.

  • قد تبقى كل نسخة متغيرة داخل السجل.

  • تكون الفروقات محدودة أو غير متاحة.

  • يصبح الدمج صعبًا.

  • تصبح عمليات CI والشبكة أبطأ.

بالنسبة إلى الملفات الثنائية الكبيرة الضرورية، فكّر في:

  • Git LFS.

  • مستودعات artifacts.

  • Object storage.

  • Package registries.

  • Build pipelines تُنتج artifacts من المصدر.

لا تسجل مخرجات البناء لمجرد أنها مطلوبة للنشر. فضّل builds قابلة لإعادة الإنتاج وartifacts غير قابلة للتغيير مخزنة في أنظمة مصممة لذلك.

أفضل ممارسة 24: لا تسجل الاعتماديات المولدة إلا عند الحاجة

تتبع معظم الأنظمة ملفات تعريف الاعتماديات وlock files بدل مجلدات الاعتماديات المثبتة.

أمثلة:

  • تتبّع composer.json وعادة composer.lock، وتجاهل vendor/.

  • تتبّع package.json وlock file المختار، وتجاهل node_modules/.

  • تتبّع dependency manifests، وأعد إنشاء الحزم المثبتة داخل CI.

توجد استثناءات لنماذج النشر، والمكتبات المضمنة، وعمليات البناء دون اتصال، والبيئات المدمجة. وثّق السبب عندما تُسجل الاعتماديات المولدة عمدًا.

أفضل ممارسة 25: حافظ على اتساق Lock Files

تستفيد التطبيقات عادة من تسجيل lock file الخاص بالنظام لأنه يسجل إصدارات الاعتماديات التي جرى اختبارها.

تشمل المشكلات الشائعة:

  • تحديث manifest من دون تحديث lock file.

  • دمج تغييرات اعتماديات غير مرتبطة.

  • حل تعارضات lock file يدويًا من دون إعادة تثبيت الاعتماديات.

  • استخدام عدة صيغ متنافسة من lock files.

بعد تغييرات الاعتماديات:

  • شغّل أمر التحديث المعتاد لمدير الحزم.

  • راجع تغييرات manifest وlock معًا.

  • شغّل الاختبارات وعمليات البناء.

  • حافظ على تركيز تحديث الاعتماديات.

أفضل ممارسة 26: استخدم Git Hooks بحذر

يمكن لـGit hooks تشغيل فحوص عند نقاط مهمة.

تشمل hooks المحلية المفيدة:

  • pre-commit: التنسيق وlinting وفحص الأسرار.

  • commit-msg: التحقق من الرسالة.

  • pre-push: الاختبارات قبل النشر.

الفوائد:

  • ملاحظات سريعة قبل CI.

  • تنسيق تلقائي.

  • تقليل الأخطاء غير المقصودة.

  • تحقق محلي ثابت.

القيود:

  • Hooks محلية افتراضيًا.

  • يمكن للمطورين تجاوزها.

  • تبطئ hooks الثقيلة كل commit أوpush.

  • قد تتصرف البيئات المختلفة بطرق مختلفة.

ينبغي أن تعمل القواعد الحرجة أيضًا داخل CI أوضوابط الخادم.

أفضل ممارسة 27: اجعل الفحوص الآلية سريعة وذات صلة

ينبغي لـCI الإلزامي تقديم ملاحظات موثوقة بسرعة.

قد تتضمن pipeline عملية:

  • فحوص التنسيق.

  • Linting.

  • التحليل الثابت.

  • Unit tests.

  • Integration tests.

  • فحص الأمان.

  • التحقق من build.

  • التحقق من migrations.

تشمل ممارسات CI السيئة:

  • اختبارات إلزامية متذبذبة.

  • تشغيل كل الاختبارات المكلفة لكل تغيير صغير في التوثيق.

  • تجاهل الفحوص الفاشلة.

  • ترك pipelines معطلة لفترات طويلة.

  • السماح بالدمج قبل انتهاء الفحوص الحرجة.

استخدم تحققًا يعتمد على المسار أو طبقات عندما يكون مناسبًا، لكن لا تضعف الفحوص لمجرد جعل pipelines تبدو أسرع.

أفضل ممارسة 28: وقّع الالتزامات والعلامات المهمة عند الحاجة

يمكن للتوقيع التشفيري أن يساعد في التحقق من أن التزامًا أوعلامة أُنشئت بواسطة حامل مفتاح معتمد.

وقّع التزامًا:

git commit -S -m "إصدار إصلاح استدعاء الدفع"

وقّع علامة:

git tag -s v2.0.1 -m "إصدار النسخة 2.0.1"

تحقق من العلامة:

git tag -v v2.0.1

يثبت التوقيع شيئًا عن كائن Git وعلاقته بالمفتاح. لكنه لا يثبت أن:

  • الشيفرة آمنة.

  • المراجعة كانت صحيحة.

  • ملف build يطابق المصدر.

  • النشر كان مصرحًا به.

ادمج التوقيع مع عمليات موثوقة للبناء والإصدار والملفات.

أفضل ممارسة 29: ضع علامات واضحة على الإصدارات

استخدم العلامات لتحديد الالتزامات المهمة التي جرى إصدارها.

فضّل العلامات annotated أوsigned للإصدارات الرسمية:

git tag -a v3.1.0 -m "إصدار النسخة 3.1.0"
git push origin v3.1.0

قبل وضع العلامة:

  • تحقق من الفرع.

  • تحقق من الالتزام.

  • تأكد من أن working tree نظيف.

  • شغّل اختبارات الإصدار.

  • أكد رقم النسخة.

  • افحص العلامة قبل نشرها.

تعامل مع علامات الإصدارات المنشورة بوصفها غير قابلة للتغيير. فنقل علامة إصدار ينشئ هويات غير متسقة عبر clone والذاكرات المؤقتة وأنظمة البناء وعمليات النشر.

أفضل ممارسة 30: استخدم Reflog أداةً للاستعادة

عندما يتحرك فرع بصورة غير متوقعة أو يختفي التزام من السجل الطبيعي، افحص:

git reflog

تشمل حالات الاستعادة المفيدة:

  • Reset غير مقصود.

  • Amend غير صحيح.

  • Rebase أزال التزامات متوقعة.

  • فرع محلي محذوف.

  • التزام detached-HEAD.

افحص مرشحًا:

git show HEAD@{2}

احفظه:

git branch recovery HEAD@{2}

Reflogs محلية ومؤقتة. وليست بديلًا عن الالتزامات العادية أو النسخ البعيدة أو النسخ الاحتياطية.

أفضل ممارسة 31: لا تستخدم الأوامر المدمرة قبل فهم الطبقات

يمكن لأوامر مثل التالية إزالة العمل:

git reset --hard
git clean -fd
git restore .
git checkout -- .
git branch -D
git push --force

قبل استخدامها:

  • نفّذ git status.

  • راجع revision الهدف.

  • افحص الملفات untracked.

  • أنشئ فرعًا مؤقتًا أوstash عند الحاجة.

  • تأكد مما إذا كان العمل موجودًا في مكان آخر.

استخدم أوضاع المعاينة عندما تكون متاحة:

git clean -nd

يعرض ذلك ما سيحذفه git clean من دون تنفيذ الحذف.

أفضل ممارسة 32: لا تستخدم Stash للتخزين الدائم

يفيد stash للعمل المحلي المؤقت، لا لإدارة المشروع على المدى الطويل.

تشمل مشكلات stashes القديمة:

  • غرضًا غير واضح.

  • تعارضات مع الشيفرة الأحدث.

  • غياب الظهور الطبيعي ضمن الفروع.

  • غياب التعاون عبر remote.

  • خطر الحذف العرضي.

حوّل العمل المهم إلى فرع:

git stash branch feature/recovered-work stash@{0}

ثم أنشئ التزامات مركزة.

أفضل ممارسة 33: احذف الفروع المكتملة

بعد الدمج، أزل الفروع قصيرة العمر.

احذف فرعًا محليًا مدمجًا بأمان:

git branch -d feature/task-search

احذف فرعًا بعيدًا:

git push origin --delete feature/task-search

تجعل الفروع القديمة فهم ما هو نشط أمرًا صعبًا.

قبل الحذف الإجباري:

git log --oneline main..feature/task-search
git branch --contains feature/task-search

تأكد من حفظ العمل الفريد في مكان آخر.

أفضل ممارسة 34: نظّف مراجع Remote-Tracking القديمة

قد تترك الفروع البعيدة التي حذفها الآخرون مراجع remote-tracking قديمة محليًا.

نفّذ fetch مع التنظيف:

git fetch --prune

أو نظّف remote واحدًا:

git remote prune origin

اضبط التنظيف التلقائي إن كان يتوافق مع تفضيلات الفريق:

git config --global fetch.prune true

يزيل pruning مراجع remote-tracking القديمة. ولا يحذف الفروع البعيدة النشطة.

أفضل ممارسة 35: حافظ على أداء المستودع

ينفذ Git الصيانة تلقائيًا في بيئات كثيرة، لكن المستودعات الكبيرة أو طويلة العمر قد تتطلب اهتمامًا.

تشمل الأوامر المفيدة:

git count-objects -vH
git gc
git maintenance run
git fsck

الاستخدامات:

  • git count-objects: فحص استخدام loose objects وpacks.

  • git gc: تحسين بيانات المستودع وتنظيفها.

  • git maintenance: تشغيل مهام الصيانة.

  • git fsck: التحقق من ترابط الكائنات وصحتها.

لا تشغّل تنظيفًا عدوانيًا أثناء محاولة استعادة كائنات غير قابلة للوصول. فقد تزيل الصيانة بيانات كان يمكن العثور عليها بواسطة reflog أو أدوات استعادة الكائنات.

أفضل ممارسة 36: استخدم Sparse Checkout أوPartial Clone للمستودعات الكبيرة جدًا

قد تكون تكلفة clone وcheckout مرتفعة في monorepositories الكبيرة.

تشمل الخيارات:

  • Partial clone.

  • Sparse checkout.

  • Shallow clone في سيناريوهات CI محدودة.

  • تقسيم المستودع عندما تدعم المعمارية ذلك.

مثال على إعداد sparse-checkout:

git sparse-checkout init --cone
git sparse-checkout set services/billing shared

لهذه التقنيات مقايضات. تتصرف بعض الأوامر والأدوات بصورة مختلفة مع السجل shallow أوpartial. استخدمها عمدًا ووثّق توقعات الفريق.

أفضل ممارسة 37: استخدم .mailmap لاتساق الهوية

قد يظهر المطورون بأسماء أو عناوين بريد إلكتروني متعددة.

يمكن لملف .mailmap توحيد الهويات داخل أوامر مثل git shortlog.

مثال:

Jane Developer <jane@company.example> <jane.old@example.com>

يحسن ذلك ملخصات المساهمين من دون إعادة كتابة الالتزامات الحالية.

أفضل ممارسة 38: وثّق قواعد Git الخاصة بالمستودع

لا تعتمد على عادات فريق غير مكتوبة.

تشمل الملفات المفيدة:

CONTRIBUTING.md
docs/git-workflow.md
docs/release-process.md
CODEOWNERS

وثّق:

  • تسمية الفروع.

  • توقعات الفرع الافتراضي.

  • أسلوب رسائل الالتزام.

  • الفحوص المطلوبة.

  • متطلبات المراجعة.

  • طرق الدمج.

  • وضع علامات الإصدارات.

  • Hotfixes وbackports.

  • سياسة force push.

  • قواعد التعامل مع الأسرار.

سياسة قصيرة ومطبقة أفضل من وثيقة طويلة لا يتبعها أحد.

أفضل ممارسة 39: استخدم CODEOWNERS ومسؤولية المراجعة

تستفيد المستودعات الكبيرة من وضوح ملكية المراجعة.

يمكن لملف CODEOWNERS ربط المسارات بالمراجعين المسؤولين على منصات الاستضافة المدعومة.

مثال:

/src/Payments/ @payments-team
/database/migrations/ @backend-team
/docs/ @documentation-team

ينبغي ألا تخلق الملكية صوامع. بل يجب أن تضمن حصول المناطق الحساسة على مراجعة خبيرة مع استمرار مشاركة المعرفة المعمارية.

أفضل ممارسة 40: راجع أكثر من الصياغة

تتحقق مراجعة الشيفرة المفيدة من:

  • الصحة.

  • الأمان.

  • معالجة الأخطاء.

  • الاختبارات.

  • الأداء.

  • أمان نقل البيانات.

  • التوافق مع الإصدارات السابقة.

  • Observability.

  • قابلية الصيانة.

  • تأثير النشر.

يعرض Git الفرق، لكن يجب على المراجعين فهم النظام المحيط.

قد ينشئ تغيير صغير في الصياغة خطرًا تشغيليًا كبيرًا. وقد يحتوي فرق مولد ضخم على قدر قليل من المنطق ذي المعنى.

أفضل ممارسة 41: لا تخلط التنسيق بالتغييرات الوظيفية

إعادة تنسيق ملفات كاملة داخل فرع ميزة تنشئ فروقات مليئة بالضوضاء.

فضّل:

  • التنسيق الآلي قبل عمل الميزة.

  • التزامًا منفصلًا للتنسيق.

  • إعداد formatter على مستوى المستودع.

  • فحوص CI تمنع انحراف الأسلوب.

يحافظ ذلك على وضوح التغييرات الوظيفية أثناء المراجعة ويحسن سجل blame.

أفضل ممارسة 42: اجعل تغييرات قاعدة البيانات قابلة للنشر

تستحق database migrations انضباطًا خاصًا في Git.

تشمل الممارسات الجيدة:

  • حافظ على توافق تغييرات schema والتطبيق أثناء الإطلاق.

  • تجنب التغييرات المدمرة في عملية النشر نفسها التي تزيل مسارات الشيفرة القديمة.

  • اختبر إجراءات التقدم والتراجع عندما يكون rollback مدعومًا.

  • لا تعدّل migrations مطبقة على نطاق واسع إلا إذا كان المشروع يسمح بذلك صراحة.

  • افصل عمليات تعبئة البيانات عن تعريفات schema عند الحاجة.

  • وثّق تسلسل العمليات.

الالتزام النظيف في Git لا يكفي إذا جعل ترتيب النشر التطبيق يفشل.

أفضل ممارسة 43: سجّل مصدر عمليات النشر

ينبغي للفرق معرفة الالتزام والـartifact اللذين وصلا إلى كل بيئة بالضبط.

تشمل المعرّفات المفيدة:

  • Commit hash.

  • Release tag.

  • رقم build.

  • Container digest.

  • Artifact checksum.

اسم الفرع وحده غير كافٍ لأن الفروع تتحرك.

ينبغي لأنظمة النشر تسجيل معرّفات غير قابلة للتغيير.

أفضل ممارسة 44: استخدم الأتمتة لمهام المستودع المتكررة

يمكن للأتمتة معالجة:

  • حذف الفروع المدمجة.

  • إنشاء ملاحظات الإصدار.

  • إنشاء علامات النسخ.

  • تحديث changelogs.

  • تشغيل تحديثات الاعتماديات.

  • التحقق من الفروع القديمة.

  • التحقق من اتفاقات commit أوpull request.

ينبغي للأتمتة تقليل الأخطاء اليدوية، لا إخفاء القرارات المهمة. ما تزال علامات الإصدارات وmigrations والتنظيف المدمر تتطلب ملكية واضحة وإمكانية تدقيق.

أفضل ممارسة 45: اجعل السجل مفيدًا لا مثاليًا بصورة مصطنعة

ينبغي أن يكون السجل المفيد:

  • مفهومًا.

  • قابلًا للتتبع.

  • قابلًا للمراجعة.

  • قابلًا للاستعادة.

  • متسقًا مع مسار عمل الفريق.

ليس مطلوبًا أن يبدو مثاليًا رياضيًا.

قد ينتج عن الإفراط في تحسين السجل:

  • Rebase مفرط.

  • فقدان سياق التعاون.

  • خطر force push.

  • إضاعة الوقت في تنقيح تفاصيل صغيرة بعد المراجعة.

نظّف السجل الخاص قبل المشاركة عندما يكون ذلك مفيدًا. وحافظ على استقرار السجل المشترك بعد الدمج.

مسار Git يومي عملي

1. تحديث Base

git switch main
git fetch origin
git merge --ff-only origin/main

2. إنشاء فرع مركز

git switch -c fix/payment-timeout

3. العمل بخطوات صغيرة

git status
git diff
git add -p
git diff --staged
git commit -m "زيادة مهلة مزود الدفع"

4. تشغيل الاختبارات

# استخدم أوامر المشروع الفعلية
php vendor/bin/phpunit
npm test

5. مراجعة الفرع

git log --oneline main..HEAD
git diff --stat main...HEAD
git diff main...HEAD

6. الدفع وفتح المراجعة

git push -u origin fix/payment-timeout

7. الاستجابة للمراجعة

أنشئ التزامات متابعة مركزة أو عدّل الالتزامات الخاصة وفق سياسة الفريق.

8. الدمج والتنظيف

git switch main
git pull --ff-only
git branch -d fix/payment-timeout

تطبيق يدوي: تنظيف Working Tree مختلط

افترض أن working tree يحتوي على:

  • إصلاح خطأ في الدفع.

  • تحسين في README.

  • مخرجات debug مؤقتة.

افحص:

git status
git diff

ضع إصلاح الخطأ فقط في staging:

git add -p src/PaymentService.php
git add tests/PaymentServiceTest.php

راجع:

git diff --staged

أنشئ الالتزام:

git commit -m "منع محاولات الدفع المكررة"

أزل مخرجات debug غير المطلوبة من working tree، أو اتركها unstaged أثناء إعداد التزام التوثيق.

ضع التوثيق في staging بصورة منفصلة:

git add README.md
git commit -m "توثيق إعداد إعادة محاولة الدفع"

النتيجة هي التزامان مركزان بدل لقطة واحدة مختلطة.

تطبيق يدوي: الاستعادة بعد Reset غير مقصود

افترض أن فرعًا جرى reset له واختفى أحدث التزام.

افحص reflog:

git reflog

اعثر على الموضع السابق للفرع:

git show HEAD@{1}

احفظه:

git branch recovery/payment-fix HEAD@{1}

تحقق:

git log --oneline --graph --decorate --all

أنشئ فرع استعادة قبل تشغيل مزيد من الأوامر التي تغير السجل.

تطبيق يدوي: تحديث فرع ميزة أُعيدت كتابته بأمان

افترض أن فرعًا خاصًا خضع لـrebase:

git rebase main

راجع السجل الجديد:

git log --oneline --graph --decorate main..HEAD

حدّث remote باستخدام lease:

git push --force-with-lease

إذا دفع مطور آخر التزامات جديدة إلى الفرع البعيد، فينبغي للـlease رفض الكتابة فوقه، ما يسمح للفريق بتسوية العمل.

أخطاء Git الشائعة

تسجيل كل شيء دفعة واحدة

ينشئ ذلك سجلًا مختلطًا ويجعل المراجعة والاستعادة صعبتين.

استخدام رسائل التزام غامضة

رسائل مثل update لا تقدم سياقًا تاريخيًا مفيدًا.

العمل مباشرة على Main من دون سياسة

قد يتجاوز ذلك المراجعة والفحوص المطلوبة.

ترك فروع الميزات مفتوحة لأسابيع

يزداد التباعد وخطر الدمج مع الوقت.

تنفيذ Force Push على الفروع المشتركة

قد يمحو ذلك السجل الظاهر لمطورين آخرين.

تسجيل الأسرار

حذفها لاحقًا لا يزيلها من الالتزامات الأقدم.

تجاهل فشل CI

تفقد الفحوص المطلوبة قيمتها عندما يُقبل فشلها بصورة روتينية.

استخدام Reset على سجل منشور

يعيد ذلك كتابة موضع الفرع وقد يعطل عمل المتعاونين.

حذف الفروع من دون فحص الالتزامات الفريدة

قد يصبح العثور على عمل مهم صعبًا.

تسجيل الملفات المولدة من دون حاجة

يزيد ذلك حجم المستودع وينشئ فروقات مليئة بالضوضاء.

استخدام عدة أساليب دمج عشوائيًا

يصبح السجل غير متسق وصعب التفسير.

التعامل مع Reflog بوصفه نسخة احتياطية

Reflog محلي ومؤقت.

مثال على سياسة Git للفريق

الفرع الافتراضي:
- main

أسماء الفروع:
- feature/<الوصف>
- fix/<الوصف>
- docs/<الوصف>
- hotfix/<الوصف>

قواعد الالتزام:
- تغيير منطقي واحد لكل التزام
- عنوان واضح وموجه نحو الفعل
- لا أسرار أو اعتماديات مولدة

قواعد Pull Request:
- تُمنع عمليات الدفع المباشر إلى main
- تُطلب موافقة واحدة على الأقل
- يجب أن تنجح CI والتحليلات الثابتة والاختبارات
- ينبغي أن تبقى pull requests مركزة وصغيرة

سياسة الدمج:
- Squash merge لفروع الميزات العادية
- Merge commits لفروع الإصدارات والصيانة طويلة العمر
- Rebase للسجل الخاص للميزات فقط

سياسة الإصدار:
- علامات annotated أوsigned
- تحدد العلامات التزامات جرى اختبارها
- العلامات المنشورة غير قابلة للتغيير

الأمان:
- استخدم revert للسجل المشترك
- استخدم force-with-lease لفروع الميزات المعاد كتابتها والمعتمدة
- لا force push إلى main

قائمة التحقق لأفضل ممارسات Git

قبل إنشاء الالتزام:

  • الفرع الحالي صحيح.

  • يحتوي الالتزام على تغيير منطقي واحد.

  • جرى فحص staged diff.

  • لا توجد أسرار أو ملفات مولدة في staging.

  • الاختبارات ذات الصلة ناجحة.

  • تشرح رسالة الالتزام الغرض.

قبل فتح pull request:

  • يبدأ الفرع من base الصحيحة.

  • Pull request مركزة.

  • راجع المطور فرق الفرع بنفسه.

  • CI ناجحة.

  • الاختبارات ومخاوف migration موثقة.

  • لا تبقى شيفرة debug مؤقتة.

قبل الدمج:

  • اكتملت الموافقات المطلوبة.

  • نجحت الفحوص المطلوبة.

  • تطابق طريقة الدمج سياسة الفريق.

  • الفرع الهدف صحيح.

  • تأثير الإصدار والنشر مفهوم.

قبل إعادة كتابة السجل أو حذفه:

  • الالتزامات خاصة أو نسق الفريق العملية.

  • العمل المهم محفوظ في مكان آخر.

  • حالة remote مفهومة.

  • يُستخدم --force-with-lease بدل force العشوائي عند الحاجة.

  • يتوفر فرع استعادة أو مرجع reflog.

الأسئلة الشائعة

كم مرة ينبغي أن أنشئ التزامًا؟

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

هل ينبغي أن يجتاز كل التزام جميع الاختبارات؟

ينبغي لكل التزام مثاليًا الحفاظ على حالة قابلة للاستخدام والاختبار. وعلى الأقل، يجب ألا يكسر افتراضات المستودع الأساسية عن علم من دون سبب موثق.

هل ينبغي أن أستخدم git add .؟

يكون مقبولًا عندما تنتمي كل التغييرات الحالية إلى العمل نفسه، لكن راجع دائمًا git status وgit diff --staged بعد ذلك.

هل ينبغي تنفيذ Squash لجميع الالتزامات؟

لا. نفّذ squash لسجل الفرع المليء بالضوضاء أو المؤقت عندما يكون المطلوب التزامًا منطقيًا واحدًا على المسار الرئيسي. وحافظ على الالتزامات المستقلة ذات المعنى عندما تحسن السجل.

هل Rebase أفضل من Merge؟

لا يوجد واحد أفضل دائمًا. ينشئ rebase التزامات بديلة وقد ينتج سجلًا خطيًا. أما merge فيحافظ على السجل الحالي ويسجل عملية الدمج. استخدم سياسة الفريق الموثقة.

متى يكون Force Push مقبولًا؟

عادة على فرع ميزة خاص أو مسموح صراحة بإعادة كتابته فقط. فضّل --force-with-lease. ولا تنفذ force push على الفروع المشتركة المحمية.

ماذا أفعل بعد تسجيل سر؟

دوّره أو ألغِه فورًا. ثم أزله من الملفات الحالية، وقيّم تنظيف السجل، ونسق مع الفريق والأنظمة المتأثرة.

هل ينبغي تسجيل .env.example؟

نعم، عندما يحتوي على مفاتيح بديلة آمنة ويوثق الإعدادات المطلوبة. لا تضع داخله قيم أسرار حقيقية.

هل ينبغي تسجيل Lock Files؟

ينبغي للتطبيقات ذلك عمومًا. وقد تتبع المكتبات سياسات خاصة بالنظام المستخدم. وينبغي للفريق توثيق القرار.

هل ينبغي حذف الفروع المدمجة؟

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

هل السجل الخطي النظيف أفضل دائمًا؟

لا. السجل القابل للقراءة أهم من الرسم المستقيم تمامًا. ويمكن لـmerge commits الحفاظ على سياق دمج ذي قيمة.

هل يستطيع Git استبدال نظام النسخ الاحتياطي؟

لا. يحمي Git سجل المستودع المسجل، لا قواعد البيانات أو الملفات المرفوعة أو الخدمات الخارجية أو كل تغيير محلي غير مسجل.

كيف أجعل Git أسهل لأعضاء الفريق الجدد؟

وثّق مسار العمل، وأتمت الإعداد والتحقق، واستخدم اتفاقات ثابتة للفروع والالتزامات، وحافظ على سجل المستودع مفهومًا.

الخلاصة

أفضل ممارسات Git لا تتعلق بحفظ أكبر عدد من الأوامر. بل تتعلق بتقليل الغموض.

الالتزام النظيف يشرح تغييرًا منطقيًا واحدًا. والفرع الجيد يصف غرضًا واحدًا. وpull request المفيدة صغيرة بما يكفي للمراجعة. والفرع الافتراضي الصحي يجتاز الفحوص المطلوبة. والمستودع الآمن يبقي الأسرار خارج السجل، ويستخدم علامات إصدار واضحة، ويتجنب إعادة كتابة الالتزامات المشتركة من دون تنسيق.

النمط اليومي الأكثر موثوقية بسيط: افحص المستودع، وراجع فرق العمل، وضع التغييرات في staging عمدًا، وراجع staged diff، واختبر التغيير، وأنشئ التزامًا برسالة ذات معنى، وانشر من خلال عملية مراجعة الفريق.

بالنسبة إلى الفرق، تأتي التحسينات الأعلى قيمة من الاتساق والتطبيق. وثّق مسار العمل، واحمِ الفروع المهمة، وأتمت الفحوص القابلة للتكرار، وحدد سياسات الدمج والإصدار، ولا تجعل العملية أعقد مما يتطلبه المنتج.

ستقدم المقالة الأخيرة في سلسلة أساسيات Git قاموسًا كاملًا لمصطلحات Git، يربط المصطلحات الأساسية المستخدمة في المستودعات والالتزامات والفروع وremotes وعمليات الدمج وrebase والعلامات وstashes والاستعادة والتعاون.

المراجع الرسمية ومواد إضافية للقراءة