كانت أخطاؤنا الصغيرة تتسلل للإنتاج: كيف أنقذتنا خطافات Git (Git Hooks) من جحيم التسليمات المحرجة؟

يا جماعة الخير، السلام عليكم ورحمة الله وبركاته.

قبل كم سنة، كنت شغال في فريق على مشروع كبير ومستعجل. ليلة من الليالي، كنا سهرانين عشان نسلّم “هوت فيكس” (Hotfix) ضروري جدًا للعميل. التعب واصل حده، والتركيز في الحضيض. واحد من الشباب، وهو بيشتغل على حل المشكلة، ترك كم سطر console.log('test 123') وكم تعليق فيه “TODO: remove this later” في الكود. طبعًا في عجقة الشغل والتسليم، ما حدا انتبه.

عملنا push للكود، عملنا deploy… والحمد لله المشكلة الأساسية انحلت. نمنا مرتاحين البال. ثاني يوم الصبح، بنصحى على إيميل من مدير المشروع، ومعاه سكرين شوت من الـ console في المتصفح عند العميل، وفيها “test 123” طالعة بشكل فاضح. صحيح إنها ما كسرت إشي، بس شكلنا كان سيء جدًا. صارت قصة، أو زي ما بنحكي “صارت فضيحة صغيرة”.

هذا الموقف المحرج، مع إنه بسيط، كان هو الشرارة اللي خلتنا ندوّر على حل جذري. كيف نمنع هاي الأخطاء البشرية الصغيرة إنها توصل للإنتاج؟ الجواب كان أبسط وأقوى مما توقعنا: خطافات Git (Git Hooks).

ما هي خطافات Git (Git Hooks)؟ وليش لازم نهتم فيها؟

ببساطة شديدة، الـ Git Hooks هي عبارة عن سكربتات (scripts) بتشتغل تلقائيًا عند نقاط معينة في دورة حياة Git. يعني، بتقدر تخلي Git ينفّذ أوامر معينة قبل ما تعمل commit، أو قبل ما تعمل push، أو بعد ما تعمل merge، وهلم جرا.

تشبيه بسيط: الحارس الشخصي للكود (The Bodyguard)

تخيل إن الكود تبعك هو شخصية مهمة رايحة على حفلة (الحفلة هي الـ code base تبعك). الـ Git Hook هو الحارس الشخصي (البودي جارد) اللي واقف على الباب. قبل ما يخلّي أي كود يفوت، بيعمل عليه تفتيش كامل:

  • هل الكود نظيف ومهندم؟ (Linting)
  • هل يتبع القواعد العامة للمكان؟ (Code style)
  • هل معه “تصريح أمني”؟ (Passing tests)
  • هل في كلام مش لازم ينحكى جوه؟ (مثل console.log أو كلمات مثل “WIP”)

إذا كل إشي تمام، الحارس بيسمح له بالدخول. إذا في أي مشكلة، بيرجّعه من الباب وبيقول له: “ارجع صلّح حالك وتعال!”. هذا بالضبط ما تفعله الـ Git Hooks، فهي تحمي مستودع الكود الخاص بك من الأخطاء غير المقصودة.

كيف تعمل الـ Git Hooks؟ رحلة الكود قبل الـ Commit

لما تعمل git init في أي مشروع، Git بيخلق مجلد مخفي اسمه .git. جوه هذا المجلد، في مجلد ثاني اسمه hooks. لو فتحته، رح تلاقي فيه مجموعة ملفات بتنتهي بـ .sample. هاي هي أمثلة للـ Hooks اللي ممكن تستخدمها.

عشان تفعّل أي hook، كل اللي عليك تعمله هو إنك تشيل الـ .sample من اسم الملف، وتتأكد إن الملف قابل للتنفيذ (executable).

الـ Hooks نوعين رئيسيين: خطافات جانب العميل (Client-Side) وخطافات جانب الخادم (Server-Side).

خطافات جانب العميل (Client-Side Hooks)

