Можно ли ретроактивно превратить набор коммитов в ветвь?

Скажем, у меня есть репозиторий git, и я работал над мастером, могу ли я ретроактивно создать ветку. Например:

A - B - C - A1 - D - A2 - E

Я хочу сделать так:

A - A1 - A2   
\           \   
B - C - D - E

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

По сути, это то, что было бы хорошо как ветка с функцией или темой, но не создавалось таким образом.

Ответ 1

Конечно, вы можете. (С Git там не так много, как вы can not все равно.:)

git checkout -b new-branch hash-of-A
git cherry-pick hash-of-A1
git cherry-pick hash-of-A2

Это создаст новую ветку, начиная с commit A. Затем вы снова возвращаетесь к одной и той же фиксации, создавая другую ветку:

git checkout -b new-branch2 hash-of-A
git cherry-pick hash-of-B
git cherry-pick hash-of-C
git cherry-pick hash-of-D
git cherry-pick hash-of-E
git merge new-branch

Теперь вам просто нужно объединить new-branch и new-branch2, чтобы получить нужную структуру и отбросить старую ветку.

Конечно, что Дастин сказал, что все еще держится: хэши коммитов будут изменены, поэтому вы должны сделать это только в том случае, если вы еще не опубликовали свои изменения.

Ответ 2

Если вы хотите, чтобы все транзакции после ревизии XXX произошли в ветке, я нахожу это намного проще, чем другие предлагаемые методы.

$ git branch fixes       # copies master to new branch
$ git reset --hard XXX   # resets master to XXX

Это описано в справочной странице git для reset в разделе "Отменить фиксацию, сделав ее ветвью темы".

Ответ 3

Вы не можете сделать это прозрачно, потому что хэши должны будут меняться, но вам просто нужно отключить HEAD и rebase -i в обеих ветвях, чтобы удалить соответствующие изменения.

Ответ 4

Забудьте все, что вишневое. Просто rebase -i дважды опускаю изменения, каждый раз создавая новую ветку, а затем объединяем 2.

Ответ 5

Что вы хотите сделать, это фактически переписать историю. Идентификаторы коммитов изменились бы, и в некоторых случаях изменения, заданные коммитами, изменились бы. Поэтому, если есть вероятность, что кто-то может основывать работу на старой версии ветки, которую вы хотите изменить, лучше не делать этого. Но если вы не опубликовали эту ветку, не стесняйтесь.

Предположим, что ветвь, которую мы хотим изменить, называется "master", и что точка, в которой мы хотим начать новую ветку, называется "A" (в данном примере одним из имен, которые вы можете использовать, является "master-6" ").

Сначала давайте создадим новую ветку из commit 'A', назовите ее "fixes"

$ git checkout -b fixes A

Это также приведет к тому, что текущие значения "исправления" ветки. Потому что есть только несколько коммитов, которые мы хотим использовать без вишни, мы можем вишни выбрать их на фикчированных ветвях:

$ git cherry-pick A1
$ git cherry-pick A2

Затем мы хотим удалить коммиты 'A1' и 'A2' из ветки 'master'. Поскольку есть только несколько коммитов, которые мы хотим удалить, и, возможно, еще многое, что мы хотим сохранить, мы будем использовать 'git rebase -interactive' для этого:

$ git rebase -i fixes master

Редактор будет запущен со всеми коммитами в "хозяине" после фиксации "А" (который является общим фиксатором, т.е. объединяет базу ветвей "мастер" и "исправления ветки" ). Список будет выглядеть следующим образом:

pick deadbee B
pick fa1afe1 C
pick a98d4ba A1
...

Удалите строки с фиксациями "A1" и "A2", сохраните изменения, закройте редактор (или иным образом отправьте изменения в inetractive rebase), а git будет повторно использовать все фиксации, кроме тех, которые вы удалили.

Затем вы можете завершить работу с помощью

$ git merge fixes

(git -rebase оставил нас на перезаписанной ветке "master" ).