التزاماتنا البرمجية كانت قنابل موقوتة: كيف أنقذتنا ‘خطافات Git’ من جحيم ‘لقد كسر أحدهم البناء’؟

أذكرها وكأنها البارحة. كانت ليلة خميس، وأجواء المكتب بدأت تهدأ. الكل يجهز نفسه لعطلة نهاية الأسبوع، وأنا كنت أضع اللمسات الأخيرة على ميزة جديدة عملت عليها طويلاً. فجأة، علت أصوات الإشعارات من قناة “Slack” الخاصة بالفريق، تلك الإشعارات الحمراء التي لا تبشر بخير أبداً. “🔴 Build Failed on main”.

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

المشكلة ليست في المبرمج، بل في العملية

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

نحن نعتمد على أنفسنا لنتذكر قائمة طويلة من المهام قبل كل عملية git commit أو git push:

  • هل قمت بتنسيق الكود (Code Formatting)؟
  • هل قمت بتشغيل مدقق الشيفرة (Linting)؟
  • هل قمت بتشغيل كافة الاختبارات (Unit Tests)؟
  • هل رسالة الالتزام (Commit Message) تتبع المعايير المتفق عليها؟

هذه العملية اليدوية هي وصفة للكارثة. إنها مجرد مسألة وقت قبل أن ينسى أحدهم خطوة ما تحت ضغط العمل، وتنفجر “القنبلة الموقوتة” في نظام التكامل المستمر (CI/CD) لدينا.

الحل السحري: لنتعرف على خطافات Git (Git Hooks)

هنا يأتي دور البطل الصامت في عالم Git: “الخطافات” أو Git Hooks. ببساطة، خطافات Git هي عبارة عن سكربتات (scripts) برمجية يمكنك إعدادها لتعمل تلقائياً عند وقوع أحداث معينة في Git. فكر فيها كحارس أمن يقف على باب مستودعك البرمجي.

قبل أن تسمح لأي “التزام” (commit) بالدخول، يقوم هذا الحارس بفحصه والتأكد من مطابقته للقواعد. إذا لم يطابقها، يمنعه من الدخول ويرجعه لصاحبه ليقوم بتعديله.

أشهر أنواع الخطافات:

  • pre-commit: يعمل هذا الخطاف قبل إنشاء الالتزام مباشرةً. إنه المكان المثالي لتشغيل مهام سريعة مثل تنسيق الكود والتحقق من الأخطاء البسيطة (linting). إذا فشل السكربت، يتم إلغاء عملية الالتزام.
  • commit-msg: يعمل بعد كتابة رسالة الالتزام وقبل إنشائه فعلياً. رائع لفرض معايير محددة على رسائل الالتزام (مثل Conventional Commits).
  • pre-push: يعمل قبل دفع (push) التزاماتك إلى المستودع البعيد (remote repository). هذا هو المكان الأنسب لتشغيل مهام أطول وأكثر شمولاً، مثل مجموعة الاختبارات الكاملة (test suite).

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

“بس يا أبو عمر، هالشغلانة معقدة!” – نقدم لكم Husky 🐺

لهذا السبب بالذات، ظهرت أدوات لتسهيل هذه العملية. وأشهرها وأروعها برأيي هي أداة اسمها Husky. Husky هي أداة بسيطة تجعل إدارة خطافات Git أمراً سهلاً للغاية وتسمح بمشاركتها مع كل أعضاء الفريق عبر package.json.

Husky يقوم بتوصيل خطافات Git بأوامر npm scripts، مما يعني أن الإعدادات تصبح جزءاً من المشروع نفسه، ويحصل عليها كل مطور تلقائياً بمجرد تثبيت تبعيات المشروع.

لنطبق الأمر عملياً: إعداد Husky خطوة بخطوة

لنفترض أن لدينا مشروع JavaScript/TypeScript ونريد أن نتأكد من أن كل كود يتم الالتزام به منسق وخالٍ من أخطاء الـ linting.

الخطوة 1: تثبيت Husky

