Как переписать историю для нескольких веток одновременно? - PullRequest
0 голосов
/ 22 февраля 2020

С помощью интерактивного перебазирования (git -i rebase ...) можно редактировать коммиты в любом месте в линии текущей ветви, таким образом, «переписывая историю».

Однако данный коммит может принадлежать линиям нескольких ветвей.

Например, предположим, что у меня есть репо с такой структурой ветвления:

A --- B --- C --- D --- F --- G  branch_1*
             \
              `-- H --- I --- J  branch_2
                         \
                          `-- K  branch_3

Если активная ветвь равна branch_1, и я использую rebase -i для редактирования коммита B, результирующий репо будет выглядеть так (по крайней мере, пока не произойдет G C):

  ,-- b --- c --- d --- f --- g  branch_1*
 /
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J  branch_2
                         \
                          `-- K  branch_3

Обратите внимание, что исходный B по-прежнему находится в линиях branch_2 и branch_1. Повторение процесса для каждой из этих веток, как бы это ни было утомительно, приведет к множественным избыточным фиксациям, и первоначальная структура ветки будет потеряна:

  ,-- b --- c --- d --- f --- g  branch_1
 /
A --- B --- C --- D --- F --- G
|            \
|             `-- H --- I --- J
|                        \
|                         `-- K
|\
| `-- b' -- c' -- h --- i --- j  branch_2*
 \
  `-- b'' - c'' - h' -- i' -- k  branch_3*

Обратите внимание, что b, b' и b'' по существу эквивалентны коммитам. То же самое касается c, c' и c'', h и h', i и i'.

Есть ли на полпути удобный способ чего-то достичь например:

A --- b --- c --- d --- f --- g  branch_1*
             \
              `-- h --- i --- j  branch_2
                         \
                          `-- k  branch_3

... где модификация коммита B распространяется через все линий, к которым он принадлежит?

(я бы предпочитайте решение, которое также распространяет изменения на все последующие тайники.)

Ответы [ 2 ]

3 голосов
/ 22 февраля 2020

... есть ли на полпути удобный способ достижения [разумного результата]

Нет.

Есть одна команда, git filter-branch, которая может сделать это, но это не удобно и даже не удобно на 1/4. Это около 1000% в удобно. : -)

Новый git rebase --rebase-merges механизм вполне приспособлен для более удобного выполнения подобных задач, 1 , но в настоящее время он не предназначен для перебазируйте несколько названий ветвей.

Новый экспериментальный git filter-repo достаточно способен делать то, что вы хотите, и, вероятно, менее неудобен, чем git filter-branch, но он все еще отбрасывает ошибки с ядерным оружием - в этом случае, может быть, довольно крупная ошибка, не просто муха, но все же серьезное излишество.

(однажды я написал свою собственную экспериментальную вещь, чтобы сделать такой перебаз, но я так и не закончил. Я нуждался в этом, когда это было нужно. Он работал с использованием эквивалента повторяющихся git rebase --onto операций и имел много угловых случаев.)


1 Ключ к быть в состоянии пометить определенных коммитов, так что после того, как ребаз копирует их, вы можете создать пару ha sh -ID пары, и в противном случае перепрыгивайте структуру графа из одной цепочки в другую по мере продвижения ребаза. Старый код --preserve-merges не мог этого сделать; новый код --rebase-merges может. После того, как эти фрагменты будут на месте, перебазирование нескольких ветвей «одновременно» - это просто вопрос сохранения нескольких названий ветвей для принудительной настройки после завершения ребазирования. Затем у вас есть список ребаз правильных коммитов и точек перехода. Основная часть операции rebase состоит из копирования этих коммитов. Наконец, используя сопоставление «старый-новый», rebase может настроить имя каждой ветви, а затем повторно подключить HEAD к нужному.

Оставшаяся проблема уровня пользовательского интерфейса заключается в выборе правильного набора ветвей. имена для multi-rebase.

0 голосов
/ 22 февраля 2020

Как вы говорите, если вы перебазируете branch_1, меняя B, вы получите:

  ,-- b --- c --- d --- f --- g  branch_1*
 /
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J  branch_2
                         \
                          `-- K  branch_3

Затем вы можете перебазировать branch_2 на c с помощью:

git rebase --onto c C

уступает:

  ,-- b --- c --- d --- f --- g  branch_1*
 /           \
|             `-- h --- i --- j  branch_2
|
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J
                         \
                          `-- K  branch_3

и затем перебазирует branch_3 на i:

git rebase --onto i I

, получая:


  ,-- b --- c --- d --- f --- g  branch_1*
 /           \
|             `-- h --- i --- j  branch_2
|                        \
|                         `-- j  branch_3
|
A --- B --- C --- D --- F --- G
             \
              `-- H --- I --- J
                         \
                          `-- K

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

...