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 смотрите. (Таков ваш оригинальный вопрос.)