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
толчок отклоняется, поскольку дерево изменилось из-за перебазирования. Это может быть решено только с git push --force origin feature
,
Я ненавижу использовать --force
не будучи уверенным, что мне это нужно. Так мне это нужно? Обязательно ли перебазировка подразумевает, что следующий push
должно быть --force
FUL?
Эта ветвь функций не используется другими разработчиками, поэтому де-факто у меня нет проблем с принудительным нажатием, я не собираюсь терять какие-либо данные, вопрос более концептуальный.
14 ответов
Проблема в том, что git push
Предполагается, что удаленная ветвь может быть быстро перенаправлена в вашу локальную ветвь, то есть, что вся разница между локальной и удаленной ветвями заключается в том, что в конце есть несколько новых коммитов:
Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
\
T--Y <- some-branch
Когда вы выполняете git rebase
коммиты D и E применяются к новой базе, и создаются новые коммиты. Это означает, что после перебазирования у вас есть что-то вроде этого:
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
и принудительно отправлять их обратно в удаленное хранилище - это нормально, если вы единственный, кто работает в этой ветке.
Вместо использования -f или --force разработчики должны использовать
--force-with-lease
Зачем? Потому что он проверяет удаленную ветку на наличие изменений, что является хорошей идеей. Давайте представим, что Джеймс и Лиза работают над одной и той же веткой функций, а Лиза выдвинула коммит. Джеймс теперь перебазирует свою местную ветку и отклоняется при попытке толкнуть. Конечно, Джеймс думает, что это происходит из-за перебазирования и использует --force, и переписал бы все изменения Лизы. Если бы Джеймс использовал --force-with-аренды, он получил бы предупреждение о том, что кто-то другой совершил коммиты. Я не понимаю, почему кто-то будет использовать --force вместо --force-with-lease при нажатии после ребазинга.
Я бы использовал вместо "checkout -b", и это легче понять.
git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature
когда вы удаляете, вы не можете нажать на выходящую ветку с другим идентификатором SHA. Я удаляю только удаленную ветку в этом случае.
Одно из решений этой проблемы - сделать то, что делает сценарий слияния msysGit: после слияния слить в старый заголовок feature
с -s ours
, В итоге вы получите граф фиксации:
A--B--C------F--G (master)
\ \
\ D'--E' (feature)
\ /
\ --
\ /
D--E (old-feature)
... и ваш толчок feature
будет перемотка вперед.
Другими словами, вы можете сделать:
git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature
(Не проверено, но я думаю, что это правильно...)
Другие ответили на ваш вопрос. Если вы перебазируете ветку, вам нужно будет принудительно нажать на эту ветку.
Rebase и общий репозиторий обычно не ладят. Это переписывает историю. Если другие используют эту ветку или имеют ответвления от этой ветки, то ребаз будет довольно неприятным.
В целом, rebase хорошо работает для местного филиала. Удаленное управление филиалами лучше всего работает с явными слияниями (--no-ff).
Мы также избегаем слияния мастера в ветку функций. Вместо этого мы перебазируем на master, но с новым именем ветви (например, добавив суффикс версии). Это позволяет избежать проблемы перебазирования в общем хранилище.
Может быть, а может и нет, что в этой ветке только один разработчик, который сейчас (после ребазинга) не соответствует источнику / функции.
В качестве такового я бы предложил использовать следующую последовательность:
git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2
Да, новая ветка, это должно решить эту проблему без --force, что, на мой взгляд, является основным недостатком git.
Мой способ избежать принудительного нажатия - создать новую ветку и продолжить работу над этой новой веткой и после некоторой стабильности удалить старую ветку, которая была перебазирована:
- Перебазирование проверенной ветки локально
- Ветвление из перебазированной ветки в новую ветку
- Раздвигая эту ветку как новую ветку к удаленной. и удаление старой ветки на удаленной
Что не так с 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
,
Следующие работы для меня:
git push -f origin branch_name
и это не удаляет любой мой код.
Но, если вы хотите избежать этого, вы можете сделать следующее:
git checkout master
git pull --rebase
git checkout -b new_branch_name
тогда вы можете выбрать все свои коммиты в новую ветку.git cherry-pick COMMIT ID
а затем нажмите вашу новую ветку.
Для меня работает следующие простые шаги:
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
Получение новых изменений в главной и функциональной ветке rebase поверх последней главной
git checkout master
git pull
git checkout feature
git pull --rebase origin master
git push origin feature
Поскольку ОП понимает проблему, просто ищет более хорошее решение...
Как насчет этого как практики?
Вступайте в настоящую ветку разработки функций (где вы никогда не перебираете и не форсируете, чтобы ваши коллеги-разработчики не ненавидели вас). Здесь регулярно берут эти изменения с основного слияния. Да, история сложнее, но жизнь легка, и никто не вмешивается в его работу.
Иметь вторую ветку разработки функций, где один член команды функций регулярно выталкивает все функции, делает их фактически перебазированными, действительно форсированными. Так что почти чисто основано на довольно недавнем генеральном коммите. По завершении функции нажмите эту ветку сверху мастера.
Для этого метода уже может быть имя шаблона.
Сначала извините, это не ответ Обычно это должен быть ответ, но я подумал, что было бы важно подчеркнуть, что ответы не выглядят как правильный способ использования перебазирования (некоторые из них являются допустимым обходным путем, но не так элегантны, как мы можно было ожидать от git).
- "git force" - опасно, может переопределить работу других
- Создание новой ветки — потребуется синхронизация с другими, кто работает над этой функциональной веткой, упустите смысл использования git.
- воссоздание ветки (после ее удаления с помощью или без однострочной магической команды), те же проблемы, что и в № 2.
- «git merge» — rebase был разработан, чтобы избежать/предотвратить коммиты слияния в журнале и поддерживать чистоту и согласованность журнала git.
К сожалению, у меня нет ответа (пока). Среди вышеперечисленных «git merge» — единственный, который безопасен для командной работы.
[Редактировать № 1] В соответствии с этим замечательным документом Atlassian rebase следует использовать только для вашей локальной работы.
Не перебазируйте общедоступную историю. Как мы обсуждали ранее в истории перезаписи, вы никогда не должны перебазировать коммиты после того, как они были отправлены в общедоступный репозиторий. Перебазирование заменит старые коммиты новыми, и будет казаться, что эта часть истории вашего проекта внезапно исчезла.
[Редактировать № 2] Согласно этому прекрасному объяснению , это ожидаемое поведение. Это означает, что вам может потребоваться повторно объединить вещи, которые уже были объединены в исходном коммите. Если torec прав и если я прав, то я голосую за старый добрый поток извлечения (выборки/слияния).
[Edit #3] Все вышеперечисленное может быть правильным в зависимости от сценария. Если вы работаете над функциональной веткой с другом, не нажимайте --force, а извлекайте и объединяйте origin/feature1. Если вы работаете над веткой в одиночку, вы можете нажать --force и получить красивый лог.
Я бы сделал как показано ниже
rebase feature
git checkout -b feature2 origin/feature
git push -u origin feature2:feature2
Delete the old remote branch feature
git push -u origin feature:feature
Теперь пульт будет иметь функцию (переустановленную на последний мастер) и функцию 2(со старой головкой мастера). Это позволит вам позже сравнить, если вы допустили ошибки при разрешении конфликтов.