# باستخدام npm
npm install husky --save-dev

# أو باستخدام yarn
yarn add husky --dev

الخطوة 2: تفعيل خطافات Git في مشروعك

بعد التثبيت، قم بتشغيل هذا الأمر لمرة واحدة:

npx husky install

هذا الأمر سيقوم بإنشاء مجلد .husky في مشروعك. لجعل هذه العملية تلقائية لكل من ينضم للفريق، أضف السكربت التالي إلى ملف package.json:

# هذا يضمن أن `husky install` يعمل تلقائياً بعد كل `npm install`
npm set-script prepare "husky install"

الخطوة 3: إنشاء أول خطاف (pre-commit)

لنفترض أن لدينا سكربت اسمه npm run lint. نريد تشغيله قبل كل عملية commit. الأمر بسيط:

npx husky add .husky/pre-commit "npm run lint"

هذا الأمر سينشئ ملفاً جديداً باسم pre-commit داخل مجلد .husky يحتوي على الأمر الذي حددناه. الآن، في كل مرة يحاول أي مطور في الفريق عمل git commit، سيتم تشغيل npm run lint تلقائياً. إذا فشل الأمر، ستفشل عملية الـ commit. رائع!

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

شريك Husky المفضل: `lint-staged`

هنا يأتي دور أداة أخرى عبقرية تعمل بتناغم تام مع Husky، وهي lint-staged. فكرتها بسيطة: لماذا نشغل الأوامر على كل ملفات المشروع، بينما يمكننا تشغيلها فقط على الملفات التي تم تعديلها وإضافتها إلى منطقة التجهيز (staged files)؟

الخطوة 1: تثبيت `lint-staged`

npm install lint-staged --save-dev

الخطوة 2: إعداد `lint-staged`

أضف الإعدادات الخاصة به إلى ملف package.json:

// في ملف package.json
"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ],
  "*.{json,css,md}": "prettier --write"
}

هذا الإعداد يخبر lint-staged بالآتي: لأي ملف JavaScript أو TypeScript جاهز للالتزام، قم بتشغيل eslint --fix ثم prettier --write عليه. ولأي ملفات أخرى مثل JSON أو CSS، قم فقط بتنسيقها باستخدام Prettier.

الخطوة 3: تحديث خطاف `pre-commit`

الآن، بدلاً من تشغيل npm run lint، سنجعل الخطاف يشغل lint-staged:

npx husky set .husky/pre-commit "npx lint-staged"

والآن، أصبحت العملية آلية وذكية وسريعة جداً. قبل كل commit، سيتم فحص وتنسيق الملفات المعدلة فقط. يا سلام! انتهى زمن الالتزامات البرمجية الفوضوية.

سيناريوهات متقدمة ونصائح من الميدان

بمجرد أن تتقن الأساسيات، يمكنك فعل الكثير مع Husky.

فرض معايير على رسائل الالتزام (Commit Messages)

تاريخ Git النظيف هو كنز لا يقدر بثمن. باستخدام أداة مثل commitlint مع خطاف commit-msg، يمكنك إجبار الفريق على اتباع نمط معين في كتابة الرسائل (مثل Conventional Commits)، مما يسهل تتبع التغييرات وإنشاء سجلات التغيير (Changelogs) تلقائياً.

# تثبيت الأدوات
npm install @commitlint/cli @commitlint/config-conventional --save-dev

# إنشاء ملف الإعدادات
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

# إضافة الخطاف
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

تشغيل الاختبارات قبل الدفع (pre-push)

لتجنب كسر “البناء” على الفرع الرئيسي، يمكنك إضافة خطاف pre-push لتشغيل الاختبارات الأساسية.

npx husky add .husky/pre-push "npm test"

نصيحة عملية جداً من أبو عمر: كن حذراً مع خطاف pre-push. إذا كانت مجموعة الاختبارات لديك تستغرق 5 أو 10 دقائق، فسيشعر المطورون بالإحباط وسيبحثون عن طرق لتجاوزها (مثل استخدام git push --no-verify). القاعدة الذهبية هي: اجعل الخطافات المحلية سريعة. استخدم pre-push للاختبارات السريعة والحرجة فقط، واترك الاختبارات الشاملة والطويلة لخادم الـ CI/CD. التوازن هو مفتاح النجاح.

