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

خليني أحكيلكم قصة صارت معي قبل كم سنة، قصة علّمتني درس ما بنساه. كنا في نص الليل، قبل إطلاق ميزة جديدة ومهمة للعميل. الأجواء متوترة، والقهوة شغّالة، وأنا كنت مسؤول عن دمج آخر التعديلات وإطلاق النسخة الجديدة. ضغطت زر الـ “Merge”، ورفعت الكود على السيرفر، وقلت “يا رب”.

ما هي إلا دقائق حتى بدأت الإشعارات تنهال على Slack… “The build is broken!”، “الموقع وقع يا أبو عمر!”، “شو اللي صار؟!”. قلبي صار يدق بسرعة، كيف صار هيك وكل شي كان شغال تمام على جهازي؟ بعد ساعة من التوتر والبحث المحموم، اكتشفت الكارثة. الكارثة كانت عبارة عن فاصلة منقوطة (semicolon) نسيتها في ملف JavaScript. نعم، فاصلة منقوطة واحدة كانت كفيلة بإيقاف كل شيء.

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

ما هي خطافات Git (Git Hooks) بالضبط؟

بكل بساطة، تخيل أن Git هو بيتك، وعمليات مثل git commit أو git push هي أبواب هذا البيت. خطافات Git هي حراس أذكياء يمكنك وضعهم عند هذه الأبواب.

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

أجمل ما في الأمر أن هذه السكربتات موجودة محلياً على جهازك داخل كل مستودع (repository) في مجلد مخفي اسمه .git/hooks. لو فتحت هذا المجلد الآن، ستجد مجموعة من الملفات بأسماء مثل pre-commit.sample و pre-push.sample. كل ما عليك فعله هو إزالة الـ .sample من نهاية الملف وجعل الملف قابلاً للتنفيذ (executable) ليبدأ بالعمل.

كيف غيّرت هذه الخطافات طريقة عملي؟ (أمثلة عملية)

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

الخطاف الأول: pre-commit – حارس البوابة الأمامية

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

مثال 1: فحص الصيغة وجودة الكود (Linting & Formatting)

أول شيء أضفته كان فاحص الصيغة (Linter). لنفترض أننا نعمل على مشروع JavaScript. يمكننا إنشاء ملف باسم .git/hooks/pre-commit ونضع فيه الكود التالي:

#!/bin/sh

echo "Running linter before commit..."

# قم بتشغيل ESLint على الملفات التي تم إضافتها للمرحلة المؤقتة (staged files)
STAGED_JS_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".js$")

if [ -n "$STAGED_JS_FILES" ]; then
  ./node_modules/.bin/eslint $STAGED_JS_FILES
  
  if [ $? -ne 0 ]; then
    echo "ESLint found errors. Commit aborted."
    exit 1
  fi
fi

echo "Linting passed. Proceeding with commit."
exit 0

ماذا يفعل هذا الكود؟

  • يحدد ملفات JavaScript التي أضفتها للـ “commit” (staged files).
  • يقوم بتشغيل أداة ESLint عليها.
  • إذا وجدت ESLint أي أخطاء، يقوم السكربت بإرجاع exit 1، مما يوقف عملية الـ “commit” ويعرض لك الأخطاء لتصلحها.
  • إذا كان كل شيء سليماً، يسمح للـ “commit” بالمرور.

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

الخطاف الثاني: commit-msg – لتوحيد رسائل الـ Commit

هل سئمت من رؤية رسائل “commit” مثل “fix” أو “update” أو “stuff” في تاريخ المشروع؟ أنا أيضاً. رسائل الـ “commit” الواضحة والمنظمة كنز لا يقدر بثمن، خاصة عندما تحاول فهم تاريخ تغيير معين بعد ستة أشهر.

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

مثال: فرض نمط “Conventional Commits”

يمكنك إنشاء ملف .git/hooks/commit-msg للتأكد من أن كل رسالة تبدأ بكلمة مثل feat:, fix:, docs:, chore:.

#!/bin/sh

COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat $COMMIT_MSG_FILE)

# Regex to validate the commit message format
REGEX="^(feat|fix|docs|style|refactor|test|chore)((.+))?: .+"

if ! echo "$COMMIT_MSG" | grep -qE "$REGEX"; then
    echo "ERROR: Your commit message does not follow the Conventional Commits format."
    echo "Example: 'feat(auth): add login endpoint'"
    echo "Please amend your commit message."
    exit 1
fi

exit 0

الآن، إذا حاولت كتابة git commit -m "updated user logic"، سيتم رفض الـ “commit” فوراً مع رسالة توضيحية تطلب منك تعديل الرسالة لتصبح مثلاً git commit -m "refactor(user): simplify user logic". هذا التنظيم يجعل سجل التغييرات (Changelog) يكتب نفسه بنفسه تقريباً!

الخطاف الثالث: pre-push – آخر خط دفاع قبل “الكارثة”

هذا الخطاف يعمل قبل أن تقوم بدفع (push) التزاماتك إلى المستودع البعيد (مثل GitHub أو GitLab). هذا هو المكان المثالي لتشغيل العمليات التي قد تكون أبطأ قليلاً، مثل الاختبارات الشاملة.

مثال: تشغيل الاختبارات التكاملية (Integration Tests)

قبل أن أشارك الكود مع الفريق، أريد أن أتأكد 100% أنني لم أكسر أي جزء آخر من النظام. في ملف .git/hooks/pre-push، يمكنني إضافة أمر تشغيل حزمة الاختبارات الكاملة.

