Git: как отделить ветку функций после факта

Как я могу переместить некоторые коммиты функции из существующей ветви в ветку функции и эффективно удалить их из текущей ветви - как если бы функция была разработана в отдельной ветви функции?

Фон: ветка develop содержит коммиты двух функций A (скажем, 50 коммитов) и B (10 коммитов), дико смешанные, так как они изначально должны были быть в одном выпуске. Теперь мы откладываем функцию B. Таким образом, мы хотим иметь только функцию A в develop филиал и новый featureB ветвь, которая содержит коммиты A или A и B, так что если мы объединяем обе ветви, мы получаем текущую позицию develop ветка.

Один из способов сделать это - создать featureB ответвление от текущей позиции develop ветвь, а затем обратно применить коммиты от А до develop, Но тогда слияние нового develop а также featureB будет просто А.

Другим способом было бы переименовать текущий develop в featureB и вишня забрать все коммиты А в новый develop ветка. Но это эффективно изменило бы историю develop, что хлопотно.

Какой лучший способ сделать это?

4 ответа

Если твой develop ветка была опубликована, и вы не хотите переписывать ее историю (что было бы самым простым способом), тогда вы действительно можете отменить свои изменения в develop, начать все заново featureB ответвление перебазировано B изменения в верхней части develop, Что-то в этом роде:

 #given history (top - newest)
 #shaA3 <-- develop, HEAD
 #shaB2
 #shaA2
 #shaB1
 #shaA1

вернуться:

 git revert B2
 git revert B1

Теперь история содержит:

 #revert of shaB1 <-- develop, HEAD
 #revert of shaB2
 #shaA3
 #shaB2
 #shaA2
 #shaB1
 #shaA1

Создайте featureB и заново воспроизвести возвращенные коммиты заново:

 git checkout -b featureB
 git rebase -i --onto develop shaB1~1 featureB

Закомментируйте все коммиты, кроме тех, которые принадлежат функции B (shaB1 а также shaB2 в нашем случае) и завершите ребаз. На данный момент у вас должна быть история:

 #shaB2' <-- featureB, HEAD
 #shaB1'
 #revert of shaB1 <-- develop
 #revert of shaB2
 #shaA3
 #shaB2
 #shaA2
 #shaB1
 #shaA1

Чтобы перепроверить, что все прошло хорошо, вы можете сделать git diff shaA3 - должно быть пустым, git diff develop - должен содержать все желаемые B изменения.

PS Вы, конечно, можете использовать cherry-pick или reverts откатов, чтобы воспроизвести b изменения в branchBвместо интерактивной перебазировки, например, при разработке:

 git checkout -b branchB
 git revert <revert of shaB1>
 git revert <revert of shaB2>

Дам тебе:

 #revert of revert of shaB2 = shaB2' <-- featureB, HEAD
 #revert of revert of shaB1 = shaB1'
 #revert of shaB1 <-- develop
 #revert of shaB2
 #shaA3
 #shaB2
 #shaA2
 #shaB1
 #shaA1

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

git checkout -b new-develop X
git cherry-pick [all the feature_A commits]
# repeat the cherry-pick as needed or convenient if there's too many 
git checkout -b new-featureB X
git cherry-pick [all the feature_B commits]
# ...

затем поменяйте местами имена с git branch -m, принудительно нажмите и заставьте всех переиздать и перебазировать любую неопубликованную работу по мере необходимости.

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

Если вы на самом деле не можете этого сделать, тогда посмотрите подробный ответ @MykolaGurov.


(branchcheckout -b,,,)

Создать ветку featureB от текущего состояния развития. Передать код в ветку develop для дальнейшего развития FeatureA. Передать код в ветку featureB для разработки FeatureB. Регулярно перебазировать ветку featureB против ветви develop так что в нем есть изменения, которые добавляются для разработки featureA.

Если вы хотите избежать изменения опубликованной истории ветки develop, как в ответе @thill, а также хотите избежать отмены возвращенных коммитов, как в ответе @Mikola Gorov, вы также можете

  1. Создать ветку featureB от develop
  2. Вернуть коммитов B в филиал develop, Было бы разумно сделать это за один коммит revert B, так как это одна операция в истории.
  3. Слияние филиал develop в featureB со стратегией ours, Это не меняет никаких файлов в ветке featureB, но помечает отмененный коммит из 2. как уже слил в featureB, Таким образом, если вы позже объедините ветку featureB Вернуться в develop, результат не будет содержать commit revert B больше.

При слиянии featureB Вернуться в develop Вы могли бы хотеть иметь featureB в качестве первого родителя коммита. (Например, вы сливаете develop в featureB а затем установить develop в featureB, а не наоборот.) Я полагаю, таким образом, возвращение больше не будет путать вину и т.д. (?)

Другие вопросы по тегам