هاي الخطافات بتشتغل على جهازك المحلي، وهي اللي رح نركز عليها اليوم لأنها بتأثر بشكل مباشر على إنتاجيتك وجودة عملك اليومي. أشهرها:

  • pre-commit: الأهم على الإطلاق. بيشتغل قبل ما Git يجهز رسالة الـ commit. هذا هو المكان المثالي لفحص الكود، تشغيل الـ linter، والتأكد من عدم وجود أخطاء. إذا السكربت رجّع قيمة غير الصفر (exit code non-zero)، عملية الـ commit رح تفشل.
  • prepare-commit-msg: بيشتغل بعد الـ pre-commit وقبل ما يفتح محرر رسائل الـ commit. مفيد عشان تعدل رسالة الـ commit تلقائيًا، مثلاً تضيف رقم الـ ticket من اسم الـ branch.
  • commit-msg: بيشتغل بعد ما تكتب رسالة الـ commit وقبل ما يتم تسجيلها. هذا هو المكان المناسب للتأكد من أن رسالة الـ commit تتبع نسقًا معينًا (مثلاً Conventional Commits).
  • post-commit: بيشتغل بعد ما تتم عملية الـ commit بنجاح. ممكن تستخدمه عشان ترسل إشعار (notification) أو تعمل أي عملية لا تؤثر على الـ commit نفسه.

نصيحة من ختيار في الكار

ركز على الـ pre-commit. لو بدك تبدأ بخطاف واحد بس، خليه يكون هذا. 90% من الفوائد اللي رح تحصل عليها من الـ Hooks بتيجي من هذا الخطاف تحديدًا.

مثال عملي: إنشاء Pre-Commit Hook يدويًا

لنفترض أننا نريد منع أي commit يحتوي على console.log أو debugger. افتح ملف جديد في .git/hooks/pre-commit (بدون امتداد .sample) واكتب فيه الكود التالي (هذا سكربت Shell):

#!/bin/sh

# هذا السكربت سيمنع أي commit يحتوي على كلمات محظورة

# ابحث عن الكلمات المحظورة في الملفات المعدلة (staged files)
FORBIDDEN_STRINGS=("console.log" "debugger" "WIP")

for STRING in "${FORBIDDEN_STRINGS[@]}"
do
  if git diff --cached | grep -q "$STRING"; then
    echo "=================================================="
    echo "يا زلمة! لقيت كلمة '$STRING' في الكود تبعك."
    echo "نظّف الكود قبل ما تعمل commit الله يرضى عليك."
    echo "=================================================="
    exit 1 # أفشل عملية الـ commit
  fi
done

# إذا كل شيء تمام، شغل الـ linter
echo "ما في كلمات محظورة، جاري تشغيل الـ Linter..."
npm run lint

# تحقق من نتيجة أمر الـ linter
if [ $? -ne 0 ]; then
  echo "=================================================="
  echo "الـ Linter زعلان، صلّح الأخطاء بالأول."
  echo "=================================================="
  exit 1 # أفشل عملية الـ commit
fi

exit 0 # اسمح بالـ commit

بعد ما تحفظ الملف، لازم تعطيه صلاحيات التنفيذ عن طريق الأمر التالي في الـ terminal:

chmod +x .git/hooks/pre-commit

الآن، جرب تعدل أي ملف وتضيف فيه console.log('test')، ثم حاول تعمل git commit. رح تشوف كيف الـ hook بيمنعك وبيطلع لك رسالة الخطأ اللي كتبناها.

الطريقة الاحترافية: أتمتة إدارة الـ Hooks مع Husky و lint-staged

الطريقة اليدوية اللي شفناها فوق ممتازة، بس فيها مشكلتين رئيسيتين:

  1. مجلد .git/hooks لا يتم إضافته إلى مستودع Git، يعني هاي السكربتات رح تكون على جهازك بس، وما رح تنتقل لباقي أعضاء الفريق.
  2. إدارتها وتحديثها لكل أعضاء الفريق بشكل يدوي هو كابوس.

وهنا يأتي دور الأدوات الاحترافية اللي بتحل هاي المشاكل. أشهر أداتين في عالم الـ JavaScript/TypeScript هما Husky و lint-staged.

  • Husky: أداة بتخليك تدير الـ Git Hooks تبعتك من خلال ملف package.json. لما أي مطور يعمل npm install، Husky بيقوم بتثبيت الـ Hooks تلقائيًا في مجلد .git/hooks عنده. هيك بنضمن إنه كل الفريق بيستخدم نفس القواعد.
  • lint-staged: أداة ذكية جدًا بتشتغل مع Husky. بدل ما تشغل الـ linter أو الـ formatter على كل ملفات المشروع (وهذا بطيء جدًا)، lint-staged بيشغل الأوامر فقط على الملفات اللي أنت عدلتها وعملت لها git add (يعني staged files).

