Разделите ветку git на несколько веток, чтобы объединить их в мастер

Моя команда работала в прототипе ветки master. Теперь я хочу взять эту работу, разбить ее на разные «ветви функций» и объединить их по отдельности в мастер. Я вижу пару способов сделать это, ни один из которых мне не нравится:

1 – Создайте новую ветку Feature_1 вне master. Вручную скопируйте код из Prototype в Feature_1. Это означает, что я должен отслеживать, что я скопировал, когда я иду делать Feature_N, и я теряю историю.

2. Создайте новую ветку Feature_1 вне Prototype. Каким-то образом верните код, который не является частью первой функции в Feature_1. Это позволяет избежать лжи git (и сохраняет историю), но кажется, что Feature_N будет беспорядком для слияния, потому что я сказал мастеру, что изменения были отменены, когда я нажал Feature_1.

Я пропустил более хороший способ сделать это?


person JoeB    schedule 30.10.2014    source источник


Ответы (2)


Ответ @Michael хорош, если ваши коммиты представляют собой коммиты с одной функцией, которые не имеют общих зависимостей с фиксациями для какой-либо другой функции. Однако, если вы смешали работу над двумя функциями в каком-либо коммите, вам понадобится интерактивная перебазировка. Он позволяет произвольно перераспределять фрагменты изменений и границы фиксации, а также отслеживает, какие фрагменты еще не были зафиксированы в текущей ветке.

Если изменения функций просто иногда объединяются в коммиты и нет зависимостей между функциями, то для облегчения жизни моей первой попыткой было бы git rebase -i master prototype разделить коммиты со смешанными фрагментами на два коммита, по одному для каждого, а затем завершить с помощью вишни, как в ответе Майкла. Данный

A1-B2-C12-D2-E1-F12    prototype

где цифры означают, для каких функций коммит содержит код, для `git rebase -i мастер-прототип, который вы редактируете, коммиты C12 и F12,

pick A1
pick B2
edit C12
pick D2
pick E1
edit F12

(с использованием хэша каждого коммита вместо его иллюстративного тега здесь).

Rebase остановится после коммита C12, и вы можете git reset HEAD~ затем git add --patch применить все фрагменты функции-1, git commit создать коммит C1 там, где был C12, затем git commit -a применить все оставшиеся фрагменты и создать коммит C2 после него. Вы закончите с

A1-B1-C1-C2-D2-E1-F1-F2

а потом можно git checkout -b feature1 master; git cherry-pick A1 B1 C1 E1 F1 и аналогично для feature2.

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

person jthill    schedule 30.10.2014
comment
если вы делаете git reset HEAD~, то вам нужно сделать обычный git commit (без --amend) впоследствии, чтобы создать новый коммит C1. В противном случае git commit --amend отредактирует (изменит) предыдущую фиксацию (в данном примере B2), и вы получите ...-B12-C2-.... Кроме того, вы можете сбросить только отдельные файлы с помощью git reset HEAD~ /path/to/file, что оставит остальную часть коммита на месте, поэтому вы можете изменить его с помощью git commit --amend. - person iliis; 03.02.2021
comment
@iliis вы правы, это должно быть либо git read-tree @~ вместо git reset @~, либо просто git commit вместо git commit --amend. Спасибо, что указали на это, исправлено. - person jthill; 03.02.2021

Создайте две ветки feature_1 и feature_2 от master и выберите коммиты из prototype в соответствующей ветке:

git checkout -b feature_1 master
git cherry-pick <commit>
git cherry-pick <commit>
…

git checkout -b feature_2 master
git cherry feature_1 prototype | grep "^+" | cut -c3- | xargs git cherry-pick

Вишенка последней строки выбирает все коммиты из prototype, которые не находятся в feature_1, в текущую ветку, т.е. feature_2.

Когда вы сталкиваетесь с конфликтами, используйте git status для подсказок, как продолжить.

См. git-cherry-pick для получения дополнительной документации.

person Michael    schedule 30.10.2014
comment
Мы на самом деле придумали вишневый выбор, когда обсуждали здесь, я попробую это. - person JoeB; 30.10.2014
comment
Есть ли способ сделать это, если ни одно из изменений еще не было зафиксировано? - person Michael; 06.02.2018
comment
Создайте новую ветку, используйте git add --patch, чтобы добавить изменения, которые вы хотите иметь в этой ветке (+ git add для новых файлов), зафиксируйте, сохраните оставшиеся изменения, извлеките новую ветку на основе мастера (git checkout -b feature_2 master), добавьте и зафиксируйте свои изменения. - person Michael; 07.02.2018