الخلاصة: من قنابل موقوتة إلى التزامات واثقة 😌

رحلتنا بدأت من الفوضى والإحباط بسبب أخطاء كان من الممكن تفاديها بسهولة. المشكلة لم تكن في قدراتنا كمبرمجين، بل في اعتمادنا على عمليات يدوية هشة. من خلال تبني الأتمتة في أبسط صورها عبر خطافات Git، وبمساعدة أدوات مثل Husky و lint-staged، حولنا عملية الالتزام البرمجي من حقل ألغام إلى مسار آمن وموثوق.

النتائج كانت مذهلة:

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

يا جماعة، استثمار بضع دقائق في إعداد هذه الأدوات سيوفر عليكم ساعات، بل أياماً، من وجع الراس لاحقاً. أتمتة هذه العمليات ليست رفاهية، بل هي من أساسيات الهندسة البرمجية الحديثة التي تفرق بين فريق هاوٍ وفريق محترف. ابدأوا اليوم، وسترون الفرق بأنفسكم. يلا، شدّوا حيلكم! 💪

أبو عمر

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

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

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

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

آخر المدونات

برمجة وقواعد بيانات

تحديثات قاعدة البيانات بدون توقف: كيف أنقذنا نمط التوسيع والتعاقد (Expand/Contract) من جحيم التوقفات المجدولة؟

هل سئمت من إيقاف الخدمة مع كل تحديث لهيكلة قاعدة البيانات؟ أشارككم قصة حقيقية وكيف أنقذنا نمط التوسيع والتعاقد (Expand/Contract) من ليالي النشر الطويلة والمُجهدة،...

4 يونيو، 2026 قراءة المزيد
الشبكات والـ APIs

كانت إعادة المحاولة كارثة: كيف أنقذتنا مفاتيح عدم تكرار العمليات (Idempotency Keys) من جحيم الفواتير المزدوجة؟

أشارككم قصة حقيقية من الخنادق البرمجية، يوم كاد خطأ بسيط في إعادة محاولة طلبات الدفع أن يكلفنا سمعتنا وأموال عملائنا. اكتشفوا معنا كيف كانت مفاتيح...

4 يونيو، 2026 قراءة المزيد
الحوسبة السحابية

من التوقف التام إلى النجاة: كيف أنقذتنا استراتيجية “الضوء المرشد” (Pilot Light) يوم انقطعت السحابة؟

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

4 يونيو، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

كانت مهمتي البرمجية للاختبار مجرد كود: كيف أنقذني توثيق القرارات من جحيم الصمت بعد المقابلة؟

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

4 يونيو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

من الانتظار لأيام إلى الدفع في ثوانٍ: كيف أنقذتنا شبكات الدفع الفوري من جحيم التحويلات البنكية؟

أسرد لكم من واقع تجربتي كـ "أبو عمر"، كيف عانينا من بطء وتكلفة التحويلات البنكية الدولية، وكيف جاءت شبكات الدفع الفوري ومعيار ISO 20022 لتكون...

4 يونيو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كان كل خادم لدينا ‘ندفة ثلج’ فريدة: كيف أنقذنا ‘الكود كبنية تحتية’ (IaC) من جحيم الانجراف اليدوي؟

في هذه المقالة، أشارككم قصة حقيقية من قلب المعركة التقنية مع "خوادم ندفات الثلج" الفوضوية. سنغوص في مفهوم "الكود كبنية تحتية" (IaC) وكيف أن أدوات...

4 يونيو، 2026 قراءة المزيد
اختبارات الاداء والجودة

كانت تغطية الاختبارات 100% لكن الأخطاء تتسرب: كيف أنقذنا “الاختبار الطفري” من جحيم الثقة الزائفة؟

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

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