Git push отклонен после переадресации функции
Хорошо, я думал, что это был простой сценарий мерзавца, что я пропускаю?
У меня есть master
ветвь и ветвь feature
. Я делаю некоторую работу над master
, некоторые - над feature
, а затем еще немного над master
. Я получаю что-то вроде этого (лексикографический порядок подразумевает порядок коммитов):
A--B--C------F--G (master)
\
D--E (feature)
У меня нет проблем ни с git push origin master
чтобы поддерживать удаленный master
обновленным, ни с git push origin feature
(когда она feature
), чтобы поддерживать удаленное резервное копирование для работы моей feature
. До сих пор у нас все хорошо.
Но теперь я хочу, чтобы перебазировать feature
на вершине F--G
совершающий на мастере, так что я git checkout feature
и git rebase master
. Все еще хорош. Теперь у нас есть:
A--B--C------F--G (master)
\
D'--E' (feature)
Проблема: в момент, когда я хочу сделать резервную копию новой перебазированной feature
разветвленной с git push origin feature
, push отклоняется, так как дерево изменилось из-за перебазировки. Эту проблему можно решить только с git push --force origin feature
.
Я ненавижу использовать --force
не будучи уверенным, что мне это нужно. Так мне это нужно? Обязательно ли перебазировка подразумевает, что следующий push
должен быть --force
?
Эта ветвь функций не используется другими разработчиками, поэтому де-факто у меня нет проблем с принудительным нажатием, я не собираюсь терять какие-либо данные, вопрос более концептуальный.
Ответы
Ответ 1
Проблема заключается в том, что git push
предполагает, что удаленная ветка может быть быстро перенаправлена в вашу локальную ветвь, то есть вся разница между локальной и удаленной ветвями в локальной сети имеет некоторые новые коммиты в конце:
Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
\
T--Y <- some-branch
Когда вы выполняете git rebase
, коммиты D и E применяются к новой базе, и создаются новые коммиты. Это означает, что после rebase у вас есть что-то вроде этого:
A--B--C------F--G--D'--E' <- feature-branch
\
D--E <- origin/feature-branch
В этой ситуации удаленная ветка не может быть быстро перенаправлена на локальную. Хотя, теоретически, локальная ветвь может быть объединена в удаленный (очевидно, в этом случае она вам не нужна), но поскольку git push
выполняет только перемотку вперед, он выдает и ошибки.
А какая опция --force
- это просто игнорирование состояния удаленной ветки и установка ее на фиксацию, которую вы в нее вставляете. Итак, git push --force origin feature-branch
просто переопределяет origin/feature-branch
с помощью локального feature-branch
.
На мой взгляд, переполнение ветвей функций на master
и принудительное отталкивание их обратно в удаленный репозиторий в порядке, пока вы единственный, кто работает на этой ветке.
Ответ 2
Вместо использования -f или -force разработчики должны использовать
--force-with-lease
Почему? Потому что он проверяет удаленную ветку для изменений, что является абсолютно хорошей идеей. Представьте себе, что Джеймс и Лиза работают над одной и той же ветвью функций, и Лиза нажала на фиксацию. Джеймс теперь сворачивает свою местную ветку и отклоняется при попытке толчка. Конечно, Джеймс считает, что это связано с переустановкой и использованием --force и будет переписывать все изменения Лизы. Если бы Джеймс использовал -force-with-lease, он бы получил предупреждение о совершении кем-то другим. Я не понимаю, почему кто-то использовал бы -force вместо -force-with-lease при нажатии после rebase.
Ответ 3
Я бы использовал вместо "checkout -b", и это легче понять.
git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature
когда вы удаляете, вы не можете нажать в выходящую ветку, содержащую разные идентификаторы SHA.
В этом случае я удаляю только удаленную ветвь.
Ответ 4
Одно из решений заключается в том, чтобы сделать то, что msysGit сбрасывание слияния script делает - после перезагрузки слияние в старой главе feature
с помощью -s ours
. Вы получите граф фиксации:
A--B--C------F--G (master)
\ \
\ D'--E' (feature)
\ /
\ --
\ /
D--E (old-feature)
... и ваш push feature
будет быстрой перемоткой вперед.
Другими словами, вы можете сделать:
git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature
(Не проверено, но я думаю, что правильно...)
Ответ 5
Возможно, не может быть, что в этой ветке есть только один разработчик, который теперь (после переустановки) не встроен в начало/функцию.
Как таковой, я предложил бы использовать следующую последовательность:
git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2
Да, новая ветка, это должно решить это без использования --force, что, по моему мнению, является главным недостатком git.
Ответ 6
Другие ответили на ваш вопрос. Если вы пересобираете ветку, вам нужно будет принудительно нажать эту ветку.
Rebase и общий репозиторий обычно не ладят. Это история переписывания. Если другие используют эту ветвь или разветвляются из этой ветки, тогда перестановка будет довольно неприятной.
В целом, rebase хорошо работает для управления локальными веткими. Управление удаленным филиалом работает лучше всего с явным слиянием (-no-ff).
Мы также избегаем объединения мастера в ветвь функции. Вместо этого мы переустанавливаем мастер, но с новым именем ветки (например, добавляем суффикс версии). Это позволяет избежать проблемы с перезагрузкой в общем хранилище.
Ответ 7
Мой способ избежать принудительного нажатия - создать новую ветку и продолжить работу над этой новой веткой и после некоторой стабильности удалить прежнюю ветвь, которая была переустановлена:
- Восстановление локально проверенной ветки
- Ветвление с переустановленной ветки на новую ветку
- Нажатие этой ветки как новая ветвь на удаленный. и удаление старой ветки на пульте дистанционного управления.
Ответ 8
Что случилось с git merge master
в ветке feature
? Это сохранит работу, которую вы имели, оставив ее отдельно от основной ветки.
A--B--C------F--G
\ \
D--E------H
Изменить: Ах, извините, не прочитал ваш запрос проблемы. При выполнении rebase
вам понадобится сила. Все команды, которые изменяют историю, нуждаются в аргументе --force
. Это отказоустойчиво, чтобы вы не потеряли работу (старые D
и E
будут потеряны).
Итак, вы выполнили git rebase
, который сделал дерево похожим (хотя частично скрытый как D
и E
больше не находится в названной ветке):
A--B--C------F--G
\ \
D--E D'--E'
Итак, при попытке нажать новую ветвь feature
(с D'
и E'
в ней) вы потеряете D
и E
.
Ответ 9
Для меня работает следующее:
git push -f origin branch_name
и он не удаляет мой код.
Но, если вы хотите этого избежать, вы можете сделать следующее:
git checkout master
git pull --rebase
git checkout -b new_branch_name
то вы можете вишневым выбрать все свои фиксации в новую ветку.
git cherry-pick COMMIT ID
а затем нажмите новую ветку.
Ответ 10
Для меня работает следующие простые шаги:
1. git checkout myFeature
2. git rebase master
3. git push --force-with-lease
4. git branch -f master HEAD
5. git checkout master
6. git pull
После всего вышеперечисленного, мы также можем удалить ветку myFeature, выполнив следующую команду:
git push origin --delete myFeature
Ответ 11
Поскольку ОП понимает проблему, просто ищет более приятное решение...
Как насчет практики?
-
Имейте в реальной ветке разработки функций (где вы никогда не переустанавливаете и не нажимаете, поэтому ваши разработчики разработчиков не ненавидят вас). Здесь регулярно извлекайте эти изменения из основного с помощью слияния. История Мессье, да, но жизнь проста, и никто не ввязывается в его работу.
-
У вас есть вторая ветвь для разработки функций, в которой член команды один постоянно подталкивает все функции к фиксации, действительно переустановленные, действительно принудительные. Таким образом, почти чисто основано на довольно недавнем комманде. По завершении функции нажмите эту ветвь поверх мастера.
Возможно, уже существует имя шаблона для этого метода.