تخطَّ إلى المحتوى

ملف .gitignore بالتفصيل: ما الذي لا يدخل Git؟

الدرس 6 من 10 · Git و GitHub

في درس add و commit تعرّفت على .gitignore سريعاً: ملف تكتب فيه أسماء ما لا تريد حفظه. لكن المشاريع الحقيقية فيها مئات الملفات المؤقتة والمولَّدة والسرية، وكتابتها واحداً واحداً مستحيلة. في هذا الدرس ستتعلم الأنماط (Patterns) التي تتجاهل مجموعات كاملة بسطر واحد، وكيف تتصرف مع أشهر مشكلة: ملف دخل Git قبل أن تتجاهله.

القاعدة: احفظ في Git ما كتبته بيدك، وتجاهل ما يمكن توليده من جديد أو ما يجب أن يبقى سراً.

النوع أمثلة
مكتبات تُنزَّل تلقائياً node_modules/ و vendor/
نواتج البناء build/ و dist/
ملفات السجلات والمؤقتة *.log و *.tmp
الأسرار والإعدادات المحلية .env وملفات كلمات المرور
ملفات النظام والمحرر .DS_Store و Thumbs.db و .idea/

تخيّل المستودع مثل حقيبة سفر: تضع فيها ما تحتاجه فعلاً، لا كل ما في غرفتك.

في مشروعنا my-site ظهرت ملفات كثيرة أثناء العمل:

نافذة طرفيّة
git status --short
الناتج
?? .env
?? app.log
?? build/
?? debug.log
?? images/
?? node_modules/
?? notes.txt

العلامة ?? تعني «غير متتبَّع». ننشئ ملف .gitignore في جذر المشروع:

.gitignore
# ملفات السجلات
*.log
# مجلدات تتولد تلقائياً
node_modules/
build/
# الأسرار
.env
نافذة طرفيّة
git status --short
الناتج
?? .gitignore
?? images/
?? notes.txt

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

النمط ما يتجاهله
debug.log أي ملف بهذا الاسم، في أي مجلد
*.log كل الملفات التي تنتهي بـ .log
build/ مجلد build وكل ما بداخله (الشرطة في الآخر تعني «مجلد»)
/todo.txt todo.txt في جذر المشروع فقط
docs/*.pdf ملفات PDF داخل docs مباشرة
**/temp/ أي مجلد اسمه temp على أي عمق
# نص تعليق يتجاهله Git

النجمة * تعني «أي حروف»، والسطر الفارغ للتنظيم فقط.

الاستثناء بعلامة التعجب

Section titled “الاستثناء بعلامة التعجب”

تجاهلنا كل ملفات .log، لكن عندنا ملف important.log نريد حفظه. علامة ! في أول السطر تعني «إلا هذا»:

.gitignore
*.log
# استثناء: هذا الملف مهم
!important.log
نافذة طرفيّة
git status --short
الناتج
?? .gitignore
?? images/
?? important.log
?? notes.txt

عاد important.log للظهور. والترتيب مهم: الاستثناء يجب أن يأتي بعد القاعدة التي يستثني منها.

لماذا تجاهل Git هذا الملف؟

Section titled “لماذا تجاهل Git هذا الملف؟”

في المشاريع الكبيرة قد تتفاجأ بملف لا يظهر في git status. الأمر git check-ignore -v يخبرك أي سطر هو السبب:

نافذة طرفيّة
git check-ignore -v debug.log
الناتج
.gitignore:2:*.log debug.log

الملف .gitignore، السطر 2، النمط *.log. ولرؤية كل ما يتجاهله Git حالياً أضف --ignored:

نافذة طرفيّة
git status --short --ignored
الناتج
?? .gitignore
?? images/
?? important.log
?? notes.txt
!! .env
!! app.log
!! build/
!! debug.log
!! node_modules/

العلامة !! تعني «متجاهَل».

الفخ الأشهر: الملف محفوظ من قبل

