التزاماتي كانت تكسر البناء: كيف أنقذتني خطافات 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، وقم بإعداد أول خطاف لك. قد يستغرق الأمر ساعة من وقتك، لكنه سيوفر عليك وعلى فريقك عشرات الساعات في المستقبل. صدقني، ستشكر نفسك لاحقاً.

أبو عمر

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

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

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

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

آخر المدونات

البنية التحتية وإدارة السيرفرات

وداعاً لـ `kubectl apply -f`: كيف حولنا إدارة Kubernetes إلى عملية آلية وموثوقة مع GitOps؟

في هذه المقالة، يشارككم أبو عمر، مطور برمجيات فلسطيني، قصة حقيقية حول مخاطر الإدارة اليدوية لـ Kubernetes وكيف أنقذنا مبدأ GitOps من كوارث محتملة. سنتعمق...

13 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

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

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

13 مايو، 2026 قراءة المزيد
أتمتة العمليات

كانت عملياتنا كالدومينو: كيف أنقذنا “منسق سير العمل” من جحيم الفشل المتتالي؟

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

13 مايو، 2026 قراءة المزيد
نصائح برمجية

كانت شفرتنا هرماً من الجحيم: كيف أنقذتنا ‘شروط الحماية’ (Guard Clauses) من فوضى الـ if-else المتداخلة؟

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

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

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

في هذه المقالة، أسرد لكم تجربتي كـ"أبو عمر" مع جحيم الأنظمة المترابطة بإحكام (Tight Coupling) وكيف كانت "المعمارية القائمة على الأحداث" (Event-Driven Architecture) طوق النجاة...

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

متجر الميزات (Feature Store): كيف أنقذنا مشروعنا من جحيم “الانحراف التدريبي-التنبؤي”؟

أشارككم قصة حقيقية عن "الانحراف التدريبي-التنبؤي" (Training-Serving Skew)، الكابوس الصامت الذي كاد أن يدمر أحد مشاريعنا في الذكاء الاصطناعي. اكتشفوا كيف كان "متجر الميزات" (Feature...

13 مايو، 2026 قراءة المزيد
خوارزميات

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

أشارككم قصة حقيقية من قلب المعركة البرمجية، وكيف أنقذتنا خوارزمية بسيطة وعبقرية تُدعى "مرشح بلوم" (Bloom Filter) من انهيار قاعدة البيانات تحت وطأة الاستعلامات المتكررة....

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