Git push error '[удаленный отклонен] master -> master (ветка в настоящее время извлечена)' - PullRequest
926 голосов
/ 12 мая 2010

Вчера я опубликовал вопрос о том, как клонировать репозиторий Git с одной из моих машин на другую, Как я могу 'git clone' с другой машины? .

Теперь я могу успешно клонировать Git-репозиторий из моего источника (192.168.1.2) в пункт назначения (192.168.1.1).

Но когда я произвел редактирование файла, a git commit -a -m "test" и a git push, я получаю эту ошибку в пункте назначения (192.168.1.1):

git push                                                
hap@192.168.1.2's password: 
Counting objects: 21, done.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 1010 bytes, done.
Total 11 (delta 9), 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 git+ssh://hap@192.168.1.2/media/LINUXDATA/working
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'git+ssh://hap@192.168.1.2/media/LINUXDATA/working'

Я использую две разные версии Git (1.7 на пульте и 1.5 на локальной машине). Это возможная причина?

Ответы [ 30 ]

1108 голосов
/ 15 июля 2010

Вы можете просто преобразовать свой удаленный репозиторий в пустой репозиторий (в пустом репозитории нет рабочей копии - папка содержит только фактические данные репозитория).

Выполните следующую команду в папке удаленного хранилища:

git config --bool core.bare true

Затем удалите все файлы, кроме .git в этой папке. И тогда вы сможете без ошибок выполнять git push в удаленном хранилище.

680 голосов
/ 29 мая 2010

У меня была та же ошибка, когда я начал изучать Git . Некоторые другие ответы явно не для кого-то нового в Git!

(Я собираюсь использовать нетехнические термины, чтобы донести идею.) В любом случае, у вас есть два хранилища: одно - оригинал, который вы впервые сделали, а другое - работа, которую вы только что сделали. 1005 *

Прямо сейчас вы находитесь в своем рабочем хранилище и используете ветку "master". Но вы также «залогинены» в исходном репозитории в ту же «главную» ветку. Теперь, когда вы «вошли» в оригинал, Git боится, что вы можете испортить, потому что вы можете работать с оригиналом и все испортить. Поэтому вам нужно вернуться в исходный репозиторий и выполнить «git checkout someotherbranch», и теперь вы можете выполнить без проблем.

Надеюсь, это поможет.

123 голосов
/ 12 мая 2010

Сообщение об ошибке описывает, что произошло. Более современные версии Git отказываются обновлять ветку с помощью push, если эта ветка извлечена.

Самый простой способ работы между двумя непрошенными репозиториями - это либо

  1. всегда обновлять репозитории путем извлечения (или извлечения и слияния) или, если необходимо,

  2. , нажав на отдельную ветку (ветку импорта), а затем объединяя эту ветку с главной веткой на удаленном компьютере.

Причина этого ограничения в том, что операция push работает только в удаленном Git-репозитории, у нее нет доступа к индексу и рабочему дереву. Таким образом, если разрешено, нажатие на извлеченную ветку изменит HEAD на несовместимость с индексом и рабочим деревом в удаленном хранилище.

Это упростит случайную фиксацию изменения, которое отменяет все отправленные изменения , а также очень затруднит различие между локальными изменениями, которые не были зафиксированы, и различиями между новыми HEAD, индекс и рабочее дерево, вызванные push-перемещением HEAD.

113 голосов
/ 14 февраля 2013

Резюме

Вы не можете нажать на одну извлеченную ветвь репозитория, потому что он будет связываться с пользователем этого репозитория таким образом, который, скорее всего, закончится потерей данных и истории 1004 *. Но вы можете нажать на любую другую ветку того же хранилища.

Поскольку в пустых хранилищах никогда не проверяется какая-либо ветвь, вы всегда можете перейти в любую ветвь пустого хранилища.

Существует несколько решений в зависимости от ваших потребностей.

Решение 1: использовать хранилище чуть-чуть

Как и предполагалось, если на одном компьютере вам не нужен рабочий каталог, вы можете перейти в пустой репозиторий. Чтобы не связываться с хранилищем, вы можете просто его клонировать:

