العودة إلى المدونة

Gitignore لا يعمل؟ هذا هو الإصلاح الحقيقي

17 سبتمبر 2026

الخلاصة: إذا لم يكن .gitignore يعمل، فالملف متتبع في الغالب أصلًا. يتجاهل Git ما لم يره قط — والملف في الفهرس محصّن ضد أي قاعدة تكتبها. اكشف الحقيقة بـ git check-ignore -v <path>: الصمت يعني أن المسار متتبع ولا قاعدة تنطبق. أصلحه بـ git rm --cached <path> ثم التزم، فتبدأ القاعدة العمل من ذلك الالتزام فصاعدًا. وترتيب القواعد وفخ النفي وأحجية VS Code الزائفة تفسر الحالات المتبقية.

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

آلية واحدة تغطي غالبية الحالات: الملف التُزم قبل وجود القاعدة. .gitignore ليس مرشحًا يخفي الملفات عن git — إنه قاعدة عمّا ينبغي لـ git add التقاطه من حالة غير متتبعة. وحين يدخل الملف الفهرس يتتبع git تغييراته للأبد حتى تزيل التتبع صراحة. تعديل .gitignore بعد الوقائع لا يغيّر شيئًا في الملفات المتتبعة — ولهذا تسلسل “التزم .env، هُلع، أضف .env إلى .gitignore، التزم مجددًا” ما يزال يشحن السر مع كل دفعة.

وهذا يلدغ الجميع لأن git شبه شامل — استطلاع Stack Overflow 2022 وضع استخدام Git فوق 93% من المطورين المحترفين (survey.stackoverflow.co) — وكل واحد منهم سيكتب قاعدة لملف التزم الأسبوع الماضي عاجلًا أم آجلًا.

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

كيف أعرف أي قاعدة gitignore تطابق ملفًا؟

git check-ignore هو أداة التشخيص، وصمته هو التشخيص:

# يطبع القاعدة المطابقة + الملف + رقم السطر حين تنطبق قاعدة
git check-ignore -v debug.log
# .gitignore:3:*.log    debug.log

# لا يطبع شيئًا حين لا تنطبق قاعدة — الملف متتبع (أو لا قاعدة موجودة)
git check-ignore -v src/.env
# (الصمت = .gitignore لا يتجاهل هذا المسار، مهما كتبت)

# رموز الخروج: 0 = متجاهل، 1 = غير متجاهل — قابل للسكربت
git check-ignore -q debug.log && echo "ignored" || echo "tracked or unruly"

قراءة ناتج -v: مصدر التجاهل (.gitignore أو .git/info/exclude أو ملف التجاهل العام لديك)، ثم رقم-السطر:نمط، ثم المسار. وإذا فاجأك قاعدة لاحقة فتذكر الأسبقية: آخر قاعدة مطابقة تفوز، فـ !important.log بعد *.log يعيد تضمين ذلك الملف الواحد.

لماذا لا يعمل gitignore مع ملفات التُزمت من قبل؟

أزل تتبع الملف، أبقه على القرص، والتزم الإزالة:

# أزل تتبع ملف واحد (النسخة المحلية تنجو — --cached يلمس الفهرس فقط)
git rm --cached .env
git commit -m "stop tracking .env"

# تحقق أن قاعدة التجاهل تنطبق الآن
git check-ignore -v .env

من هذا الالتزام فصاعدًا، .gitignore يملك المسار: تعديلاته لم تعد تظهر في git status، ولن يلتقطه git add . مجددًا. لكن الملف يبقى في التاريخ — وإن كان سرًّا فإزالته من آخر التزام لا تكفي. تدوير بيانات الاعتماد هو الإصلاح الحقيقي الوحيد؛ وإعادة كتابة التاريخ هي التجميلية (والتراجع عن آخر commit يساعد فقط ما دام الالتزام السيئ هو القمة).

ولمستودع مليء بالقمم الملتزمة سابقًا — مخرجات بناء، فضلات محرر، node_modules تسللت مبكرًا — إزالة التتبع بالجملة سطران:

git rm -r --cached .
git add .
git commit -m "apply .gitignore to tracked files"

هذا يعيد بناء الفهرس وفق القواعد الحالية: تسقط المسارات المتجاهلة، ويعاد كل ما عداه دون تغيير. يبدو الـ diff دراماتيكيًا (آلاف الحذوف) لكنه لا يحذف شيئًا من القرص. وإذا كان هدفك حذف تلك الملفات لا مجرد إزالة تتبعها، فذاك ميدان git clean -fdx — انظر حذف الملفات غير المتتبعة بأمان.

يتجاهل Git ما لم يره قط. والملف الموجود أصلًا في الفهرس محصّن ضد .gitignore — لا قاعدة تكتبها تجعله ينساه.

لماذا لا يعمل gitignore مع مجلد؟

ثلاثة فخاخ خاصة بالمجلدات:

1. الشرطة الختامية تخص النية لا المطابقة. build وbuild/ كلاهما يطابق مجلدًا، لكن build/ يوثق أنك تقصد مجلدًا فقط — ملف اسمه build ينجو من قبضته. غير أن التناظر ينكسر عند إعادة التضمين (الفخ التالي).

2. النفي لا يُنقذ الملفات داخل مجلد مستبعد. وثائق git لا لبس فيها: “It is not possible to re-include a file if a parent directory of that file is excluded” (git-scm.com/docs/gitignore). هذا قرار أداء — يتخطى git المجلدات المستبعدة بالكامل بدل السير فيها. لذا هذا لا يعمل:

build/
!build/keep.me        # قاعدة ميتة — git لا ينظر داخل build/ قط

والإصلاح أن تستبعد المحتوى لا المجلد:

