دليل

ملف .gitignore: كيف تستبعد الملفات من Git وتزيل ما أُضيف منها

آخر تحديث: · Skillaria.Top

يسرد ملف .gitignore في جذر المستودع أنماط الملفات والمجلدات التي لن يتتبعها Git، مثل التبعيات والبناءات والسجلات والأسرار. ولا يسري إلا على الملفات غير المتعقَّبة، لذلك يجب إزالة الملف الذي سبق إيداعه من الفهرس بالأمر git rm --cached.

آلية git ignore وسيلة لإخبار Git بقولك: «لا تلمس هذه الملفات، ولا تعرضها في git status، ولا تضفها بـ git add .». تُكتب القواعد في ملف نصي باسم .gitignore يُرفع مع المشروع ويعمل لكل الفريق. والدقيقة الأساسية: التجاهل يسري فقط على الملفات التي لا يتعقبها Git بعد.

ما الذي يُضاف عادةً إلى .gitignore

  • التبعيات: node_modules/ وvendor/ و.venv/ — يعيد مدير الحزم بناءها؛
  • نتائج البناء: dist/ وbuild/ و*.class و__pycache__/؛
  • السجلات والملفات المؤقتة: *.log وtmp/ و*.swp؛
  • الأسرار والإعدادات المحلية: .env والمفاتيح والإعدادات المحلية؛
  • مخلفات نظام التشغيل والمحررات: .DS_Store وThumbs.db و.idea/ — ولكن الأفضل وضعها في التجاهل العام، كما سيأتي.

القاعدة بسيطة: يجب أن يحتوي المستودع على ما يكتبه الناس، لا على ما تولّده البرامج أو ما يعتمد على جهاز بعينه.

كيف تنشئ .gitignore

هو ملف نصي عادي في جذر المستودع. أنشئه، واكتب الأنماط سطراً في كل مرة، ثم أودعه:

cat > .gitignore <<'EOF'
# التبعيات
node_modules/
# البناء
dist/
# السجلات
*.log
# الأسرار
.env
EOF

git add .gitignore
git commit -m "chore: إضافة .gitignore"

توجد قوالب جاهزة للغات والأطر الشائعة في مستودع github/gitignore، كما يقترح GitHub وGitLab اختيار قالب عند إنشاء المشروع. خذها أساساً، واحذف منها ما لا تحتاجه.

صياغة أنماط .gitignore

النمطما الذي يتجاهله
*.logكل الملفات ذات الامتداد .log في أي مجلد
build/مجلد build في أي مستوى (الشرطة المائلة في النهاية = المجلدات فقط)
/buildمجلد build في الجذر فقط (الشرطة في البداية تربطه بمجلد ملف .gitignore)
docs/*.pdfملفات pdf داخل docs مباشرة، لا داخل docs/old/
docs/**/*.pdfملفات pdf في docs وكل مجلداتها الفرعية
**/temptemp في أي مجلد
!keep.logاستثناء: لا تتجاهل keep.log
file?.txt? — أي رمز واحد
[ab].txta.txt أو b.txt
# تعليقسطر تعليق

ملاحظة مهمة: النمط الذي لا يحوي شرطة مائلة داخله (config.json) يُطبَّق على أي مستوى، أما النمط الذي فيه شرطة مائلة في البداية أو الوسط (/config.json، src/config.json) فيُطبَّق نسبةً إلى المجلد الذي يقع فيه ملف .gitignore.

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

*.log
!important.log

فخ: لا يمكن «استرجاع» ملف إذا كان مجلده الأب متجاهلاً. لا يدخل Git المجلدات المتجاهلة، لذلك لن ينجح هذا:

logs/
!logs/keep.txt     # لا يعمل

الصحيح هو تجاهل محتويات المجلد لا المجلد نفسه:

