Есть несколько возможных причин такого отказа. Согласно комментарию , это оказался устаревший master.lock
файл на сервере. Достаточно удалить его вручную.
Поскольку может быть более одной причины отказа, не очень полезно давать только один конкретный c ответ. Однако мы можем обрисовать здесь общий процесс, и что может go ошибаться.
Помните, что имена веток и тегов являются c формами ссылок refs или . Каждый просто содержит 1 га sh ID. Имена тегов обычно содержат идентификатор ha sh либо тега объекта , который создает аннотированный тег, либо объекта фиксации, и после создания никогда не изменяются. Однако имена ветвей идентифицируют одну фиксацию в цепочке коммитов, и эта одна фиксация считается последней фиксацией, которая является частью этой ветки. (Могут быть последующие коммиты, но они не содержатся в этой ветке. Обратите внимание, что фиксация, идентифицированная именем ветки , может, тем не менее, содержаться в других ветвях.) это то, что эти значения регулярно меняются по мере роста ветвей. Так что пары должны быть обновлены.
Эти пары имя-значение, вероятно, должны храниться в какой-то транзакционной базе данных, но это не так. Git в настоящее время (как и все выпуски до сегодняшней версии 2.26.2 и, вероятно, в течение длительного времени) хранит все эти ссылки в одном или обоих из двух мест: либо в одном плоском файле с именем packed-refs
, либо в отдельном файлы, хранящиеся в файловой системе, например, refs/heads/master
. Чтобы найти имя, Git сначала проверяет, существует ли отдельный файл. Если это так, файл будет иметь правильное значение. Если нет, Git проверяет, существует ли имя в файле packed-refs
, и если да, то использует это значение. Если оба поиска завершились неудачно, имя не существует.
Чтобы убедиться, что любое обновление является атомарным, чтобы никакая другая команда Git не могла обновить имя, пока одна команда Git его обновление - Git использует тщательную последовательность создания .lock
файлов. Например, для обновления refs/heads/master
, Git сначала создает refs/heads/master.lock
. 1 ОС хоста должна (и предоставляет) предоставить для этого операцию «создать файл, но не выполнить, если он уже существует».
Здесь все может go неправильно. Предположим, например, что каталог (или папка, если вы предпочитаете этот термин) refs/heads/
отказывает в разрешении на создание нового файла идентификатору пользователя, который обрабатывает процесс git push
. В этом случае создание master.lock
завершится ошибкой типа «доступ запрещен».
В вашем конкретном случае файл master.lock
уже существует. Обычно такие файлы создаются, записываются, а затем удаляются или переименовываются. Однако в случае сбоя питания, отказа системы sh или другого внезапного завершения программы Git система не остается в хорошем состоянии. В частности, продолжает существовать файл .lock
.
При сбоях питания или сбоях системы можно ввести go и удалить оставшиеся файлы .lock
во время запуска системы. На практике это не так часто встречается на большинстве серверов, чтобы возиться с ним - люди могут просто go исправить свой Git сервер вручную, как это сделали вы. Git программы, как правило, также не должны внезапно уничтожаться ОС, но в некоторых системах используются «убийцы нехватки памяти» (OOM-killers), которые иногда могут вызывать такого рода проблемы.
1 Создав соответствующий файл .lock
, Git будет go записать новое значение в файл блокировки, а затем использовать операцию переименования atomi c, чтобы изменить master.lock
файл в файл с именем master
, удалив все предыдущие файлы. Это освобождает блокировку и сохраняет новое значение таким образом, чтобы любая другая команда Git, которой требуется значение, увидит новое.
Git использует тот же метод для создания index.lock
при обновлении своего индексного файла, но поскольку записи индекса никогда не передаются из одного Git в другой, любые сбои здесь всегда чисто локальные, а не во время git push
. Этот метод имеет еще одну особенность, заключающуюся в том, что «транзакцию» можно «откатить», просто удалив файл блокировки, вместо того, чтобы переименовывать файл блокировки в основное имя.
Помните термин ACID при работе с базами данных: атомарность, согласованность, изоляция, долговечность. Метод файла .lock
обеспечивает атомарность и, если ОС предоставляет правильные гарантии, согласованность и долговечность. Однако свойство изоляции полностью отсутствует: мы не можем обновить одно поле базы данных самостоятельно. Это , почему Git использует отдельные файлы для каждой ссылки (за исключением случаев, когда это не так, через файл packed-refs
, который, следовательно, фактически доступен только для чтения: только один Git программа, git pack-refs
, когда-либо обновляет ее, используя собственную более сложную блокировку).
Отсутствие изоляции может быть болезненным при работе с очень большим индексом. По этой причине Git может использовать режим «разделенного индекса», в котором некоторые записи (те, которые не были изменены в последнее время) находятся во втором файле, а только «активно изменяющиеся» записи находятся в основном .git/index
файл.
(Использование реальной базы данных решило бы все эти проблемы вместе с множеством других, но настоящие базы данных сложны.)