Git push отклонен после перебазировки ветки - PullRequest
790 голосов
/ 20 января 2012

ОК, я думал, что это простой сценарий git, чего мне не хватает?

У меня есть ветка 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 коммитов на master, поэтому я 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 ful?

Эта ветвь функций не используется другими разработчиками, поэтому у меня нет проблем deФакт с помощью принудительного толчка, я не собираюсь терять данные, вопрос более концептуальный.

Ответы [ 11 ]

563 голосов
/ 20 января 2012

Проблема в том, что 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 и принудительное их возвращение в удаленный репозиторий - это нормально, если вы единственный, кто работает в этой ветке.

337 голосов
/ 26 мая 2016

Вместо использования -f или --force разработчики должны использовать

--force-with-lease

Почему?Потому что он проверяет удаленную ветку на наличие изменений, что является хорошей идеей.Давайте представим, что Джеймс и Лиза работают над одной и той же веткой функций, а Лиза выдвинула коммит.Джеймс теперь перебазирует свою местную ветку и отклоняется при попытке подтолкнуть.Конечно, Джеймс думает, что это связано с перебазированием и использует --force, и переписал бы все изменения Лизы.Если бы Джеймс использовал --force-with-lease, он бы получил предупреждение о том, что кто-то другой совершил коммиты.Я не понимаю, почему кто-то будет использовать --force вместо --force-with-lease при нажатии после ребазинга.

41 голосов
/ 22 октября 2015

Я бы использовал вместо этого «checkout -b», и это было бы легче понять.

git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature

при удалении вы не можете нажать на выходящую ветку, которая содержит другой идентификатор SHA.В этом случае я удаляю только удаленную ветку.

19 голосов
/ 20 января 2012

Одно из решений этой проблемы состоит в том, чтобы сделать то, что делает сценарий msysGit rebasing merge - после rebase объединить старый заголовок 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

(Не проверено, но я думаю, что правильно ...)

15 голосов
/ 28 октября 2013

Может быть, а может и нет, что в этой ветке есть только один разработчик, который сейчас (после ребазинга) не соответствует источнику / функции.

Как таковой, я бы предложил использоватьследующая последовательность:

git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2

Да, новая ветвь, это должно решить эту проблему без --force, что, на мой взгляд, является основным недостатком git.

12 голосов
/ 20 января 2012

Другие ответили на ваш вопрос. Если вы перебазируете ветку, вам нужно будет принудительно нажать на эту ветку.

Rebase и общий репозиторий обычно не ладят. Это переписывает историю. Если другие используют эту ветку или имеют ответвления от этой ветви, то ребаз будет довольно неприятным.

В целом, rebase хорошо работает для локального управления филиалами. Удаленное управление ветками лучше всего работает с явными слияниями (--no-ff).

Мы также избегаем слияния мастера в ветку функций. Вместо этого мы перебазируем на master, но с новым именем ветви (например, добавив суффикс версии). Это позволяет избежать проблемы перебазирования в общем хранилище.

11 голосов
/ 19 июня 2017

Мой способ избежать принудительного нажатия - создать новую ветку и продолжить работу с этой новой веткой, а после некоторой стабильности удалить старую ветвь, которая была перебазирована:

  • Перебазирование извлеченной веткилокально
  • Ветвление из перебазированной ветви в новую ветвь
  • Перенос этой ветви как новой ветки на удаленную ветку.и удаление старой ветки на удаленном
8 голосов
/ 20 января 2012

Что не так с 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'

Таким образом, при попытке вставить новую ветку featureD' и E' в ней) вы потеряете D и E.

4 голосов
/ 19 августа 2015

У меня работает следующее:

git push -f origin branch_name

и он не удаляет мой код.

Но, если вы хотите избежать этого, вы можете сделать следующее:

git checkout master
git pull --rebase
git checkout -b new_branch_name

тогда вы можете выбрать все свои коммиты в новую ветку. git cherry-pick COMMIT ID а затем нажмите вашу новую ветку.

2 голосов
/ 08 августа 2018

Для меня работает следующие простые шаги:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...