كانت سجلات التغيير لدينا لغزاً: كيف أنقذنا معيار ‘Conventional Commits’ من جحيم ‘git log’ عديم الفائدة؟

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

كنا نعرف أن المشكلة ظهرت بعد آخر عملية دمج (merge) للكود. وبكل ثقة (ساذجة وقتها)، فتحت الطرفية وكتبت الأمر السحري: git log --oneline. وهنا بدأت الكارثة الحقيقية. ما ظهر أمامي كان أشبه بنص مشفر من روايات دان براون، سلسلة لا نهائية من رسائل الـ commit التي لا تقول شيئًا:


a1b2c3d (HEAD -> main) Merge pull request #123 from dev/feature-x
f4g5h6i Update files
e7d8c9b Fix
a0b1c2d More updates
c3d4e5f Stuff
...

“Fix”؟ أي إصلاح؟ “Update files”؟ أي ملفات ولماذا؟ “Stuff”؟ بالله عليك يا زميلي، ما هذا الـ “Stuff” الذي كلفنا ليلتنا؟! كنا كمن يبحث عن إبرة في كومة قش عملاقة. بعد ساعات من البحث اليدوي المؤلم والمقارنة بين الـ commits، وجدنا التغيير المسبب للمشكلة. لكن السؤال الذي بقي يتردد في ذهني تلك الليلة: “هل هذا هو أفضل ما يمكننا فعله؟ هل محكوم علينا أن نعيش في جحيم الـ git log هذا إلى الأبد؟”.

من رحم تلك المعاناة، بدأت رحلة البحث عن حل، رحلة انتهت بنا إلى تبني فلسفة غيرت كل شيء. وهذه هي قصتنا مع “Conventional Commits”.

ما هو الجحيم الذي أتحدث عنه؟ (مشكلة الـ Commits العشوائية)

قبل أن ننتقل للحل، دعونا نعترف بالمشكلة. المشكلة التي وصفتها في قصتي ليست حالة نادرة، بل هي الوضع الافتراضي في كثير من فرق العمل. حين لا توجد قواعد واضحة لكتابة رسائل الـ commit، يكتب كل مطور ما يخطر بباله في تلك اللحظة. والنتيجة؟

  • سجل تغييرات عديم الفائدة: يصبح git log مجرد ضوضاء، من المستحيل فهم تسلسل التغييرات أو تاريخ تطور المشروع منه.
  • صعوبة تتبع الأخطاء (Bugs): كما حدث معنا، يصبح تحديد الـ commit الذي أدخل خطأً معينًا مهمة شبه مستحيلة.
  • استحالة إنشاء سجلات التغيير (Changelogs) تلقائيًا: كيف يمكنك أن تخبر المستخدمين بما هو جديد في الإصدار 2.1.0 إذا كان سجل الـ commits الخاص بك عبارة عن “updates” و “fixes”؟
  • مراجعات الكود (Code Reviews) أصعب: عندما تراجع طلب سحب (Pull Request) يحتوي على 10 commits برسائل غامضة، يصعب عليك فهم القصة التي يحاول المطور سردها من خلال تغييراته.

من الآخر، الشغل بكون “ملخبط” وغير احترافي. وهذا لا يؤثر فقط على الإنتاجية، بل على معنويات الفريق أيضًا.

الضوء في آخر النفق: معيار ‘Conventional Commits’

وسط هذا الظلام، وجدنا ضالتنا في معيار بسيط لكنه عبقري يسمى Conventional Commits. القصة وما فيها، هو عبارة عن اتفاقية أو مجموعة قواعد خفيفة لكيفية تنسيق رسائل الـ commit الخاصة بك. إنه ليس أداة جديدة أو برنامج معقد، بل هو مجرد “وصفة” لكتابة الرسائل.

الفكرة الأساسية هي إعطاء هيكل واضح لرسائل الـ commit، مما يسمح للبشر والآلات بفهمها بسهولة. الهيكل العام يبدو هكذا:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

قد يبدو معقدًا للوهلة الأولى، لكنه في الحقيقة بسيط جدًا. دعونا نفصّله جزءًا جزءًا.

تشريح رسالة الـ Commit المثالية

1. النوع (Type) – إجباري

