Git reset --hard и удаленный репозиторий
У меня был репозиторий, в котором были плохие коммиты (D, E и F для этого примера).
A-B-C-D-E-F мастер и источник/мастер
Я изменил локальный репозиторий с помощью git reset --hard
. Я взял ветку перед reset, так что теперь у меня есть репо, которое выглядит так:
A-B-C master
\ D-E-F old_master
A-B-C-D-E-F origin/master
Теперь мне нужны были некоторые части этих плохих коммитов, поэтому я вишневый выбрал нужные мне биты и сделал несколько новых коммитов, так что теперь у меня есть следующее локально:
A-B-C-G-H master
\ D-E-F old_master
Теперь я хочу подтолкнуть это положение к удаленному репо. Однако, когда я пытаюсь сделать git push
Git вежливо, я отбрасываю кисть:
$ git push origin +master:master --force
Total 0 (delta 0), reused 0 (delta 0)
error: denying non-fast forward refs/heads/master (you should pull first)
To [email protected]:myrepo.git
! [remote rejected] master -> master (non-fast forward)
error: failed to push some refs to '[email protected]:myrepo.git'
Как заставить удаленное репо принять текущее состояние локального репо?
Ответы
Ответ 1
Если принудительное нажатие не помогает ( "git push --force origin
" или "git push --force origin master
" должно быть достаточно), это может означать, что удаленный сервер отказывается от ускоренной перемотки вперед либо через receive.denyNonFastForwards config (см. git config manpage для описание) или с помощью обновления/предварительного приема.
С более старыми Git вы можете обойти это ограничение, удалив "git push origin :master
" (см. ":" перед именем ветки), а затем повторно создав "git push origin master
" данную ветку.
Если вы не можете изменить это, тогда единственным решением будет вместо переписывания истории создать фиксацию возврат изменений в DEF:
A-B-C-D-E-F-[(D-E-F)^-1] master
A-B-C-D-E-F origin/master
Ответ 2
Чтобы дополнить ответ Jakub, если у вас есть доступ к удаленному серверу git в ssh, вы можете войти в каталог git и установить:
[email protected]$ git config receive.denyNonFastforwards false
Затем вернитесь к местному репо, повторите попытку с помощью --force
:
[email protected]$ git push origin +master:master --force
И, наконец, верните настройку сервера в исходном защищенном состоянии:
[email protected]$ git config receive.denyNonFastforwards true
Ответ 3
Вместо того, чтобы фиксировать свою "ведущую" ветвь, проще ее заменить своим "желаемым мастером", переименовав ветки. См. fooobar.com/questions/1278/.... Таким образом, вы даже не оставите никаких следов нескольких журналов возврата.
Ответ 4
Весь бизнес сброса git выглядел намного усложняющим для меня.
Итак, я сделал что-то в этом роде, чтобы получить мою папку src в состоянии, которое у меня было несколько коммитов назад.
# reset the local state
git reset <somecommit> --hard
# copy the relevant part e.g. src (exclude is only needed if you specify .)
tar cvfz /tmp/current.tgz --exclude .git src
# get the current state of git
git pull
# remove what you don't like anymore
rm -rf src
# restore from the tar file
tar xvfz /tmp/current.tgz
# commit everything back to git
git commit -a
# now you can properly push
git push
Таким образом, состояние дел в src хранится в tar файле, а git вынужден принимать это состояние без чрезмерного использования. В основном каталог src заменяется состоянием, которое у него было несколько месяцев назад.