إذا أبلغ Git عن أن ملفاً أصبح قابلاً للتنفيذ—أو توقف عن كونه قابلاً للتنفيذ—على جهاز Mac الخاص بك، فحدد أولاً الطبقة التي تغيرت: ملف العمل، أو فهرس الإعداد (staging index)، أو الالتزام (commit). قارن بين هذه الحالات قبل تغيير الأذونات أو إعدادات Git. يسجل Git الملفات العادية بالوضع 100644 (غير قابل للتنفيذ) أو 100755 (قابل للتنفيذ)؛ وعادةً ما يشير التغيير المنفرد بينهما إلى بت التنفيذ، وليس إلى تغير محتويات الملف. وثائق Git diff
1. تحقق مما إذا كان التغيير مجهزاً (Staged)
في Terminal، انتقل إلى المستودع وافحص حالته وكلتا مقارنتي الفروق (diffs):
git status --short
git diff --summary
git diff --cached --summary
يقارن git diff بين شجرة العمل والفهرس؛ بينما يقارن git diff --cached بين الفهرس و HEAD. يميز Git status هذه الطبقات نفسها، لذا يظهر التغيير المجهز (staged) منفصلاً عن التغيير غير المجهز (unstaged). وثائق Git status
ابحث عن مخرجات مثل mode change 100644 => 100755 path/to/file. إذا ظهرت فقط في git diff --summary، فإن ملف العمل يختلف عن الفهرس. وإذا ظهرت في git diff --cached --summary، فهذا يعني أن تغيير الوضع قد تم تجهيزه (staged) ويمكن تثبيته (committed). إذا كانت كلاهما فارغتين ولكن أحد زملائك في الفريق أبلغ عن تغيير مثبت، فافحص السجل بعد ذلك.
2. قارن الفهرس مع ملف Mac
بالنسبة لمسار متتبع، افحص الوضع المسجل في الفهرس وأذونات الملف الحالية:
git ls-files --stage -- "scripts/build.sh"
ls -l "scripts/build.sh"
استبدل scripts/build.sh بالمسار الدقيق المتعلق بالمستودع؛ ضعه بين علامات اقتباس حتى يتم التعامل مع المسافات ورموز shell حرفياً. في مخرجات git ls-files --stage، يكون الحقل الأول هو الوضع المخزن في الفهرس: 100644 يعني أن Git لا يسجل الملف كقابل للتنفيذ، بينما 100755 يعني أنه يسجله كذلك. تُظهر مخرجات ls -l بتات الأذونات المحلية؛ يشير وجود x في ثلاثية الأذونات إلى إذن التنفيذ لتلك الفئة من المستخدمين. توضح وثائق Git ls-files ودليل أذونات Apple هذين العرضين.
تضيق هذه المقارنة نطاق السبب. إذا كان الفهرس يشير إلى 100644، ولكن ls -l يُظهر إذن التنفيذ، فإن التعارض يكمن في ملف العمل (أو أن Git مُهيأ لتجاهل فروق أوضاع الملفات). وإذا كان الفهرس يشير إلى 100755، فإن Git قد قام بالفعل بتجهيز (stage) أو استخراج وضع قابل للتنفيذ، بغض النظر عما كنت تقصده أن يكون الملف عليه.
3. ابحث عن الالتزام الذي أدخل هذا الوضع
إذا كان التغيير موجوداً بالفعل في السجل، فافحص ملخصات التزامات الملف المعني:
git log --summary -- "scripts/build.sh"
تطبع صيغة رقعة Git (patch format) ترويسات منفصلة لـ old mode و new mode عند تغير وضع الملف. راجع الالتزام الذي تم فيه تبديل تلك القيم، ثم قارن التزامه الأصلي وسياق العمل المحيط به: هل تم جعل الملف قابلاً للتنفيذ عمداً، أم قام محرر أو برنامج نصي بتغيير الأذونات، أم تم استخدام المستودع على نظام ملفات أو نظام تشغيل آخر؟ يحدد الالتزام وقت تسجيل Git للتغيير؛ ولكنه لا يثبت التطبيق أو الشخص الذي تسبب فيه. وثائق صيغة Git diff
قد يشير تغيير الوضع عبر عدة ملفات غير مرتبطة إلى عملية واسعة لتعيين الأذونات أو انتقال بين أنظمة ملفات/بيئات تشغيل. تذكر وثائق Git أن بعض أنظمة الملفات تفشل في الحفاظ على بتات التنفيذ، وأن المستودع المنقول بين بيئات مختلفة قد يواجه سلوكاً مختلفاً في وضع الملفات. تعامل مع هذا كدليل للتحقيق، وليس دليلاً قاطعاً على سبب محدد. وثائق تكوين Git
4. تحقق من إعداد وضع الملفات في Git
تحقق من الإعداد ومصدره:
git config --show-origin --get core.filemode
يتحكم core.filemode فيما إذا كان Git يراعي فروق بت التنفيذ في شجرة العمل. يجعله Git افتراضياً true ما لم يُحدد خلاف ذلك، وقد يستطلع سلوك نظام الملفات عند تهيئة المستودع أو استنساخه. إذا طبع الأمر false، فقد يتجاهل Git التغييرات المحلية في بت التنفيذ؛ وهذا الإعداد لا يفسر وضعاً مسجلاً بالفعل في التزام (commit). وإذا لم يطبع شيئاً، فقد يكون الإعداد غير محدد، وفي هذه الحالة يُطبق الإعداد الافتراضي الموثق لـ Git. وثائق تكوين Git
تجنب تعيين هذا الخيار إلى false لمجرد إخفاء اختلاف مفاجئ واحد (diff). تحقق أولاً مما إذا كان المستودع موجوداً على نظام ملفات أو بيئة مشتركة لا تحافظ بشكل موثوق على بتات التنفيذ، وما إذا كان المتعاونون يعتمدون على تتبع الوضع. يؤدي تغيير الإعداد إلى تغيير معالجة Git لفروق الأوضاع؛ ولا يصلح وضعاً تم تسجيله بشكل خاطئ في الفهرس أو الالتزام.
5. قم بالإصلاح فقط بعد تحديد الوضع المقصود
إذا لم يكن من المفترض أن يكون الملف قابلاً للتنفيذ وكان التغيير غير مجهز (unstaged)، فاستعد الإذن المحلي باستخدام chmod:
chmod a-x "scripts/build.sh"
git diff --summary
إذا كان الوضع المقصود هو أن يكون قابلاً للتنفيذ، فاستخدم chmod a+x "scripts/build.sh" بدلاً من ذلك. على نظام macOS، يغير chmod أذونات العنصر المحدد؛ اختر الوضع المقصود بناءً على دور الملف والاتفاق المتبع في المستودع، وليس لمجرد إخفاء الـ diff. دليل أذونات Apple
إذا تم تجهيز (stage) وضع غير صحيح، فاضبط الإذن المحلي المقصود، ثم قم بتجهيز هذا المسار مرة أخرى وراجع الملخص المجهز:
chmod a-x "scripts/build.sh"
git add -- "scripts/build.sh"
git diff --cached --summary
استخدم a+x بدلاً من a-x عندما ينبغي أن يكون الملف قابلاً للتنفيذ. إذا كان الوضع خاطئاً في التزام حالي، فإن إجراء التزام تصحيحي جديد يكون عموماً أوضح من إعادة كتابة السجل المشترك؛ نسق مع الفريق قبل إعادة كتابة الالتزامات التي قد يستخدمها الآخرون بالفعل. في كل حالة، افحص git diff و git diff --cached بعد ذلك حتى لا تغفل عن أي تعديلات في المحتوى تزامنت مع تغيير الإذن.
المصادر
Git - وثائق git-diff — Git
Git - وثائق git-status — Git
Git - وثائق git-ls-files — Git
Git - وثائق git-config — Git
أذونات وملكيات BSD — Apple Developer