logs/*
!logs/keep.txt

وبالحيلة نفسها تحفظ مجلداً فارغاً في المستودع: لا يخزّن Git المجلدات الفارغة، فيُوضع فيها ملف .gitkeep ويُسمح به وحده.

أماكن أخرى لضبط التجاهل

المكانيسري علىيدخل المستودع
.gitignore في الجذر والمجلدات الفرعيةالفريق كلهنعم
.git/info/excludeهذه النسخة فقطلا
الملف العام core.excludesFileكل مستودعاتكلا

من المعقول نقل مخلفات نظام التشغيل والـ IDE إلى التجاهل العام، حتى لا تزدحم .gitignore المشتركة:

git config --global core.excludesFile ~/.gitignore_global
echo ".DS_Store" >> ~/.gitignore_global
echo ".idea/" >> ~/.gitignore_global

إذا لم يكن core.excludesFile مضبوطاً فإن Git يقرأ ~/.config/git/ignore إذا كان موجوداً.

لماذا لا يعمل .gitignore

أكثر شكوى شيوعاً: «أضفت الملف إلى .gitignore لكن Git ما زال يُظهر التغييرات». السبب في الغالب واحد — الملف متعقَّب أصلاً. التجاهل لا يؤثر في الملفات التي دخلت commit مرة.

لمعرفة القاعدة التي تعمل (أو لماذا لا تعمل) استخدم git check-ignore:

git check-ignore -v logs/app.log
# .gitignore:3:*.log	logs/app.log

يُظهر الناتج الملف ورقم السطر في القاعدة. والناتج الفارغ يعني أن الملف غير متجاهل. وسبب آخر للعطل هو المسافات في نهاية سطر النمط، أو ترميز الملف الخاطئ (مثل UTF-16 عند إنشائه من PowerShell).

إزالة ملف سبق إيداعه: git rm --cached

الأمر git rm يحذف الملف من الفهرس ومن القرص. ومع الخيار --cached يحذفه من الفهرس فقط: يبقى الملف عندك، لكنه يتوقف عن التعقب.

echo ".env" >> .gitignore
git rm --cached .env
git commit -m "chore: لم يعد .env متعقَّباً"
git push

بالنسبة للمجلد نحتاج إلى -r:

git rm -r --cached node_modules/

إذا كانت التعديلات كثيرة ولست متأكداً مما دخل المستودع، يمكن إعادة بناء الفهرس بالكامل: git rm -r --cached .، ثم git add . والـ commit. وقبل الـ commit تحقق من git status — ستظهر فيه الملفات المحذوفة من الفهرس.

تنبيه: الأسرار تبقى في التاريخ

git rm --cached يزيل الملف من الـ commits اللاحقة، لا من السابقة. فإذا دخلت كلمة مرور أو رمز إلى المستودع تكون متاحة في التاريخ لكل من لديه نسخة. يجب اعتبار السر مكشوفاً وإعادة إصداره. ويمكن إعادة كتابة التاريخ بأدوات مثل git filter-repo، لكن هذا يغيّر hash كل الـ commits اللاحقة ويحتاج إلى تنسيق مع الفريق.

نتيجة أخرى: عند الزملاء، بعد git pull، سيُحذف من القرص الملف الذي أزلته من الفهرس بـ --cached. بالنسبة لـ .env أخبر الفريق مسبقاً، أو احتفظ بقالب .env.example في المستودع.

git rm: حذف الملفات

git rm old.py              # حذف من القرص ومن الفهرس
git rm -r legacy/          # حذف مجلد
git rm -n '*.tmp'          # تجربة جافة: عرض ما سيُحذف
git rm -f changed.py       # حذف ملف فيه تعديلات غير مُثبَّتة

إذا حذفت الملف بـ rm العادي سيراه Git «محذوفاً» (deleted)، ويجب أن تضيف الحذف عبر git add أو git rm. أما git rm فينفذ الخطوتين معاً. ودون -f يرفض حذف ملف فيه تعديلات غير مُثبَّتة — وهذه حماية من فقدان العمل.

git mv: إعادة التسمية والنقل

git mv utils.py helpers.py
git mv helpers.py src/helpers.py

git mv اختصار لـ mv + git rm للمسار القديم + git add للجديد. لا يحفظ Git حقيقة إعادة التسمية: بل يحسبها من تشابه المحتوى عند عرض git status وgit log --follow وgit diff. لذلك تعطي إعادة التسمية والـ mv العادي متبوعاً بـ git add -A النتيجة نفسها.

نصيحة عملية: أعد تسمية الملف وغيّر محتواه في commits منفصلة. فإذا تغير الملف كثيراً مع إعادة التسمية قد لا يتعرف Git عليه كالملف نفسه، فينقطع التاريخ عند استخدام --follow.

لتغيير حالة الأحرف فقط في الاسم على Windows وmacOS (حيث نظام الملفات لا يفرق بين الحروف الكبيرة والصغيرة) استخدم git mv readme.md README.md — فالإعادة البسيطة من المستكشف قد لا يلاحظها Git.

ترتيب القواعد والأولوية

داخل الملف الواحد تُقرأ القواعد من الأعلى إلى الأسفل، والقاعدة الأخيرة المطابقة هي التي تفوز. لذلك يجب أن يأتي الاستثناء !keep.log تحت القاعدة *.log، وإلا فسيُلغى. وبين الملفات الأولوية كالتالي: .gitignore في مجلد فرعي أقوى من الملف في الجذر، أما التجاهل العام و.git/info/exclude فلهما أدنى أولوية.

مثال .gitignore لمشروع ويب

فيما يلي نموذج عملي لمشروع Node.js مع خلفية Python. لاحظ التعليقات: بعد ستة أشهر لن يتذكر أحد سبب كل قاعدة.

# --- التبعيات ---
node_modules/
.venv/

# --- البناء والذاكرة المؤقتة ---
/dist
/build
__pycache__/
*.pyc
.pytest_cache/
coverage/

# --- السجلات ---
*.log
npm-debug.log*

# --- البيئة والأسرار ---
.env
.env.*
!.env.example

# --- ملفات المستخدمين، مع الإبقاء على المجلد ---
uploads/*
!uploads/.gitkeep

هنا استُخدم كلا أسلوبي الاستثناء: .env.* يخفي كل نسخ البيئة المحلية، لكن القالب .env.example يبقى في المستودع، ويوجد مجلد uploads في النسخة المستنسخة بفضل .gitkeep.

ما الذي لا ينبغي تجاهله

المبالغة في التجاهل ضارة أيضاً. ملفات قفل التبعيات — package-lock.json وpoetry.lock وcomposer.lock — تُرفع عادةً في التطبيقات، لأنها تضمن أن يثبّت الجميع والـ CI الإصدارات نفسها من الحزم. وإعدادات التنسيق المشتركة (.editorconfig وإعدادات أدوات الفحص) يجب أن تعيش في المستودع.

حالة مثيرة للجدل هي إعدادات الـ IDE. يُتجاهل مجلد .vscode/ غالباً بالكامل، لكن أحياناً تُرفع الإضافات المقترحة ومهام البناء: .vscode/*، ثم !.vscode/extensions.json. القرار للفريق، والمهم ألا تحفظ في المستودع المشترك مسارات شخصية أو مفاتيح.

سيناريو: رفعت node_modules بالخطأ

خطأ كلاسيكي للمبتدئ: git add . قبل إنشاء .gitignore، فتدخل عشرات الآلاف من الملفات إلى الـ commit. الإصلاح في ثلاث خطوات:

echo "node_modules/" >> .gitignore
git rm -r --cached node_modules
git commit -m "chore: إزالة node_modules من المستودع"

إذا لم يُرسل الـ commit إلى الخادم بعد، فمن الأفضل إعادة كتابته حتى لا تبقى الملفات الثقيلة في التاريخ: git reset --soft HEAD~1، ثم الأوامر نفسها والـ commit الجديد. وبعد الـ push تبقى الملفات في التاريخ، ولن ينخفض حجم النسخة إلا بإعادة كتابة التاريخ.

ولتفادي تكرار ذلك أنشئ .gitignore قبل أول git add، واعتد على النظر إلى git status قبل كل commit: قائمة طويلة مريبة من الملفات الجديدة سبب كافٍ للتوقف.

الخلاصة

ملف .gitignore هو أول ملف يستحق أن تودعه في أي مشروع جديد: التبعيات والبناءات والسجلات والأسرار لا مكان لها في المستودع. التجاهل يعمل فقط على الملفات غير المتعقَّبة، لذلك تُزال الملفات المضافة سابقاً بـ git rm --cached، وتُفحص القواعد بـ git check-ignore -v. ولحذف الملفات وإعادة تسميتها استخدم git rm وgit mv حتى تدخل التغييرات الفهرس فوراً. والعمل مع الفهرس والمستودع الأول مشروح عملياً في دورة Git.

الأسئلة الشائعة

هل يجب إيداع ملف .gitignore نفسه؟

نعم، حتى تسري القواعد على الفريق كله. أما الاستثناءات الشخصية فضعها في .git/info/exclude أو في التجاهل العام.

هل يمكن أن يكون لدي عدة ملفات .gitignore؟

نعم، يمكن وضع .gitignore في أي مجلد فرعي، وتسري قواعده نسبةً إلى ذلك المجلد، مكملةً للقواعد في الجذر.

كيف أضيف ملفاً متجاهلاً إلى commit؟

استخدم git add -f مسار/الملف؛ بعدها يُتعقَّب الملف ولا يؤثر فيه .gitignore.

كيف أرى كل الملفات المتجاهلة في المشروع؟

نفّذ git status --ignored أو git ls-files --others --ignored --exclude-standard.

كيف أتوقف مؤقتاً عن تتبع التغييرات في ملف متعقَّب؟

هناك الأمر git update-index --skip-worktree ملف، لكنه إعداد محلي وليس بديلاً عن .gitignore.

تعلّم هذا الموضوع بالفيديو

يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Git من الصفر إلى مطور واثق».

الانتقال إلى الدورة