هذا هو أهم جزء. يخبرنا عن “نوع” التغيير الذي قمت به. أشهر الأنواع هي:

  • feat: لإضافة ميزة جديدة (feature). هذا النوع هو الذي يظهر غالبًا في سجل التغييرات للمستخدمين.
  • fix: لإصلاح خطأ (bug). هذا أيضًا يظهر في سجل التغييرات.
  • docs: لتغييرات تتعلق بالتوثيق فقط (documentation).
  • style: تغييرات لا تؤثر على معنى الكود (مسافات بيضاء، تنسيق، فواصل منقوطة ناقصة، إلخ).
  • refactor: إعادة صياغة للكود لا تصلح خطأً ولا تضيف ميزة جديدة.
  • perf: تغيير في الكود يحسن الأداء (performance).
  • test: إضافة اختبارات ناقصة أو تصحيح اختبارات موجودة.
  • chore: تغييرات في عملية البناء أو الأدوات المساعدة والمكتبات مثل إدارة الحزم (e.g. updating dependencies).
  • ci: تغييرات في ملفات وإعدادات التكامل المستمر (CI configurations).

2. النطاق (Scope) – اختياري

هذا الجزء يحدد القسم من قاعدة الكود الذي تأثر بالتغيير. على سبيل المثال: auth, api, ui, database. يساعد هذا في توفير سياق إضافي بسرعة.

مثال: feat(auth): add social login with Google

3. الوصف (Description) – إجباري

وصف قصير وواضح للتغيير. يجب أن يبدأ بحرف صغير ولا ينتهي بنقطة.

4. المتن (Body) – اختياري

إذا كان التغيير معقدًا، يمكنك إضافة شرح أطول هنا. في هذا الجزء، تشرح “لماذا” قمت بهذا التغيير، وليس فقط “ماذا” غيرت. ما هي المشكلة التي يحلها؟ ما هو السياق؟

5. التذييل (Footer) – اختياري

يستخدم لمعلومات إضافية. أهم استخدامين له هما:

  • التغييرات الكاسرة (Breaking Changes): إذا كان الـ commit الخاص بك يكسر التوافق مع الإصدارات السابقة، يجب أن تذكر ذلك بوضوح هنا، بدءًا بالكلمة BREAKING CHANGE:. هذا أمر بالغ الأهمية!
  • ربط المشاكل (Referencing Issues): يمكنك إغلاق “issue” على GitHub أو GitLab تلقائيًا باستخدام كلمات مثل Closes #123.

مثال على رسالة Commit متكاملة


feat(api): allow users to change their email address

Previously, users could only set their email at signup. This change
introduces a new endpoint /api/v2/user/email to allow authenticated
users to update their email address.

A confirmation email will be sent to the new address before the
change takes effect.

Closes #45, #48
BREAKING CHANGE: The user profile endpoint /api/v1/profile no longer
returns the 'email' field. It must be fetched from the new dedicated
/api/v2/user/email endpoint.

لاحظ الفرق الشاسع بين هذا وبين “Update files”!

من النظرية إلى التطبيق: كيف بدأنا الرحلة؟

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

الخطوة الأولى: الإقناع والاتفاق

عقدت اجتماعًا قصيرًا مع الفريق. لم أبدأ بإلقاء الأوامر، بل عرضت عليهم قصة ليلة “الجحيم” التي مررنا بها. عرضت عليهم سجل git log الفوضوي، ثم عرضت عليهم كيف يمكن أن يبدو مع Conventional Commits. ركزت على الفوائد التي ستعود علينا جميعًا: سجل أوضح، تتبع أسهل، ومراجعات كود أسرع. عندما يرى الناس أن الحل سيوفر عليهم وقتًا وجهدًا، يصبحون أكثر تقبلاً له.

الخطوة الثانية: الأدوات المساعدة (وهي سر النجاح)

الاعتماد على الانضباط البشري وحده غالبًا ما يفشل. لذلك، استعنّا ببعض الأدوات لجعل العملية تلقائية وسهلة:

  • Commitizen: أداة رائعة تساعدك على كتابة رسائل commit متوافقة مع المعيار خطوة بخطوة. بدلًا من كتابة git commit، تكتب git cz، فتقوم الأداة بسؤالك عن النوع، النطاق، الوصف، إلخ. هذا يزيل عبء التذكر عن المطور.
  • commitlint: هذه الأداة هي “شرطي المرور”. تقوم بفحص رسالة الـ commit قبل قبولها للتأكد من أنها تتبع القواعد. إذا لم تكن متوافقة، يتم رفض الـ commit مع رسالة توضح الخطأ.
  • husky: أداة تسمح بتشغيل سكربتات عند أحداث معينة في Git (مثل قبل الـ commit أو قبل الـ push). استخدمناها لتشغيل commitlint تلقائيًا على كل commit.

