Перебазирование ветки дает мне ошибку не быстрой перемотки вперед - PullRequest
1 голос
/ 27 февраля 2020

В основном у меня есть ветвь feature и ветвь master. Вот график:

enter image description here

Я хочу обновить ветку feature из ветви master, не выполняя фиксацию слияния на ветвь feature (в основном, «переместить» первый коммит ветви в «master 9»). Поэтому я попробовал следующие команды:

git checkout feature
git rebase master
git push

Но после pu sh, git возвращает ошибку.

! [rejected]        feature -> feature (non-fast-forward)
error: failed to push some refs to '...'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

И если я выполню предложенный git pull, после git push мой репозиторий блокируется примерно так: enter image description here

Что я не хотел. Я уже пытался использовать параметр --rebase с командой git pull, но, к сожалению, результат таков:

enter image description here

Я просто хочу «Первоначальный коммит» из ветви feature является коммитом master 9, но я уже пробовал что-либо без выполнения git push --force (что работает).

Может кто-нибудь объяснить мне, почему мне нужно использовать параметр силы для pu sh изменений на сервере?

1 Ответ

2 голосов
/ 27 февраля 2020

Rebase принципиально работает путем копирования коммитов. У вас есть цепочка коммитов:

...--A--B--F--G   <-- master
         \
          C--D--E   <-- feature

(это рисунок, похожий на графическое изображение, которое вы выложили: у меня боковые коммиты с новыми коммитами направо, против ваших с новыми коммитами сверху). Некоторые из этих коммитов теперь старые и паршивые, и вы хотели бы заменить их новыми и улучшенными коммитами. В частности, коммит C основан на B, и вам нужна копия C, которую мы можем назвать C', которая указывает на G, а не B. После этого вы хотите сделать копию D, которую мы можем назвать D', которая основана на только что сделанной копии C'. Это также повторяется для E:

                C'-D'-E'  <-- (new-and-improved-feature)
               /
...--A--B--F--G   <-- master
         \
          C--D--E   <-- feature

Теперь каждый коммит в Git на самом деле имеет уникальный идентификатор ha sh: большую уродливую строку букв и цифр, с которой никто не хочет иметь дело с. Это нормально, у нас, как правило, нет , чтобы иметь с ними дело: именно поэтому у нас есть компьютер. У нас есть Git, запомните эти идентификаторы ha sh. имена ветвей , в частности, помнят идентификатор ha sh последнего коммита в серии, на вершине ветви.

Итак, сделав эти копий, мы теперь вытаскиваем имя feature из коммита E и вместо этого копируем E':

                C'-D'-E'  <-- feature
               /
...--A--B--F--G   <-- master
         \
          C--D--E   [abandoned]

Все это происходит в вашем хранилище. В другом хранилище, в origin, новых коммитов еще нет.

Теперь вы используете git push, чтобы ваши Git вызывали их Git. Ваш Git отправляет им три новых блестящих коммита замены C'-D'-E', которые они на мгновение помещают на карантин (на случай, если они их отклонят), но которые теперь логически находятся в их хранилище:

                C'-D'-E'  [ready]
               /
...--A--B--F--G   <-- master
         \
          C--D--E   <-- feature

Обратите внимание, что их имя feature - это их имя, а не ваше имя - все еще указывает на обязательство E.

Ваш Git теперь говорит: Пожалуйста, если все в порядке, сделайте ваше имя feature укажите, чтобы совершить E'. Их Git смотрит на это изображение и говорит: Вау, приятель, это не ОК! Если я это сделаю, я забуду идентификатор ha sh существующего коммита E! Я никогда не смогу найти этот коммит снова!

! [rejected]        feature -> feature (non-fast-forward)

Это означает Ух ты, не Хорошо, я бы потерять некоторые коммиты!

Но потеря некоторых коммитов - это именно то, что вы хотите, чтобы они сделали . Это то, что ваш Git уже сделал: вы больше не можете найти свои оригинальные коммиты; вы бросили их в мусорную корзину, в пользу новых блестящих коммитов, которые вы только что сделали.

Теперь вы должны сказать другим Git на origin сделать то же самое. Для этого у вас есть две опции:

  • --force: здесь написано Установите feature! Нет проверки; вы просто посылаете им убедительную команду вместо вежливого запроса. Они подчиняются или не подчиняются тем правилам, которые они имеют для своих ветвей. Если вы авторизованы - и, вероятно, так и есть - они просто подчиняются.

  • --force-with-lease: у вас есть Git скажем Я думаю, что ваши feature указывают на старые commit E, который сейчас устарел. Если это так, укажите вместо feature новый коммит E'. Здесь они ответят OK , если ваш Git правильный, и нет , если ваш Git неверно.

Очевидно, что --force-with-lease в некотором смысле безопаснее: если ваш Git ошибается, вы получите ошибку обратно.

Интересные вопросы, которые вы должны задать здесь:

  • Откуда мои Git получают представление о том, на что указывают их Git feature?
  • Когда и почему их feature указывают куда-то, чего я не ожидал?

На эти вопросы вы найдете ответы здесь, на StackOverflow, если вы go смотрите. (Таков ваш оригинальный вопрос.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...