Почему мой удаленный 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
Другие вопросы по тегам