#!/bin/sh

echo "Running full test suite before pushing..."

# قم بتشغيل أمر الاختبارات الخاص بمشروعك
# قد يكون npm test, pytest, go test, ./vendor/bin/phpunit, etc.
npm test

# تحقق من نتيجة الاختبارات
if [ $? -ne 0 ]; then
  echo "Tests failed! Push aborted."
  echo "Please fix the tests before pushing your changes."
  exit 1
fi

echo "All tests passed. Pushing to remote..."
exit 0

هذا الخطاف هو المنقذ الحقيقي. كم من مرة أنقذني من دفع كود يكسر البناء الرئيسي (main branch)؟ أكثر مما أستطيع أن أعد. إنه يمنحك راحة البال قبل مشاركة عملك مع العالم.

نصائح من “الختيار”: كيف تبدأ مع Git Hooks؟

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

1. لا تخترع العجلة من جديد – استخدم الأدوات الجاهزة

كتابة سكربتات Shell يدوياً أمر جيد للتعلم، ولكنه غير عملي للفرق. المشكلة الرئيسية هي أن مجلد .git/hooks لا يتم تضمينه في نظام التحكم بالمصادر (version control). هذا يعني أن كل مطور يجب أن يقوم بإعداد الخطافات يدوياً على جهازه.

الحل هو استخدام أدوات متخصصة تدير هذه الخطافات وتسمح لك بمشاركتها مع الفريق عبر ملف إعدادات واحد في المشروع. أشهر هذه الأدوات:

  • Husky: أداة ممتازة لمشاريع JavaScript/TypeScript. تقوم بإعداد الخطافات تلقائياً عند تشغيل npm install. يمكنك تعريف السكربتات مباشرة في ملف package.json.
  • pre-commit framework: أداة رائعة متعددة اللغات (Python, Go, Rust, JS, …). تقوم بإدارة بيئة معزولة لكل خطاف، مما يجعلها قوية جداً وسهلة الإعداد للجميع.

2. ابدأ بسيطاً ثم توسّع

لا تحاول أتمتة كل شيء من اليوم الأول. ستبدأ بالشعور بالإحباط. نصيحتي: ابدأ بخطاف pre-commit واحد يقوم بمهمة واحدة فقط: تشغيل الـ Linter. عندما تعتاد عليه وتلمس فائدته، أضف خطافاً آخر لتنسيق الكود (formatter) مثل Prettier أو Black. ثم فكر في إضافة اختبارات الوحدات (unit tests) السريعة. التدرج هو مفتاح النجاح.

3. اجعل خطافاتك سريعة!

لا يوجد شيء أكثر إزعاجاً من خطاف pre-commit يستغرق 30 ثانية ليعمل في كل مرة. إذا كانت خطافاتك بطيئة، سيبدأ المطورون (وأنت منهم) بالبحث عن طرق لتجاوزها. احتفظ بالعمليات البطيئة (مثل الاختبارات التكاملية الكاملة) لخطاف pre-push.

4. تذكر أمر --no-verify

في بعض الأحيان النادرة، قد تحتاج إلى عمل “commit” أو “push” بسرعة دون تشغيل الخطافات (مثلاً، تعديل بسيط جداً في ملف README). في هذه الحالة، يمكنك استخدام الراية --no-verify.

# لتجاوز خطافات pre-commit و commit-msg
git commit -m "docs: quick update to readme" --no-verify

# لتجاوز خطاف pre-push
git push origin main --no-verify

لكن احذر! استخدم هذا الأمر بحكمة شديدة وفقط عندما تكون متأكداً 100% أن تغييراتك لن تسبب أي مشكلة.

الخلاصة: من الفوضى إلى الإنتاجية 🚀

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

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

نصيحتي الأخيرة لك: لا تؤجل. افتح اليوم أحد مشاريعك، واختر أداة مثل Husky أو pre-commit، وقم بإعداد أول خطاف لك. قد يستغرق الأمر ساعة من وقتك، لكنه سيوفر عليك وعلى فريقك عشرات الساعات في المستقبل. صدقني، ستشكر نفسك لاحقاً.

أبو عمر

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

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

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

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

آخر المدونات

التوسع والأداء العالي والأحمال

طلباتي كانت تتراكم كطابور لا ينتهي: كيف أنقذني ‘طابور الرسائل’ (Message Queue) من جحيم الاختناقات المفاجئة؟

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

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

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

أنا أبو عمر، مطور برمجيات فلسطيني، وأروي لكم كيف حوّلت الخدمات المصرفية المفتوحة (Open Banking) فوضى حساباتي المالية إلى نظام متكامل. في هذه المقالة، أغوص...

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

اختباراتي كانت واثقة من نفسها أكثر من اللازم: كيف كشف لي ‘الاختبار الطفري’ (Mutation Testing) الثقوب الخفية في جودة الكود؟

كنت أظن أن تغطية الاختبارات بنسبة 100% تعني كودًا مثاليًا، حتى كشف لي الاختبار الطفري أن اختباراتي كانت سطحية وهشة. في هذه المقالة، أشارككم رحلتي...

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

تطبيقي كان كتلة واحدة متجمدة: كيف أنقذتني ‘معمارية الخدمات المصغرة’ (Microservices) من جحيم الصيانة المستحيلة؟

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

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

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

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

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