Если Git сообщает, что файл на вашем Mac стал исполняемым (или перестал им быть), сначала выясните, на каком уровне произошли изменения: в рабочем файле, в индексе (staging) или в коммите. Сравните эти состояния перед изменением прав доступа или конфигурации Git. Git сохраняет обычные файлы с режимом доступа 100644 (неисполняемый) или 100755 (исполняемый); изолированное переключение между ними обычно указывает на бит исполняемости, а не на изменение содержимого файла. Документация по git-diff
1. Проверьте, проиндексировано ли изменение
В Терминале перейдите в репозиторий и проверьте его статус, а также оба diff-отчёта:
git status --short
git diff --summary
git diff --cached --summary
Команда git diff сравнивает рабочее дерево с индексом; git diff --cached сравнивает индекс с HEAD. Git status разделяет эти же уровни, поэтому проиндексированное изменение отображается отдельно от непроиндексированного. Документация по git-status
Ищите вывод вида mode change 100644 => 100755 path/to/file. Если он появляется только в git diff --summary, рабочий файл отличается от индекса. Если он присутствует в git diff --cached --summary, смена режима уже проиндексирована и может быть закоммичена. Если оба вывода пусты, но коллега сообщает о закоммиченном изменении, переходите к проверке истории.
2. Сравните индекс с файлом на Mac
Для отслеживаемого пути проверьте режим, сохранённый в индексе, и текущие права доступа к файлу:
git ls-files --stage -- "scripts/build.sh"
ls -l "scripts/build.sh"
Замените scripts/build.sh точным путём относительно корня репозитория; заключите его в кавычки, чтобы пробелы и спецсимволы оболочки обрабатывались буквально. В выводе git ls-files --stage первое поле представляет собой режим, сохранённый в индексе: 100644 означает, что Git не считает файл исполняемым, а 100755 — что считает. Вывод ls -l показывает локальные биты разрешений; символ x в триплете прав указывает на право выполнения для соответствующего класса пользователей. Обе эти концепции разъясняются в документации по git-ls-files и руководстве Apple по правам доступа.
Такое сравнение позволяет сузить круг причин. Если в индексе указано 100644, а ls -l показывает права на выполнение, расхождение кроется в рабочем файле (или Git настроен игнорировать различия в режимах файлов). Если индекс показывает 100755, Git уже проиндексировал или извлёк исполняемый режим независимо от того, каким вы планировали сделать этот файл.
3. Найдите коммит, в котором появился этот режим
Если изменение уже зафиксировано в истории, изучите сводки коммитов по соответствующему файлу:
git log --summary -- "scripts/build.sh"
При изменении режима файла формат патча Git выводит отдельные заголовки 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 может игнорировать локальные изменения бита исполняемости; эта настройка не объясняет режим, уже зафиксированный в коммите. Если команда ничего не выводит, параметр может быть не задан — в таком случае применяется значение Git по умолчанию. Документация по конфигурации Git
Не следует устанавливать эту опцию в false только для того, чтобы скрыть неожиданный diff. Сначала убедитесь, находится ли репозиторий на файловой системе или общем сетевом ресурсе, где биты исполняемости сохраняются ненадежно, и зависит ли отслеживание режимов от других участников команды. Изменение параметра влияет на то, как Git обрабатывает различия режимов; оно не исправляет ошибочно сохранённый режим в индексе или коммите.
5. Вносите исправления только после определения нужного режима
Если файл не должен быть исполняемым и изменение не проиндексировано, восстановите локальные права с помощью chmod:
chmod a-x "scripts/build.sh"
git diff --summary
Если же целевой режим должен быть исполняемым, используйте вместо этого chmod a+x "scripts/build.sh". В macOS команда chmod изменяет разрешения для указанного элемента; выбирайте необходимый режим исходя из назначения файла и соглашений в репозитории, а не просто ради очистки diff. Руководство Apple по правам доступа
Если некорректный режим уже проиндексирован, установите нужные локальные права, повторно проиндексируйте этот путь и проверьте сводку индекса:
chmod a-x "scripts/build.sh"
git add -- "scripts/build.sh"
git diff --cached --summary
Используйте a+x вместо a-x, если файл должен быть исполняемым. Если неверный режим уже попал в существующий коммит, создание нового корректирующего коммита обычно предпочтительнее переписывания общей истории; согласуйте действия с командой, прежде чем переписывать коммиты, которые уже могут использоваться другими. В любом случае после завершения выполните git diff и git diff --cached, чтобы не упустить случайные изменения содержимого наряду со сменой прав.
Источники
BSD Permissions and Ownership — Apple Developer