Почему мой удаленный Git-репозиторий имеет незафиксированные изменения после отправки на него?
Я создал новый Git-репозиторий, используя следующие команды:
mkdir plans-for-world-domination
cd plans-for-world-domination
git init
echo "MWA HA HA HA HA!" > plans.txt
git add .
git commit -m "Beginning my plans..."
Затем я сделал клон этого репозитория, внес некоторые изменения, зафиксировал их, а затем попытался нажать:
cd ..
git clone plans-for-world-domination clone
cd clone
echo "Step 1: set up super secret spy base in Cleveland, Ohio" >> plans.txt
git commit -am "Update plans"
git push origin master
Когда я cd
обратно в plans-for-world-domination
хотя в репозитории есть изменения, внесенные в промежуточную область / индекс, которые противоположны изменениям, которые я только что выдвинул:
$ cd ../plans-for-world-domination
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: plans.txt
$ git diff --staged
diff --git a/plans.txt b/plans.txt
index febb495..ce01362 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,2 +1 @@
MWA HA HA HA HA!
-Step 1: set up super secret spy base in Cleveland, Ohio
Почему в моем первом репо есть эти неустановленные изменения, которые противоположны тому, что я только что нажал, и как я могу это исправить?
1 ответ
Толчки не обновляют рабочую копию и промежуточную область в не пустых репозиториях
Промежуточная область в первом репозитории, по-видимому, содержит обратную сторону изменений, которые были только что переданы, потому что это не пустой репозиторий, что означает, что он содержит рабочую копию, которая также часто упоминается как рабочее дерево (каталог) в Git документация. Голые репозитории, с другой стороны, не имеют каталога рабочей копии.
Поскольку репозиторий не является пустым, при нажатии на него push-уведомление обновляет только ссылки на ветви, а символические HEAD
ссылка, потому что git push
не работает с рабочей копией и областью подготовки, которые присутствуют в непрошенных репозиториях.
Как следствие этого, рабочая копия и промежуточная область не обнаженного хранилища по-прежнему остаются в том же состоянии хранилища, которое присутствовало до обновления, которое обновило HEAD
, Другими словами, фактическое состояние рабочей копии и промежуточной области не соответствует состоянию коммита, на который указывает HEAD
, Вот почему эти различия между двумя государствами проявляются, когда git status
а также git diff
запускаются:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: plans.txt
$ git diff --staged
diff --git a/plans.txt b/plans.txt
index febb495..ce01362 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,2 +1 @@
MWA HA HA HA HA!
-Step 1: set up super secret spy base in Cleveland, Ohio
(Неоптимальное) решение: полный сброс
Поскольку рабочая копия и промежуточная область не синхронизированы с HEAD
, решение, чтобы заставить их соответствовать снова просто использовать
git reset --hard HEAD
git reset --hard
сбросить рабочую область и промежуточную область в коммит, на который указывает HEAD
,
Однако это не идеальное решение...
Идеальное решение: вместо этого использовать открытые репозитории
Вы не должны толкать репозитории, не являющиеся открытыми, из-за этой проблемы с их рабочими копиями и промежуточными областями, которые не синхронизируются со ссылками на репозитории. Вместо этого, если у вас нет необычной причины для отправки в не-пустое хранилище, вам действительно следует вместо этого перейти в пустое хранилище, у которого нет рабочей копии.
Чтобы создать пустой репозиторий, просто используйте --bare
флаг:
# Initialize a bare repo
mkdir bare
cd bare
git init --bare
# Push changes to the bare repo
cd ..
mkdir project
cd project
# Make some changes and commit
git remote add origin ../bare
git push origin master
# Or create a bare clone from another bare or non-bare repo
git clone --bare <repo-path-or-uri>
Загрузка в не-пустые репозитории по умолчанию запрещена с Git 1.6.2
Обратите внимание, что начиная с Git версии 1.6.2, отправка в не пустые репозитории по умолчанию запрещена:
Со следующим основным выпуском,
git push
в ветку, которая в данный момент извлечена, по умолчанию будет отказано. Вы можете выбрать, что должно произойти при таком нажатии, установив переменную конфигурацииreceive.denyCurrentBranch
в принимающем хранилище.
На самом деле, когда вы пытаетесь перейти к непроигрышному репо с текущими версиями Git, вам нужно отказать в следующем сообщении об ошибке (слегка измененном для краткости):
$ git push origin master
Total 0 (delta 0), reused 0 (delta 0)
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.
error:
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.
error:
error: To squelch this message and still keep the default behaviour, set
error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To non-bare
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'non-bare'
Как объясняется в сообщении об ошибке, описанном выше, вы можете отключить проверки безопасности, которые не позволяют вам отправиться в репозиторий без обнажения, отключив receive.denyCurrentBranch
Настройка конфигурации в удаленном репозитории non-bare:
git config receive.denyCurrentBranch warn # Warn when pushing to non-bare repo
git config receive.denyCurrentBranch ignore # Don't even bother warning