build/*
!build/keep.me        # يعمل — build/ نفسها ما تزال مفتوحة للتفقد

3. ملفات .gitignore المتداخلة تفوز في نطاقها. القواعد في subdir/.gitignore تتجاوز الملف الجذري للمسارات تحت subdir. وعندما يسمّي git check-ignore -v مصدر تجاهل لم تتوقعه، فهذا هو السبب عادة.

لماذا لا يعمل gitignore في VS Code؟

تكاد لا تكون أبدًا لسبب VS Code. عرض التحكم بالمصادر في المحرر يقرأ الفهرس نفسه الذي يقرأه git، فالعرَض متطابق: الملف التُزم أصلًا، وإعادة تشغيل البيئة لا تغيّر الفهرس. حقيقتان مجاورتان لـ VS Code تستحقان المعرفة:

  • الباهت في Explorer = متجاهل؛ البرتقالي/الأصفر = متتبع مع تغييرات. ملف يظهر معدلًا بعد أن تجاهلته هو تأكيدك أنه متتبع — شغّل إصلاح git rm --cached أعلاه.
  • غياب .gitignore من قائمة التغييرات في Explorer يعني أن القاعدة تعمل — لم يظهر غير متتبع من البداية أصلًا. كثيرون يبلغون أن “VS Code يتجاهل gitignore الخاص بي” بينما git status على سطر الأوامر يخالف عرض SCM عتيقًا؛ أعد تحميل النافذة (Cmd/Ctrl+Shift+P ثم “Reload Window”) قبل أن تلوم git.

.gitignore مقابل .git/info/exclude مقابل العام: أيها متى؟

الملفالنطاقيُلتزم؟استخدامه
.gitignore (المستودع)كل من يستنسخنعممخرجات بناء، اعتماديات، .env — قواعد مشتركة
.git/info/excludeاستنساخك فقطلاالفوضى الشخصية: .scratch/، فضلات المحرر
core.excludesFile (عام)كل مستودعاتكلافضلات النظام: .DS_Store، Thumbs.db، *.swp
.gitignore + نفيالمستودعنعمإعادة تضمين استثناءات لتكوين متتبع

الملف العام هو ما لا يضبطه معظم المطورين وينبغي:

git config --global core.excludesFile ~/.gitignore_global
printf '.DS_Store\nThumbs.db\n*.swp\n' >> ~/.gitignore_global

وقاعدة منزلية تستحق النسخ: إذا نفعَت القاعدة الفريق كله فمكانها المستودع؛ وإن نفعَتك أنت وحدها فمكانها exclude أو الملف العام. التزام قواعد التجاهل الشخصية هو الطريقة التي تصل بها ملفات .gitignore إلى 300 سطر دون أن يعرف أحد أي نصف ما زال يهم.

كيف أتجاهل تغييرات ملف متتبع؟

أحيانًا تريد ملفًا متتبعًا (قالب تكوين، ملف إعدادات بيئة) لكنك تريد توقف ظهور تعديلاتك المحلية في git status. علمان على git update-index، ولا ينتمي أي منهما إلى سير عمل فريق:

git update-index --skip-worktree config/local.dev   # تعديلاتك المحلية تدخل في الصمت
git update-index --no-skip-worktree config/local.dev  # ...وترجع

--skip-worktree هو المدافَع عنه — يقول “نسختي المحلية منحرفة عن قصد.” وقريبه --assume-unchanged وعدُ أداء (“هذا الملف لن يتغير”) لا آلية تجاهل، وقد يكسره git بصمت. وكلاهما يفشل فشلًا مدويًا وقت السحب إذا غيّره upstream أيضًا — الجوابان الدائمان إما تكوين محلي فقط عبر exclude منذ الإنشاء، أو ملف قالب (config.example) يتتبعه git وتنسخه أنت.

فحص صحة gitignore في 30 ثانية

git check-ignore -v <path>        # أي قاعدة؟ (الصمت = متتبع، لا قاعدة)
git ls-files --error-unmatch <path>  # هل هو متتبع أصلًا؟
git rm --cached <path>            # أزل التتبع، أبقِ الملف
git commit -m "stop tracking <path>"
git check-ignore -v <path>        # القاعدة تظهر الآن

شخّص، أزل التتبع، تحقق. النمط خلف كل بلاغ “gitignore not working” هو الملف نفسه يرتدي قبّعتين — متتبع في جانب من الفهرس ومتجاهل في الجانب الآخر — وعلم --cached وحده يخلع القبعة الثانية.

FAQ

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

في معظم الحالات يكون الملف متتبعًا أصلًا. يتجاهل Git الملفات التي لم يرها فقط؛ والملف الموجود في الفهرس محصّن ضد .gitignore حتى تزيل تتبعه بـ git rm --cached وتلتزم.

كيف أعرف أي قاعدة gitignore تطابق ملفًا؟

شغّل git check-ignore -v <path>. يطبع سطر .gitignore ورقم القاعدة بدقة، أو يصمت حين يكون الملف متتبعًا ولا قاعدة تنطبق.

هل يحذف git rm --cached ملفي المحلي؟

لا. --cached يزيل الملف من الفهرس فقط؛ والنسخة على القرص تبقى. التزم الإزالة فيصبح الملف غير متتبع، وعندها يسري .gitignore.

لماذا لا يستطيع gitignore إعادة تضمين ملف داخل مجلد متجاهل؟

لأداء أدق، يتخطى Git المجلدات المستبعدة بالكامل. وفق وثائق git، يستحيل إعادة تضمين ملف إذا كان أحد مجلداته الأب مستبعدًا.

— mrsaynothing

— mrsaynothing

ملاحظات ميدانية في الذكاء الاصطناعي وLinux والاستضافة الذاتية.

ناقش هذا المقال على dev.to dev.to ↗

احصل على الشرح التطبيقي التالي بالبريد

رسالة واحدة لكل مقال. أصلح المشكلة وامضِ.

self-hosted · بلا أطراف ثالثة · إلغاء الاشتراك بنقرة واحدة

ما هذا؟

Ollama لا يستخدم الـ GPU؟ الإصلاح على لينكس وويندوز وWSL

أعجبتك هذه الكتابات؟ بناء مثل هذا هو عملي. وظّفني