هذا الثلاثي (Commitizen, commitlint, husky) كان له أثر السحر. لقد حولوا القاعدة من “شيء يجب أن نتذكره” إلى “جزء آلي من سير العمل”.

الخطوة الثالثة: جني الثمار

لم يمض وقت طويل حتى بدأنا نرى النتائج. أصبح سجل git log الخاص بنا يبدو هكذا:


d2a9f1e (HEAD -> main) fix(auth): correct redirect URL after password reset
c8b3e5a feat(ui): add loading spinner to data tables
a1b7c4d docs(readme): update setup instructions
f3e2d1c refactor(api): simplify user query logic
...

يا له من منظر مريح للعين! أصبحنا قادرين على:

  • إنشاء سجلات التغيير (Changelogs) بضغطة زر: باستخدام أدوات مثل standard-version، أصبحنا نصدر إصدارات جديدة مع سجل تغييرات مفصل وجميل يتم إنشاؤه تلقائيًا من رسائل الـ commits.
  • فهم تاريخ المشروع بسرعة: أي مطور جديد ينضم للفريق يمكنه الآن فتح git log وفهم ما حدث في المشروع خلال الأشهر الماضية.
  • تحديد الإصدارات الدلالية (Semantic Versioning) تلقائيًا: الأداة تعرف أنه إذا كان هناك feat، فيجب زيادة الرقم الثاني من الإصدار (e.g., 1.2.0). وإذا كان هناك BREAKING CHANGE، فيجب زيادة الرقم الأول (e.g., 2.0.0).

نصائح من خبرة أبو عمر

  • ابدأ ببساطة: لا تفرض كل أنواع الـ commits من اليوم الأول. ابدأ بالأساسيات: feat, fix, chore. ثم أضف المزيد حسب حاجة فريقك.
  • الأتمتة هي صديقك: لا تترك الأمر للانضباط الشخصي. استخدم أدوات مثل commitlint و husky. اجعل من المستحيل ارتكاب الخطأ.
  • كن مرنًا: الهدف هو الوضوح والتواصل، وليس الالتزام الأعمى بالقواعد. إذا واجهت حالة لا تناسبها أي من القواعد، استخدم أفضل حكم لديك. الهدف هو شغل نظيف، وليس تعقيد الأمور.
  • استخدم متن الرسالة (Body): لا تبخل في كتابة شرح مفصل في متن الرسالة للـ commits المهمة. اشرح الـ “لماذا” خلف التغيير. سَيشكرك زملاؤك (وأنت المستقبلي) على ذلك.

الخلاصة: من الفوضى إلى النظام organizado

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

إذا كنت أنت وفريقك لا تزالون تعانون من جحيم git log، فأتمنى أن تكون قصتنا هذه دافعًا لكم للتغيير. قد يتطلب الأمر بعض الجهد في البداية، لكن العائد على المدى الطويل لا يقدر بثمن. لن تحصل فقط على سجل تغييرات أنظف، بل ستبني ثقافة من الوضوح والاحترافية والعمل الجماعي. صدقني، “أنت المستقبلي” سَيشكرك على هذا القرار. 😉

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

أتمتة العمليات

كان زر النشر يسبب لنا نوبات هلع: كيف أنقذتنا خطوط أنابيب CI/CD من جحيم الإصدارات اليدوية؟

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

1 مايو، 2026 قراءة المزيد
​معمارية البرمجيات

كان تحديث نظامنا المونوليثي مستحيلاً: كيف أنقذنا نمط ‘التين الخانق’ من جحيم إعادة الكتابة الكارثية؟

أشارككم قصة حقيقية من قلب المعركة التقنية، عندما كان نظامنا القديم على وشك الانهيار وفشلت محاولات إعادة كتابته. اكتشفوا كيف أنقذنا نمط "التين الخانق" (Strangler...

1 مايو، 2026 قراءة المزيد
ذكاء اصطناعي

من الصندوق الأسود إلى الوضوح: كيف أنقذتنا أدوات SHAP و LIME من جحيم حيرة نماذج الذكاء الاصطناعي

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

1 مايو، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

كان كل فريق يصمم على هواه: كيف أنقذنا ‘نظام التصميم’ من جحيم الفوضى البصرية؟

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

1 مايو، 2026 قراءة المزيد
البودكاست