Можно ли перебазироваться на середину ветки (соединив оба конца)?

Не дубликат!

Все примеры ванильного перебазирования и причудливые диаграммы, которые я вижу, показывают, как перебазировать ветку на вершину другой ветки/коммита. Можно ли, скажем, переместить ветку А на конкретное промежуточное место на ветке Б?

        O--O--O Branch B             O--0--0--O--O Branch B
       /                            /  
O--O--O--0--0   Branch A     O--O--O

EDIT: я не ищу перебазирование в произвольную фиксацию, а перебазирую в середине ветки, соединяя оба конца


person Whimusical    schedule 25.01.2018    source источник
comment
конечно это так, вы можете проверить коммит, сделать там ветку, а затем перебазировать   -  person Dunno    schedule 25.01.2018
comment
Возможный дубликат Git: как перебазировать конкретную фиксацию?   -  person Dunno    schedule 25.01.2018
comment
@ Не знаю, это не тот случай. В примере с вашей ссылкой мой случай будет эквивалентен размещению D между B и C.   -  person Whimusical    schedule 25.01.2018
comment
Вы можете перебазировать поверх любого коммита.   -  person axiac    schedule 25.01.2018
comment
@axiac Я знаю, но я хочу не перебазировать поверх определенного коммита, а перебазировать между двумя коммитами другой ветки.   -  person Whimusical    schedule 25.01.2018
comment
Между двумя коммитами ничего нет.   -  person axiac    schedule 25.01.2018
comment
@axiac - Что это вообще значит? Между двумя книгами на моей книжной полке ничего нет, пока я не поставлю между ними другую книгу.   -  person Mark Adelsberger    schedule 25.01.2018
comment
@MarkAdelsberger каждая книга на вашей полке привязана к предыдущей?   -  person axiac    schedule 25.01.2018
comment
@axiac - О, так вы хотите сказать, что вы не можете ничего поместить между двумя соседними фиксациями. Ну, это не то, что вы сказали, и когда мы говорим о переписывании истории (например, о перебазировании), это в любом случае практически не соответствует действительности.   -  person Mark Adelsberger    schedule 25.01.2018
comment
Перебазирование @MarkAdelsberger означает изменение базы. Вопрос плохо сформулирован и спрашивает, как не перебазировать поверх новой фиксации, а поверх того, что находится между двумя фиксациями. Я понимаю, что на самом деле спрашивает ОП, только после того, как внимательно изучил чертежи.   -  person axiac    schedule 25.01.2018
comment
@axiac - Что ж, извините, вы не поняли. Да, но это не то, что мы обсуждали. Что мне показалось неясным, так это ваше заявление о том, что между двумя коммитами ничего нет, поэтому я и спросил об этом.   -  person Mark Adelsberger    schedule 25.01.2018


Ответы (4)


Вы просите взять коммиты из одной ветки и поместить их в середину другой ветки. (Эта формулировка на самом деле не совпадает с тем, как git «думает» об отношениях веток и коммитов, но я думаю, что вы имеете в виду, понятно, так что ок...)

FROM:

x -- x -- A -- B -- C -- F -- G <--(branch_1)
      \
       D -- E <--(branch_2)

TO:

x -- x -- A -- B -- C -- D' -- E' -- F' -- G' <--(branch_1)

(Неясно, где вы хотите, чтобы ссылка branch_2 заканчивалась — или вы просто хотите ее удалить — но правильное выполнение коммитов — это большая проблема, и вы можете работать с ссылками позже.)

Важное примечание: на этой диаграмме коммиты D и далее заменяются коммитами D' и далее; это потому, что фиксация не может быть «перемещена» или изменена каким-либо образом, поэтому мы делаем новые фиксации. Это означает, что коммиты D, E, F и G (исходные версии) удаляются из истории ваших веток, что может вызвать проблемы, если ветки были отправлены. Обратитесь к документации git rebase (https://git-scm.com/docs/git-rebase) для получения дополнительной информации о проблемах, которые могут возникнуть, и способах их устранения; имейте в виду, что если эти проблемы оставить без внимания, вполне вероятно, что другой разработчик непреднамеренно отменит вашу работу.

Тем не менее, есть несколько способов сделать это; обычно вам понадобятся две операции перебазирования.