Section titled “الفخ الأشهر: الملف محفوظ من قبل”

.gitignore يؤثر فقط على الملفات غير المتتبَّعة. الملف الذي دخل Git في commit سابق يبقى متتبَّعاً حتى لو أضفته إلى .gitignore. ملف config.json عندنا محفوظ من أول commit. أضفناه إلى .gitignore ثم عدّلناه:

نافذة طرفيّة
git status --short
الناتج
M .gitignore
M config.json

ما زال Git يراقبه! الحل أن تطلب منه إيقاف التتبع مع إبقاء الملف على جهازك:

نافذة طرفيّة
git rm --cached config.json
الناتج
rm 'config.json'
نافذة طرفيّة
git status --short
الناتج
M .gitignore
D config.json

D تعني أن الملف سيُحذف من المستودع في الـ commit القادم. لكنه باقٍ على القرص، فالخيار --cached يحذف من منطقة التجهيز فقط. بعد الحفظ:

نافذة طرفيّة
git add .gitignore
git commit -m "إيقاف تتبع config.json"
الناتج
[main b655445] إيقاف تتبع config.json
2 files changed, 1 insertion(+), 1 deletion(-)
delete mode 100644 config.json

من الآن أي تعديل على config.json لا يظهر في git status.

  • قوالب جاهزة: لا تبدأ من الصفر. عند إنشاء مستودع على GitHub تجد قائمة «Add .gitignore» فيها قالب لكل لغة وإطار عمل.
  • تجاهل شخصي: ملفات محررك ونظامك لا تخص بقية الفريق. ضعها في ملف عام على جهازك وعرّفه مرة واحدة: git config --global core.excludesFile ~/.gitignore_global.
  • المجلدات الفارغة: Git يتتبع الملفات لا المجلدات، فالمجلد الفارغ لا يُحفظ. العُرف الشائع أن تضع فيه ملفاً فارغاً اسمه .gitkeep.
  • أكثر من ملف: يمكن وضع .gitignore داخل مجلد فرعي، وتنطبق قواعده على ذلك المجلد وما تحته.
  1. في مستودع تجريبي أنشئ الملفات a.tmp و b.tmp و keep.tmp ومجلداً cache فيه ملف.
  2. اكتب .gitignore يتجاهل كل ملفات .tmp ما عدا keep.tmp، ويتجاهل مجلد cache.
  3. تحقق بـ git status --short --ignored، واسأل git check-ignore -v a.tmp عن السبب.
  4. تحدٍّ: احفظ ملف settings.local في commit، ثم أوقف تتبعه بـ git rm --cached وأضفه إلى .gitignore، وتأكد أن تعديله لم يعد يظهر.
  • إضافة الملف إلى .gitignore بعد حفظه: لا يكفي. أوقف تتبعه بـ git rm --cached.
  • نسيان --cached: git rm config.json بدونها يحذف الملف من القرص أيضاً.
  • الاستثناء قبل القاعدة: !important.log ثم *.log يتجاهل الملف، لأن القاعدة الأخيرة هي التي تفوز.
  • مسافات زائدة: مسافة في آخر السطر تصبح جزءاً من النمط فلا يطابق شيئاً.

سؤال

أضفت secret.txt إلى .gitignore لكنه محفوظ في commit سابق. ماذا يحدث عند تعديله؟

سؤال

ما معنى السطر !keep.log في ملف .gitignore؟

  • تجاهل ما يُولَّد تلقائياً وما هو سري، واحفظ ما كتبته بيدك.
  • *.log لنوع ملفات، و build/ لمجلد، و /file للجذر فقط، و ! للاستثناء.
  • git check-ignore -v يشرح سبب التجاهل، و git status --ignored يعرض المتجاهَل.
  • الملف المتتبَّع لا يتأثر بـ .gitignore: أوقف تتبعه بـ git rm --cached.
  • السر الذي دخل التاريخ مكشوف: غيّره فوراً.