Git без перемотки вперед отклонен

88

Мне кажется, что этот вопрос задавали много раз, но обычно решение такое: «Я удалил каталог и заново выполнил свою работу с новой проверкой». Я сделал коммит и нажал, но понял, что в сообщении коммита указал неправильный номер билета. Поэтому я посмотрел на SO в поисках быстрого решения и в итоге набрал в терминал следующее:

$ git reset --soft HEAD^
$ git commit -m "... correct message ..."

Единственная проблема в том, что я получаю следующее сообщение об ошибке:

To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

Я использую модель git-flow и работаю над веткой разработки. Как я могу снова объединить вещи, чтобы снова сделать git счастливым?

rynmrtn
источник

Ответы:

52

Сила git push:

git push origin +develop
Алан Хаггай Алави
источник
24
Это решение, но прочтите комментарий Брайана Кэмпбелла, чтобы понять, что вы делаете, прежде чем использовать это.
thelem
5
git push origin + master
Аникет Такур
См. Также примечание receive.denyNonFastForwardsв ответе Брайана Кэмпбелла : +или --forceможет быть недостаточно убедительным, в зависимости от того, как они - кем бы они ни были - настроили свой репозиторий Git.
torek
174

Если нажать коммят на сервер, а затем переписать , что совершить локально (с git reset, git rebase, git filter-branchили любую другую историю манипуляции), а затем толкнули , что переписанные фиксации обратно на сервер, вы завинчивать никого , кто тянул. Вот пример; скажем, вы зафиксировали A и отправили его на сервер.

- * - * - A <- master

- * - * - A <- origin / master

Теперь вы решаете переписать A, как вы упомянули, сбросив и повторно зафиксировав. Обратите внимание, что в результате остается болтающаяся фиксация A, которая в конечном итоге будет удалена сборщиком мусора, так как она недоступна.

- * - * - А
    \
     A '<- мастер

- * - * - A <- origin / master

Если кто-то другой, скажем, Фред, отключается masterот сервера, пока вы это делаете, у него будет ссылка на A, с которой он может начать работать:

- * - * - A '<- master

- * - * - A <- origin / master

- * - * - AB <- fred / master

Теперь, если бы вы могли подтолкнуть свой A 'к origin / master, что привело бы к созданию не-быстрой перемотки вперед, у него не было бы A в его истории. Так что, если бы Фред снова попытался потянуть, ему внезапно пришлось бы выполнить слияние, и он повторно представил бы фиксацию A:

- * - * - A '<- master

- * - * - A <- origin / master

- * - * - AB- \ 
    \ * <- фред / мастер
     А '- /

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

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

git push -f

или

git push origin +master

Они оба проигнорируют проверку на отсутствие быстрой перемотки вперед и обновят то, что находится на сервере, до вашей новой ревизии A ', отказавшись от ревизии A, так что в конечном итоге она будет собрана для мусора.

Возможно, принудительное нажатие полностью отключено с помощью receive.denyNonFastForwardsпараметра конфигурации. Эта опция включена по умолчанию для общих репозиториев. В этом случае, если вы действительно действительно хотите принудительно выполнить push, лучший вариант - удалить ветку и воссоздать ее с помощью git push origin :master; git push origin master:master. Однако denyNonFastForwardsопция включена по причине, описанной выше; в общем репозитории, это означает, что теперь каждый, кто его использует, должен убедиться, что они перебазируются на новую историю.

В общем репозитории, как правило, лучше просто размещать новые коммиты сверху, чтобы исправить любую вашу проблему; вы можете использовать git revertдля создания коммитов, которые отменят изменения предыдущих коммитов.

Брайан Кэмпбелл
источник
отличное образование, и в итоге вы правильно поняли команду, но моя ветка называлась develop (на основе git-flow), и другой парень ввел +developсвою команду - так что проверка переходит к нему. У вас все равно астрономическое количество очков: P
rynmrtn
8
Или используйте менее загадочныйgit push --force
Беннетт МакЭлви
3
@Panique Вы пытаетесь разрешить нескольким людям работать над большой сложной базой кода одновременно, не блокируя друг друга (позволяя работать над ней только одному человеку одновременно) и без изменений, перезаписывающих друг друга. Вам нужно, чтобы каждый человек мог вносить изменения независимо и объединять эти изменения. Слияние (ручное или автоматическое) может вызвать непредвиденные проблемы; поэтому вы хотите сохранить как можно больше информации, чтобы иметь возможность выяснить, что произошло, если что-то пошло не так. Это по сути сложно; это не грязно, просто сложная проблема.
Брайан Кэмпбелл
Я попробовал опцию -f и +, чтобы переписать историю удаленного репо. В обоих вариантах я столкнулся с проблемой, не связанной с перемоткой вперед. [17:05] $ git push -f origin local_A: remote_A Подсчет объектов: 35, готово. Дельта-сжатие с использованием до 2 потоков. Сжатие объектов: 100% (18/18), готово. Написание объектов: 100% (21/21), 7,41 Кбайт, готово. Всего 21 (дельта 9), повторно использовано 0 (дельта 0) удаленное: Чтобы предотвратить потерю истории, обновления без ускоренной перемотки вперед были отклонены. Объедините удаленные изменения (например, «git pull») перед повторным нажатием. См. Подробности в разделе «Примечание о быстрой перемотке вперед» в команде «git push --help».
Srikanth
4
@Srikanth Можно полностью отключить принудительные нажатия с помощью receive.denyNonFastForwardsпараметра конфигурации. Эта опция включена по умолчанию для общих репозиториев. В этом случае, если вы действительно действительно хотите принудительно выполнить push, лучший вариант - удалить ветку и воссоздать ее с помощью git push origin :remote_A; git push origin local_A:remote_A. Но прочтите то, что я написал выше о том, почему делать такой рабочий процесс в общем репозитории - плохая идея. Вы должны пытаться делать это только в том случае, если у вас есть что-то, что вызывает серьезные проблемы в коммите, от которого вы пытаетесь избавиться или переписать.
Брайан Кэмпбелл
14

Возможно, вам придется сделать git pull, который МОЖЕТ автоматически объединять файлы для вас. Затем вы можете совершить еще раз. Если у вас есть конфликты, вам будет предложено их разрешить.

Имейте в виду, что вы должны указать, из какой ветки вывести, если вы не обновили свой gitconfig, чтобы указать ...

Например:

git pull origin develop:develop
Тони
источник
Все еще без ума от быстрой перемотки вперед. Есть мысли, как заставить его слиться? ! [rejected] develop -> develop (non-fast-forward)
rynmrtn
Я думаю, что это переключатель -f, но я могу ошибаться. kernel.org/pub/software/scm/git/docs/git-pull.html
Тони,
Это частично работает. Однако я не вижу обновлений на github (он показывает предыдущий коммит как последний даже с a git push origin develop)
rynmrtn
7

Я использовал EGit, и я тоже столкнулся с этой проблемой. Просто попытался перейти rebaseв текущую ветку, и это сработало.

Нгуен Минь Бинь
источник