Один из наиболее простых способов подумать об этом — просто выполнить обычное перебазирование, а затем выполнить интерактивное перебазирование, чтобы изменить порядок коммитов.

Если вы хотите что-то более скриптовое, вы можете начать с

git rebase --onto branch_1~2 branch_1 branch_2

Здесь параметр --onto указывает новую базу, отличную от значения по умолчанию (значение по умолчанию — «конец восходящего потока»). Поскольку в этом примере я вставляю коммиты после родителя родителя branch_1, я могу использовать branch_1~2 или branch_1^^ в качестве нового базового выражения. Коммиты, которые нужно перезаписать, указываются обычным образом (в данном случае «доступны из branch_2, но недоступны из branch_1»). Таким образом, у вас будет

x -- x -- A -- B -- C -- F -- G <--(branch_1)
                     \
                      D' -- E' <--(branch_2)

и теперь вы просто холодите rebase branch_1 до конца branch_2 обычным способом.

git rebase branch_2 branch_1

уступающий

x -- x -- A -- B -- C -- D' -- E' -- F' -- G' <--(branch_1)
                                ^(branch_2)
person Mark Adelsberger    schedule 25.01.2018

Ваш вопрос неоднозначен, к счастью, рисунок проливает свет на то, что вы хотите.

Если я правильно понял, это входной статус репо

        M--N--P   <-- Branch B
       /
O--O--X--Y--Z     <-- Branch A

и это то, чего вы хотите достичь. Я использовал буквы для обозначения коммитов.

        M--Y--Z--N--P   <-- Branch B
       /
O--O--X

Сначала вам нужно создать новую ветку (C), указывающую на M, чтобы она оставалась видимой до конца операции.

git branch C B~2

Замените B~2 фактическим количеством ваших коммитов от N до B (включая оба) или используйте абсолютные ссылки (существующие ветки или хэши коммитов).

Следующая команда перемещает N-P поверх Z. Он перемещает все коммиты, которые находятся в B, но не в C, поверх A.

# Move N-P on top of Z (A points to Z, B points to P, C points to M)
git rebase --onto A C B

Последний шаг — переместить все коммиты, находящиеся в B, но не в C, поверх C:

# Move Y-Z-N-P on top of M (B still points to P, A still points to Z)
git rebase C B

Теперь репо выглядит так:

        +-- Branch C
        v
        M--Y'-Z'-N'-P'  <-- Branch B
       /
O--O--X--Y--Z           <-- Branch A

Ветвь A по-прежнему указывает на исходный коммит Z; также исходный коммит Y все еще на месте. Текущая ветка B.

Коммиты Y', Z', N' и P' являются копиями Y, Z, N и P. Они отличаются от оригиналов только датой коммита и родителем; нет изменений кода.

Ветки A и C теперь можно удалить. (git branch -D A C).

Подробнее о git rebase.

person axiac    schedule 25.01.2018

Да можно, нужно сначала

git checkout <commit>

Затем переустановите свою ветку, а затем нажмите на источник.

person Mike Tung    schedule 25.01.2018
comment
Спасибо за ответ! Это будет как на второй картинке? Я потеряю последние коммиты Branch B или что-то в этом роде? - person Whimusical; 25.01.2018
comment
На вашем изображении это будет две перебазировки: одна от A до B, чтобы вы получили фигуру справа (верхняя часть), а затем вторая от B до A, чтобы установить соединение. - person Mike Tung; 25.01.2018
comment
Я до сих пор не уверен, что это именно мой случай, извините. Похоже, все просто предположили, что я хочу, чтобы ветка была прикреплена к другой, а не интегрирована - person Whimusical; 25.01.2018
comment
Более фундаментально, чем указанная Whimusical операция, она не кажется правильной. Какая фиксация проверяется, когда вы выполняете перебазирование, не определяет новую базу для переписанных коммитов так, как это предполагает. (Он предоставляет значение по умолчанию для того, что должно быть последним переписанным коммитом, но я почти никогда не использую этот факт.) - person Mark Adelsberger; 25.01.2018

Я бы сначала перебазировал обычную ветку A на ветку B. Затем я бы использовал git rebase -i HEAD~n (где n — количество коммитов для интерактивного редактирования) и сделал бы перестановку коммитов (просто изменив порядок строк в редакторе).

person Michal Butterweck    schedule 25.01.2018