machine1$ cd ..
machine1$ mv repo repo.old
machine1$ git clone --bare repo.old repo

Теперь вы можете отправить все, что вы хотите, на тот же адрес, что и раньше.

Решение 2. Перейдите в не проверенную ветвь

Но если вам нужно проверить код на вашем пульте <remote>, тогда вы можете использовать специальную ветку для нажатия. Допустим, в вашем локальном репозитории вы назвали свой удаленный origin, и вы находитесь на главном филиале Тогда вы могли бы сделать

machine2$ git push origin master:master+machine2

Тогда вам нужно объединить его, когда вы находитесь в origin удаленном репо:

machine1$ git merge master+machine2

Вскрытие проблемы

Когда ветвь извлечена, фиксация добавит новый коммит с заголовком текущей ветки в качестве его родителя и переместит голову ветки в этот новый коммит.

So

A ← B
    ↑
[HEAD,branch1]

становится

A ← B ← C
        ↑
    [HEAD,branch1]

Но если бы кто-то мог нажать на эту ветку между ними, пользователь оказался бы в том, что git называет режим отсоединенной головы :

A ← B ← X
    ↑   ↑
[HEAD] [branch1]

Теперь пользователь больше не находится в branch1, без явного запроса проверить другую ветку. Хуже того, пользователь теперь вне любой ветви , и любой новый коммит будет просто висящим :

      [HEAD]
        ↓
        C
      ↙
A ← B ← X
        ↑
       [branch1]

Гипотетически, если в этот момент пользователь проверяет другую ветвь, то этот висячий коммит становится честной игрой для сборщика мусора Git .

61 голосов
/ 16 декабря 2010

Вы можете обойти это «ограничение», отредактировав .git/config на конечном сервере. Добавьте следующее, чтобы разрешить отправку репозитория git, даже если он «извлечен»:

[receive]
denyCurrentBranch = warn

или

[receive]
denyCurrentBranch = false

Первое разрешит толчок, предупреждая о возможности испортить ветку, а второе просто тихо разрешит.

Это можно использовать для «развертывания» кода на сервере, который не предназначен для редактирования. Это не лучший подход, но быстрый для развертывания кода.

40 голосов
/ 15 февраля 2012

Мне нравится идея о том, что на удаленном компьютере все еще можно использовать репозиторий, но вместо фиктивной ветви мне нравится использовать:

git checkout --detach

Кажется, это очень новая функция Git - я использую git версии 1.7.7.4.

39 голосов

git config --local receive.denyCurrentBranch updateInstead

https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155

Используйте это в репозитории сервера, а также обновляет рабочее дерево, если не будет перезаписанного без отслеживания.

Он был добавлен в Git 2.3 как , упомянутый VonC в комментариях.

Я скомпилировал Git 2.3 и попробовал. Пример использования:

git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead

cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master

cd ../server
ls

Выход:

a
b

Ууу, b получил толчок!

28 голосов
/ 27 января 2011

У меня была такая же проблема. Для меня я использую Git push для перемещения кода на мои серверы. Я никогда не меняю код на стороне сервера, так что это безопасно.

В хранилище вы нажимаете, чтобы набрать:

git config receive.denyCurrentBranch ignore

Это позволит вам изменить хранилище, пока оно является рабочей копией.

После запуска Git push перейдите на удаленный компьютер и введите:

git checkout -f

При этом внесенные вами изменения будут отражены в рабочей копии удаленного компьютера.

Обратите внимание, что это не всегда безопасно, если вы вносите изменения в рабочую копию, на которую нажимаете.

24 голосов
/ 07 февраля 2011

Вы можете воссоздать свой репозиторий сервера и передать его с локального главного филиала на главный сервер.

На вашем удаленном сервере:

mkdir myrepo.git
cd myrepo.git
git init --bare

ОК, из вашего местного отделения:

git push origin master:master
20 голосов
/ 13 мая 2016

Что вы, вероятно, сделали, чтобы вызвать это:

Такого рода вещи случаются, когда вы запускаете небольшую программу. Вы собираетесь изменить что-то, что уже работало, поэтому вы разыгрываете заклинание 3-го уровня вечной отмены:

machine1:~/proj1> git init

и вы начинаете добавлять / фиксировать. Но затем , проект начинает становиться более активным, и вы хотите работать на нем с другого компьютера (например, с домашнего компьютера или ноутбука), поэтому вы делаете что-то вроде

machine2:~> git clone ssh://machine1/~/proj1

и он клонируется, и все выглядит хорошо, и вы работаете над своим кодом с machine2.

Затем ... вы пытаетесь выдвинуть ваши коммиты с machine2, и вы получите предупреждающее сообщение в заголовке.

Причина этого сообщения в том, что git-репо, из которого вы извлекли, было как бы предназначено для использования только для этой папки на машине1. Вы можете клонировать из него просто отлично, но нажатие может вызвать проблемы. «Правильный» способ управления кодом в двух разных местах - это «голое» репо, как было предложено. Голый репозиторий не предназначен для выполнения какой-либо работы в , он предназначен для координации коммитов из нескольких источников. Вот почему самый лучший ответ предлагает удалить все файлы / папки, кроме папки .git, после того, как вы git config --bool core.bare true.

Уточнение ответа с самым высоким рейтингом: Во многих комментариях к этому ответу говорится что-то вроде: «Я не удалял файлы, не относящиеся к .git, с машины1, и я все еще мог зафиксировать с машины2 ». Вот так. Однако, эти другие файлы полностью «отделены» от git-репо. Попробуйте там git status, и вы увидите что-то вроде «роковой: эта операция должна выполняться в рабочем дереве». Таким образом, предложение удалить файлы не так, чтобы коммит с machine2 работал , работал ; это чтобы вы не запутались и не подумали, что git все еще отслеживает эти файлы. Но удаление файлов является проблемой, если вы все еще хотите работать с файлами на компьютере1, не так ли?

Итак, что вы действительно должны делать?

Зависит от того, сколько вы планируете по-прежнему работать на machine1 и machine2 ...

Если вы закончили разработку с machine1 и перенесли всю свою разработку на machine2 ... , просто сделайте то, что предлагает самый высокий ответ: git config --bool core.bare true, а затем, при необходимости, удалите все файлы. / папки, отличные от .git, из этой папки, поскольку они не отслежены и могут вызвать путаницу.

Если ваша работа на machine2 была единовременной, и вам не нужно продолжать там разработку ... , тогда не пытайтесь делать голое репо; просто ftp / rsync / scp / и т.д. ваши файлы с машины * 2 * поверх файлов на машине * 1 *, подтвердите / нажмите с машины * 1 *, а затем удалите файлы с машины * 2 *. Другие предлагали создать ветку, но я думаю, что это немного запутанно, если вы просто хотите объединить какую-то разработку, которую вы делали разово, с другой машины.

Если вам нужно продолжить разработку как на machine1, так и на machine2 ... , то вам нужно правильно все настроить. Вам нужно конвертировать репо в голое, , затем , вам нужно сделать клон этого на machine1, чтобы вы работали in. Вероятно, самый быстрый способ сделать это - сделать

machine1:~/proj1> git config --bool core.bare true
machine1:~/proj1> mv .git/ ../proj1.git
machine1:~/proj1> cd ..
machine1:~> rm -rf proj1
machine1:~> git clone proj1.git
machine1:~> cd proj1

Очень важно: , поскольку вы переместили расположение репозитория с proj1 на proj1.git, , вам необходимо обновить его в файле .git / config на machine2 . После этого вы можете зафиксировать свои изменения с machine2. Наконец, я стараюсь хранить свои голые репозитории в центральном месте, вдали от моих рабочих деревьев (то есть не помещайте «proj1.git» в ту же родительскую папку, что и «proj1»). Я советую вам сделать то же самое, но я хотел, чтобы описанные выше шаги были максимально простыми.

...