Исправление ошибки Git push: удаленный сервер отклонил ветку master
Исправление ошибки Git push 'remote rejected master -> master (branch is currently checked out)' с практическими решениями для небазовых репозиториев. Узнайте несколько подходов, включая преобразование в базовый репозиторий и параметры конфигурации.
Как исправить ошибку Git push “remote rejected master -> master (branch is currently checked out)” при отправке изменений в небезветвенный репозиторий?
Я столкнулся с ошибкой Git push при попытке отправить изменения с локальной машины на удаленный репозиторий. Сообщение об ошибке гласит:
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
Моя настройка:
- Исходная машина: 192.168.1.2 (версия Git 1.7)
- Целевая машина: 192.168.1.1 (версия Git 1.5)
- Я могу успешно клонировать репозиторий с исходной машины на целевую
- После внесения изменений и коммита, отправка (push) завершается ошибкой, указанной выше
Какие возможные решения существуют для устранения этой проблемы? Нужно ли настраивать удаленный репозиторий иначе, или следует использовать другой подход?
Ошибка Git push “remote rejected master -> master (branch is currently checked out)” возникает потому, что Git предотвращает прямые push-и в текущую ветку в небезрепозиториях, чтобы защитить рабочую директорию от повреждений. Это поведение по умолчанию гарантирует, что индекс и рабочее дерево остаются согласованными с состоянием репозитория. Вы можете решить эту проблему, преобразовав удаленный репозиторий в bare-репозиторий, настроив его для принятия push-ей или используя альтернативные рабочие процессы, которые избегают этого конфликта.
Содержание
- Понимание ошибки
- Решение 1: Преобразование в bare-репозиторий
- Решение 2: Настройка receive.denyCurrentBranch
- Решение 3: Push в другие ветки
- Решение 4: Использование post-receive хуков
- Решение 5: Принудительный push с осторожностью
- Лучшие практики и рекомендации
Понимание ошибки
Сообщение об ошибке, с которым вы столкнулись, является фундаментальным механизмом защиты Git:
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
Это происходит потому, что Git защищает небезрепозитории от прямых push-ей в текущую ветку. Эта защита предотвращает повреждение рабочей директории, гарантируя, что индекс и рабочее дерево остаются согласованными с состоянием репозитория.
Почему существует эта защита: В небезрепозиториях файлы извлекаются в рабочую директорию. Если бы вы могли напрямую отправлять изменения в текущую ветку, рабочая директория стала бы несогласованной с новыми коммитами, что потенциально могло бы привести к потере данных или повреждению.
Ошибка возникает именно потому, что:
- Ваш удаленный репозиторий является небезрепозиторием (имеет рабочую директорию)
- Ветка master в данный момент извлечена в удаленном репозитории
- Git предотвращает прямые обновления для избежания несогласованности состояния
Решение 1: Преобразование в bare-репозиторий
Самым распространенным и рекомендуемым решением является преобразование вашего удаленного репозитория в bare-репозиторий. Bare-репозитории не имеют рабочих директорий, поэтому они могут безопасно принимать push-и в любую ветку.
Шаги для преобразования:
- Остановите все процессы, использующие репозиторий на целевой машине
- Создайте резервную копию вашего текущего репозитория
- Инициализируйте новый bare-репозиторий:bash
cd /path/to/your/repo git init --bare --shared - Обновите URL локального удаленного репозитория:bash
git remote set-url origin /path/to/new/bare/repo.git
Примечание: Согласно Stack Overflow, bare-репозитории никогда не имеют извлеченных веток, поэтому вы всегда можете отправлять push в любую ветку bare-репозитория.
Преимущества:
- Четкое разделение хранения репозитория и рабочей директории
- Стандартная практика для удаленных репозиториев
- Нет риска повреждения рабочей директории
Недостатки:
- Нельзя напрямую редактировать файлы в репозитории
- Требуется дополнительная настройка для рабочих директорий
Решение 2: Настройка receive.denyCurrentBranch
Вы можете настроить удаленный репозиторий для принятия push-ей, изменив параметр receive.denyCurrentBranch.
Доступные варианты:
-
updateInstead(Рекомендуется для небезрепозиториев):bashcd /path/to/remote/repo git config receive.denyCurrentBranch updateInstead -
ignore(Менее безопасно):bashgit config receive.denyCurrentBranch ignore
-
warn(Разрешает push, но показывает предупреждение):bashgit config receive.denyCurrentBranch warn
Важно: Как упоминается в GitHub gist, установка
receive.denyCurrentBranchвignoreилиwarnпозволяет отправлять push в текущую ветку удаленного репозитория, но может потребоватьсяgit reset --hardдля согласования рабочей директории с HEAD.
Поведение updateInstead:
- Автоматически обновляет рабочую директорию при получении push-ей
- Поддерживает согласованность между репозиторием и рабочей директорией
- Доступно с версии Git 2.3.0 (февраль 2015)
Примечание: Некоторые старые версии Git могут не поддерживать
updateInstead. Как отмечено на форуме Atlassian, если вы столкнулись с ошибкой “fatal: bad config value for ‘receive.denycurrentbranch’”, вам может потребоваться использоватьrefuseилиignoreвместо этого.
Решение 3: Push в другие ветки
Вы можете обойти эту проблему, отправляя push в другую ветку, а затем слиянием на удаленной стороне.
Шаги:
-
Отправьте push во временную ветку:
bashgit push origin master:temp-branch
-
На удаленной машине переключитесь на целевую ветку и выполните слияние:
bashgit checkout master git merge temp-branch git branch -d temp-branch # Опционально: удалить временную ветку
Альтернативный подход: Как предложено на Stack Overflow, вы можете использовать
git push origin master:fooи выполнить слияние в удаленном репозитории.
Преимущества:
- Не требуются изменения в конфигурации
- Безопасно - избегает повреждения рабочей директории
- Работает с любой версией Git
Недостатки:
- Требуются дополнительные шаги
- Ручной процесс, который может быть подвержен ошибкам
Решение 4: Использование post-receive хуков
Для более сложных рабочих процессов вы можете использовать Git хуки для автоматизации процесса обновления.
Шаги настройки:
-
Создайте post-receive хук:
bashcd /path/to/remote/repo/.git/hooks cat > post-receive << 'EOF' #!/bin/sh unset GIT_INDEX_FILE unset GIT_WORK_TREE git checkout -f EOF -
Сделайте хук исполняемым:
bashchmod +x post-receive -
Настройте репозиторий (при необходимости):
bashgit config core.bare false git config receive.denyCurrentBranch ignore
Примечание: Как упоминается в ответе на Super User, вы можете настроить хуки для автоматической обработки процесса извлечения.
Пример расширенного хука:
#!/bin/sh
# Этот хук будет автоматически обновлять рабочую директорию
# при получении push
# Сброс рабочей директории в соответствии с новым HEAD
git reset --hard
Решение 5: Принудительный push с осторожностью
В некоторых случаях вам может потребоваться использовать принудительный push, но это следует делать с крайней осторожностью.
Команда принудительного push:
git push -f origin master
Предупреждение: Как отмечено на Stack Overflow, принудительный push требует, чтобы
denyCurrentBranchбыл проигнорирован. Это может привести к потере данных, если не обращаться с этим должным образом.
Когда использовать принудительный push:
- Только при крайней необходимости
- После обеспечения отсутствия незафиксированных изменений на удаленном репозитории
- Когда вы понимаете связанные риски
Лучшие практики и рекомендации
Рекомендуемое решение в зависимости от вашей настройки:
Учитывая вашу настройку с разными версиями Git (1.7 и 1.5), я рекомендую:
- В долгосрочной перспективе: Преобразовать в bare-репозиторий (Решение 1)
- Для немедленных нужд: Использовать
receive.denyCurrentBranch updateInstead(Решение 2)
Соображения совместимости версий:
- Git 1.5: Может не поддерживать
updateInstead- используйтеignoreвместо этого - Git 1.7: Поддерживает
updateInstead- это предпочтительный вариант - Современный Git (2.3+): Полная поддержка
updateInstead
Рекомендации для производственной среды:
Согласно Linux Hint, разработчикам следует учитывать следующие лучшие практики:
- Используйте bare-репозитории для удаленного хранения
- Храните рабочие директории отдельно от хранилища репозитория
- Используйте правильные рабочие процессы Git, которые избегают прямых push-ей в извлеченные ветки
Альтернативный рабочий процесс:
Для вашей конкретной настройки рассмотрите этот рабочий процесс:
-
На целевой машине (192.168.1.1):
bashgit init --bare ~/project.git
-
На исходной машине (192.168.1.2):
bashgit remote set-url origin user@192.168.1.1:~/project.git
-
Создайте рабочую директорию на целевой машине:
bashgit clone ~/project.git ~/project-working cd ~/project-working
Эта настройка обеспечивает лучшее из двух миров: bare-репозиторий для безопасных push-ей и отдельную рабочую директорию для разработки.
Заключение
Ошибка Git push “remote rejected master -> master (branch is currently checked out)” является механизмом защиты, который предотвращает повреждение рабочей директории. Для решения этой проблемы у вас есть несколько жизнеспособных вариантов:
- Преобразовать в bare-репозиторий - Самый надежный вариант для удаленных репозиториев
- Настроить receive.denyCurrentBranch - Быстрое исправление для небезрепозиториев
- Отправлять push в другие ветки - Безопасный обходной путь без изменений в конфигурации
- Использовать post-receive хуки - Расширенная автоматизация для сложных рабочих процессов
- Принудительный push с осторожностью - Вариант последней инстанции со значительными рисками
Для вашей конкретной настройки с разными версиями Git я рекомендую преобразовать удаленную машину (192.168.1.1) в bare-репозиторий, сохраняя при этом рабочую директорию отдельно. Этот подход обеспечивает наиболее надежное и поддерживаемое решение, которое работает с разными версиями Git и предотвращает будущие проблемы с согласованностью рабочей директории.
Источники
- [Git push error ‘remote rejected] master -> master (branch is currently checked out)’ - Stack Overflow](https://stackoverflow.com/questions/2816369/git-push-error-remote-rejected-master-master-branch-is-currently-checked)
- Git Push error: refusing to update checked out branch - Stack Overflow
- [How to Fix Git Push Error ‘remote rejected] main’? – Linux Hint](https://linuxhint.com/fix-git-push-error-remote-rejected-master/)
- git-denyCurrentBranch-updateInstead.md · GitHub
- Push-to-deploy: A nice git workflow for updating server code
- A Better Way to Git Push to Deploy (updateInstead & push-to-checkout)
- repository - How to setup git repo in order to push as currently the remote reject it? - Super User
- Problems with denycurrentbranch setting when pushing commits to origin - Atlassian Community
- git - Why doesn’t github throw an error ! [remote rejected] master -> master (branch is currently checked out) and a remote server does? - Stack Overflow
- making a remote repo update when changes are pushed to it