Устранение проблем с конфигурацией Git: распространенные исправления и лучшие практики
Исправляйте проблемы с конфигурацией Git, отслеживая источники настроек, решая проблемы с идентификацией, псевдонимами, хуками, окончаниями строк, командами pull и учетными данными.
Устранение проблем с конфигурацией Git: распространенные исправления и лучшие практики
Большинство проблем с конфигурацией Git кажутся более странными, чем они есть на самом деле. Git обычно делает именно то, что ему предписал один из его конфигурационных файлов. Сложность заключается в поиске нужного файла, поскольку настройка может находиться в репозитории, вашем пользовательском конфиге, системном конфиге, включенном файле или условном включении, которое применяется только в определенной директории.
Первая команда, к которой я обращаюсь, это:
git config --list --show-origin --show-scope
Если ваша версия Git не поддерживает --show-scope, используйте:
git config --list --show-origin
Источник (origin) показывает, какой файл предоставил каждое значение. Это важнее, чем само значение. Увидеть [email protected] недостаточно; нужно знать, пришло ли оно из .git/config, ~/.gitconfig, /etc/gitconfig или включенного рабочего профиля.
Конфигурация Git имеет приоритетный порядок. Локальная конфигурация репозитория обычно переопределяет глобальную пользовательскую конфигурацию, а глобальная конфигурация переопределяет системную. Параметры командной строки и переменные окружения могут переопределить все это для одной команды. Условные включения добавляют еще один уровень: глобальный файл может сказать: «Когда я нахожусь в этой директории, загрузи также эту другую конфигурацию».
Вы можете проверить одну настройку с ее источником:
git config --show-origin --get user.email
git config --show-origin --get core.autocrlf
git config --show-origin --get-regexp '^alias\.'
Эта привычка предотвращает много бесполезного редактирования. Если в репозитории локально установлен user.email, изменение git config --global user.email не повлияет на коммиты в этом репозитории.
Неправильное имя или email в коммитах
Симптом прост: коммиты показывают неправильного автора. Это часто происходит, когда вы используете один ноутбук для работы и личных проектов, или когда вы клонируете корпоративный репозиторий до того, как установили свой рабочий email.
Проверьте, что Git будет использовать в текущем репозитории:
git config user.name
git config user.email
git config --show-origin --get user.email
Установите свою идентификацию по умолчанию глобально:
git config --global user.name "Ваше Имя"
git config --global user.email "[email protected]"
Для одного репозитория установите локально:
git config --local user.name "Ваше Имя"
git config --local user.email "[email protected]"
Если вы хотите, чтобы Git отказывался от коммитов, когда идентификация не настроена явно, используйте:
git config --global user.useConfigOnly true
Эта настройка полезна для людей, которые переключаются между идентификациями. Она может раздражать новичков, потому что Git перестанет угадывать имя пользователя и имя хоста системы. Используйте ее, когда лучше провалить коммит, чем создать его с неправильным адресом.
Для более чистого разделения работы/личного используйте условные включения:
# ~/.gitconfig
[user]
name = Ваше Имя
email = [email protected]
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
Затем поместите это в ~/.gitconfig-work:
[user]
email = [email protected]
Косая черта в конце gitdir:~/work/ важна, потому что она означает репозитории в этой директории. Если это не срабатывает, выполните git config --list --show-origin из рабочего репозитория и проверьте, появляется ли включенный файл.
Если вы уже сделали коммиты с неправильным email, изменение конфигурации исправит только будущие коммиты. Для неопубликованных коммитов вы можете использовать amend или rebase. Для коммитов, уже отправленных в общую ветку, спросите разрешения перед переписыванием истории.
Псевдонимы, которые не работают
Псевдонимы Git хранятся в разделе alias.*. Выведите их список следующим образом:
git config --get-regexp '^alias\.'
Обычный псевдоним расширяется до подкоманды Git:
git config --global alias.st 'status -sb'
git st
Если псевдониму нужен конвейер оболочки, подстановка переменных, cd или другая не-Git команда, он должен начинаться с !:
git config --global alias.recent '!git for-each-ref --sort=-committerdate --count=10 --format="%(refname:short)" refs/heads/'
Без ! Git пытается обработать первое слово как команду Git. ls -la становится «выполнить команду Git с именем ls», что не то, что вы имели в виду.
Кавычки — еще одна распространенная причина неудач. Если вы определяете псевдонимы из оболочки, используйте одинарные кавычки вокруг всего псевдонима, когда это возможно, а затем двойные кавычки внутри него по мере необходимости. Разные оболочки обрабатывают кавычки по-разному, особенно PowerShell и cmd.exe. Если сложный псевдоним продолжает ломаться, отредактируйте файл конфигурации напрямую:
git config --global --edit
Практический трюк для отладки — начать с команды вне Git. Как только она заработает, вставьте ее в псевдоним. Если это псевдоним оболочки, добавьте префикс ! и протестируйте снова.
Также следите за псевдонимами, которые затеняют ментальные модели. Псевдоним с именем pull или merge может сделать поведение Git неожиданным. Git не позволяет псевдонимам напрямую переопределять встроенные команды, но псевдонимы оболочки и скрипты-обертки могут. Если git pull ведет себя странно, проверьте также конфигурацию вашей оболочки:
type git
alias | grep git
Хуки, которые никогда не запускаются
Хуки не работают по трем скучным причинам: Git ищет в другой директории хуков, файл не является исполняемым или скрипт предполагает окружение, которого у него нет.
Проверьте настроенный путь к хукам:
git config --show-origin --get core.hooksPath
Если это выводит .githooks, Git будет использовать .githooks/pre-commit, а не .git/hooks/pre-commit. Если ничего не выводит, Git использует .git/hooks.
На macOS и Linux проверьте права доступа:
ls -l .git/hooks/pre-commit .githooks/pre-commit 2>/dev/null
chmod +x .githooks/pre-commit
Хук, который завершается с ненулевым статусом, блокирует операцию Git. Добавьте временную трассировку в начале:
#!/usr/bin/env bash
set -x
pwd
env | sort
Не оставляйте шумную трассировку в общем хуке. Она быстро становится нечитаемой.
Проблемы с путями распространены в GUI-клиентах. Хук, который работает в вашем терминале, может не работать в IDE, потому что IDE не загрузила ваш профиль оболочки. Предпочитайте команды, локальные для проекта, где это возможно:
./node_modules/.bin/eslint .
или проверьте наличие команды и выведите полезное сообщение:
if ! command -v npm >/dev/null 2>&1; then
echo "npm is required for this hook but was not found in PATH."
exit 1
fi
Окончания строк продолжают меняться
Проблемы с окончаниями строк проявляются в виде файлов, которые выглядят измененными сразу после checkout, больших diff'ов, где изменилась каждая строка, или скриптов, которые не работают на Linux после редактирования на Windows.
Проверьте вашу настройку:
git config --show-origin --get core.autocrlf
git config --show-origin --get core.eol
Распространенные варианты:
# Дружественно к Windows: CRLF при checkout, LF в репозитории
git config --global core.autocrlf true
# Дружественно к macOS/Linux: конвертировать CRLF в LF только при коммите
git config --global core.autocrlf input
# Без автоматической конвертации
git config --global core.autocrlf false
Для команды .gitattributes более надежен, чем просить каждого разработчика правильно настроить глобальные параметры. Поместите правила проекта в репозиторий:
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary
*.pdf binary
После добавления или изменения .gitattributes нормализуйте файлы намеренно:
git add --renormalize .
git status
Внимательно просмотрите этот diff. Он может затронуть много файлов, и вы не хотите смешивать нормализацию окончаний строк с функциональной работой.
Pull, Push или Merge использует неправильное поведение по умолчанию
Иногда проблема конфигурации не в идентификации или окончаниях строк. Это Git выбирает стратегию pull, которую вы не ожидали.
Проверьте настройки, связанные с pull:
git config --show-origin --get pull.rebase
git config --show-origin --get pull.ff
git config --show-origin --get branch.main.rebase
Если git pull постоянно делает rebase, когда вы ожидали merge, может быть включен pull.rebase или настройка для конкретной ветки. Если он отказывается от non-fast-forward pull'ов, может быть установлен pull.ff=only. Эти настройки сами по себе не неправильны; они просто должны соответствовать рабочему процессу команды.
Установите явное значение по умолчанию вместо того, чтобы жить с предупреждениями и сюрпризами:
# Merge при pull
git config --global pull.rebase false
# Rebase при pull
git config --global pull.rebase true
# Только fast-forward pull'ы
git config --global pull.ff only
Для одной ветки:
git config branch.main.rebase true
Путаница с помощником по учетным данным
Проблемы аутентификации часто выглядят как проблемы с удаленным репозиторием, но исходят из локальной конфигурации. Git может использовать помощник по учетным данным, в котором кэширован старый токен.
Проверьте помощников:
git config --show-origin --get-all credential.helper
Вы можете увидеть osxkeychain, manager, manager-core, store или cache. Может быть несколько помощников. Если Git продолжает отправлять неправильные учетные данные, удалите их из связки ключей ОС или менеджера учетных данных, а не меняйте случайные удаленные URL'ы.
Также проверьте удаленный репозиторий:
git remote -v
SSH и HTTPS используют разные пути аутентификации. Если один репозиторий использует [email protected]:org/repo.git, а другой — https://github.com/org/repo.git, они не обязательно будут использовать одни и те же учетные данные.
Надежная процедура отладки
Когда конфигурация Git кажется противоречивой, используйте процедуру вместо угадывания:
- Выполните ошибочную команду из корня репозитория.
- Проверьте точную настройку с помощью
git config --show-origin --get <имя>. - Выведите список связанных настроек с помощью
git config --list --show-origin --show-scope. - Проверьте локальную конфигурацию в
.git/configперед изменением глобальной. - Проверьте условные включения, если проблема возникает только в одной директории.
- Внесите наименьшее изменение в конфигурацию и повторно выполните исходную команду.
Конфигурация Git мощна, потому что она может быть многослойной. Это также причина, по которой она становится запутанной. Решение — сделать слои видимыми, а затем изменить тот слой, который на самом деле побеждает.
Когда конфигурация отличается внутри IDE
Запутанный класс проблем Git проявляется только внутри редактора или GUI. Терминал использует одну идентификацию, но IDE делает коммиты с другой. Хук проходит в вашей оболочке, но не работает из панели коммитов. Запрос учетных данных появляется в терминале, в то время как GUI молча повторяет попытки со старым токеном.
Причина обычно в окружении. Ваша интерактивная оболочка может загружать .bashrc, .zshrc, менеджеры SDK, менеджеры версий языков и пользовательские записи PATH. GUI, запущенный с рабочего стола, может не загружать ничего из этого. Git сам читает те же конфигурационные файлы, но хуки и помощники по учетным данным могут видеть другой мир.
Чтобы отладить это, создайте временный хук, который выводит окружение в локальный файл:
#!/usr/bin/env bash
{
date
pwd
git --version
git config --list --show-origin
env | sort
} > /tmp/git-hook-debug.log
exit 1
Выполните действие Git из IDE, затем проверьте /tmp/git-hook-debug.log. Удалите хук после этого. Это покажет вам, что на самом деле видели Git и хук, а не то, что видит ваш терминал.
Для проблем с идентификацией в GUI-клиентах проверьте, есть ли у инструмента свои собственные настройки Git. Некоторые клиенты используют системный Git; другие встраивают Git или хранят пользовательскую идентификацию в настройках приложения. Если клиент делает коммиты через Git, git log --format=fuller -1 покажет результирующего автора и коммиттера. Это поможет отделить «конфигурация Git была неправильной» от «GUI использовал свою собственную настройку».
Если сомневаетесь, сделайте локальные настройки репозитория явными для важных проектов:
git config --local user.email "[email protected]"
git config --local core.hooksPath .githooks
Локальная конфигурация уменьшает количество сюрпризов, потому что она путешествует с метаданными репозитория на этой машине. Она все еще не попадает в коммиты, поэтому общие правила должны жить в отслеживаемых файлах, таких как .gitattributes, .editorconfig, скрипты хуков и документация проекта.
Сохраняйте заведомо рабочую базовую конфигурацию
Когда проблемы с конфигурацией возвращаются, сохраните небольшую заведомо рабочую базовую конфигурацию для своих машин. Она не должна быть навороченной. Закомментированного ~/.gitconfig с вашей идентификацией, редактором, поведением ветки по умолчанию, помощником по учетным данным и включениями достаточно. Затем, когда новый ноутбук ведет себя иначе, вы можете сравнить, вместо того чтобы заново открывать каждую настройку.
Полезные базовые проверки включают:
git config --global --list --show-origin
git config --global --get core.editor
git config --global --get init.defaultBranch
git config --global --get-all credential.helper
Будьте осторожны при копировании конфигурации из интернета или от коллеги. Псевдонимы могут предполагать наличие инструментов, которых у вас нет. Помощники по учетным данным зависят от платформы. Настройки окончаний строк могут быть правильными для их ОС и неправильными для вашей. Относитесь к конфигурации Git как к конфигурации оболочки: заимствуйте идеи, но понимайте каждую строку, прежде чем оставить ее.
Для мейнтейнеров проектов лучшее исправление — перенести общие ожидания из личной конфигурации. Поместите окончания строк в .gitattributes, форматирование — в конфиг форматера, игнорируемые файлы — в .gitignore, а необходимые проверки — в CI. Чем меньше проект зависит от невидимых глобальных настроек, тем меньше тикетов по конфигурации он создает.
Когда вы меняете настройку для исправления проблемы, запишите, была ли она локальной или глобальной. Многие будущие загадки Git начинаются с хорошего временного локального исправления, которое никто не помнит через шесть месяцев.