مثال عملي باستخدام Husky و lint-staged

1. قم بتثبيت الأدوات:

npm install husky lint-staged --save-dev

2. قم بتفعيل Husky:

npx husky install
npm pkg set scripts.prepare="husky install"

3. أضف الـ pre-commit hook:

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

4. قم بإعداد lint-staged في ملف package.json الخاص بك:

"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ],
  "*.{json,css,md}": [
    "prettier --write"
  ]
}

بهذا الإعداد البسيط، قبل كل عملية commit، سيحدث التالي تلقائيًا:

  • Husky سيقوم بتشغيل lint-staged.
  • lint-staged سينظر إلى الملفات التي قمت بتعديلها (staged files).
  • إذا كانت ملفات JavaScript أو TypeScript، سيقوم بتشغيل ESLint لإصلاح الأخطاء تلقائيًا، ثم Prettier لتنسيق الكود.
  • إذا كانت ملفات JSON أو CSS، سيقوم بتشغيل Prettier لتنسيقها.
  • إذا كان هناك أي خطأ لا يمكن إصلاحه تلقائيًا، ستفشل عملية الـ commit وستظهر لك رسالة بالخطأ لإصلاحه يدويًا.

هذا هو السحر بعينه. لقد حولنا عملية يدوية ومملة وسهلة النسيان إلى شبكة أمان آلية لا يمكن تجاوزها.

خطافات جانب الخادم (Server-Side Hooks)

على السريع، هاي الخطافات بتشتغل على السيرفر اللي مستضيف الـ repository تبعك (مثل GitHub, GitLab). هاي ما بتقدر أنت كمطور تعدلها مباشرة، بل مدير النظام هو اللي بيتحكم فيها. تُستخدم لفرض سياسات على مستوى المشروع ككل، مثلاً:

  • pre-receive: يُنفذ قبل تحديث أي branch. يمكن استخدامه لمنع الـ force push على الـ main branch، أو للتأكد من أن كل الـ commits موقعة رقميًا.
  • post-receive: يُنفذ بعد نجاح عملية الـ push. يُستخدم عادةً لإرسال إيميلات للفريق، أو لتشغيل الـ CI/CD pipeline.

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

يا جماعة، القصة وما فيها إن الـ Git Hooks هي مش مجرد أداة “حلوة” أو رفاهية. هي جزء أساسي من بنية تحتية لأي فريق برمجي محترف. هي الفرق بين فريق يعاني من أخطاء محرجة باستمرار، وفريق يسلّم الكود بثقة وهدوء بال.

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

نصيحتي الأخيرة: لا تنتظر حتى تحدث “فضيحة صغيرة” في مشروعك. ابدأ اليوم. ابدأ بسيطًا، ولو بسكربت يدوي يمنع الـ console.log. مع الوقت، ابنِ عليه وطوّر منظومة الأتمتة الخاصة بك. صدقني، مستقبلك البرمجي رح يشكرك. ✅

أبو عمر

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

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

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

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

آخر المدونات

ادارة الفرق والتنمية البشرية

كان الخوف من الفشل يشلّ فريقنا: كيف أنقذتنا ‘السلامة النفسية’ من جحيم الأفكار التي لم تولد قط؟

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

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

كانت نماذجنا تهذي بلا توقف: كيف أنقذنا ‘التوليد المعزز بالاسترجاع’ (RAG) من جحيم الهلوسات؟

في أحد المشاريع، كاد نموذج الذكاء الاصطناعي أن "يخرب بيتنا" بهلوساته وإجاباته الخاطئة. هذه المقالة تروي قصة كيف أنقذتنا تقنية التوليد المعزز بالاسترجاع (RAG)، وتشرح...

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

كنا نبني جدرانًا رقمية: كيف فتحت لنا ‘إمكانية الوصول’ (Accessibility) أبوابًا لم نكن نراها؟

اعتقدنا أننا نبني تطبيقات رائعة، لكننا كنا في الحقيقة نبني جدرانًا رقمية. في هذه المقالة، يشارك أبو عمر كيف غيّر فهم 'إمكانية الوصول' (Accessibility) منظوره...

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