Как разделить большую ветвь Git на множество небольших ветвей?
Я импортировал из SVN в Git, теперь у меня одна большая ветвь, вот так:
- работать с функцией C
- работа над функцией B
- работать с функцией C
- работать с функцией C
- работа над функцией B
- работа над функцией A
Я хочу отдельные ветки функций для A, B, C. Я собираю вишню для новых ветвей, но это не удаляет их из исходной ветки, поэтому мне приходится вручную отслеживать, какие из них я вытащил.
Есть около 800 коммитов для разделения и, возможно, 50 исправлений/исправлений.
Было бы неплохо, чтобы те, которые я вытащил, так или иначе вошли в журнал git, поэтому я знаю, какие из них я уже сделал. Возможно ли это?
Я могу перегрузить всю ветку, пропуская коммиты, которые я вытащил, но я беспокоюсь, что это вызовет множество конфликтов. Я не хочу разрешать 500 конфликтов каждый раз, когда я вытягиваю фиксацию.
Какой лучший способ вытащить из одной ветки uber на более мелкие ветки функций, сохраняя при этом отслеживание вашего прогресса?
Ответы
Ответ 1
В этом случае я использую интерактивную rebase.
На вашем HEAD
создайте ветки A
, B
и C
. Также создайте "резервную" ветку (вы можете назвать ее backup
), если все пойдет не так, и вам понадобится исходный HEAD
.
git branch feature-a
git branch feature-b
git branch feature-c
git-branch backup-before-rebase
Затем создайте ветку в фиксации, которую вы хотите, чтобы начать, возможно, при удобной стабильной фиксации. Назовите его new_trunk
или что-то еще.
git checkout HEAD~50 ## this will be the new tree-trunk
git branch new_trunk
Затем сделайте интерактивный rebase
и выберите коммиты, которые хотите сохранить в этой ветке. Используемый таким образом, он в основном похож на cherry-pick
навалом.
git checkout feature-a
git rebase -i new_trunk ## -i is for "Interactive"
Когда вы закончите, у вас должно быть 3 ветки с отдельными историями, начиная с new_trunk
и ветки backup
, отражающей старую HEAD
, если она вам еще нужна.
Ответ 2
Лично я бы действительно рассмотрел плюсы и минусы таких больших изменений (еще раз, если вы уже это сделали). Если вы столкнетесь с конфликтами (которые находятся в большой перегрузке/вишневом подборке, раздражающими и трудно решаемыми сами по себе), вы, вероятно, столкнетесь с трудностями при объединении функций обратно в свою "ведущую" ветвь.
Не было бы лучше/проще заморозить вашу большую ветвь, сделать ее "сделанной" (или "достаточно хорошей" ) и создать на ней новые ветки функций? (Или исключить только некоторые ветки?)
Но на ваш вопрос:
Если вы хотите отслеживать изменения/отсутствующие коммиты, автоматически используйте команду git cherry.
git cherry featureBranch bigBranch
Если бы не возникало конфликтов при вихреобразовании или перезагрузке ветки функций, вы можете использовать предыдущий код с некоторыми дополнительными каналами:
git cherry featureBranch bigBranch | awk '{ print "pick " $2 }' | tee remaining
Это будет печатать (и сохранять в файл, называемый "оставшийся" ), который отсутствует в featureBranch. Вы можете добавить это к интерактивной перестановке на BigBranch, чтобы отбросить коммиты, которые вам больше не нужны. (Возможно, вы можете script сделать это еще больше с редактором ed в редакторе git и передать команды на стандартный ввод интерактивной rebase, но я не пробовал его.)
Ответ 3
Просто, чтобы упростить ответ willoller,
создать ветки функций и выполнить резервное копирование в случае
git branch feature-a
git branch feature-b
git branch feature-c
git branch backup-before-rebase
затем проверьте ветвь функции и выполните интерактивную переустановку с фиксацией, которую вы хотите, чтобы она начиналась с
git checkout feature-a
git rebase -i <safecommit>
enter code here
Если вы хотите, чтобы некоторые ветки функций делились некоторыми коммитами, чтобы сохранить ваше дерево в чистоте, не создавайте ветку с более поздними функциями в начале, но как только у вас есть дочерняя ветвь функции, а затем используйте ссылку с общим фиксацией в качестве своего next safecommit
#on branch feature-a
git checkout -b feature-d
git rebase -i <sharedcommit>
Ответ 4
Другой метод, о котором я только что узнал, использует "git notes".
http://alblue.bandlem.com/2011/11/git-tip-of-week-git-notes.html
Эта функция позволяет добавлять комментарии к существующим коммитам без фактического изменения ветки/требующей перезагрузки. Один из способов отслеживания, который совершается, заключается в том, чтобы добавить примечание git к каждому из них:
Cherry-picked to features\xyz 925a5239d4fbcf7ad7cd656020793f83275ef45b
Это может помочь в основном ручном процессе - вы можете написать немного script, чтобы вишня выбрать фиксацию для конкретной ветки, а затем добавить соответствующую записку git обратно к первоначальной фиксации.
В качестве альтернативы, если вы хотите по-настоящему напугать, вы можете автоматизировать весь процесс, используя:
- Добавьте примечание git к каждой фиксации, указав, с какой веткой вы хотите, чтобы она зависала:
TOCHERRYPICK: features\xyz
- Напишите script для сканирования всех примечаний git и автоматически создайте все ветки функций и вишни выберите правильные выбранные коммиты. Затем он может изменить примечание git на
CHERRYPICKED: features\xxx at 925a5239d4fbcf7ad7cd656020793f83275ef45b
, чтобы позволить повторному запуску инструмента, чтобы выделить больше коммитов.
- Если вы действительно заинтересованы в том, чтобы сделать это заметным, когда фиксация была выбрана вишней, вы также можете автоматизировать создание тега с похожим именем:
CHERRYPICKED:<branch>:SHA
Ответ 5
Честно говоря, я бы не стал этого делать, если у вас нет огромного списка коммитов, которые нужно разделить, и они являются очень независимыми функциями, то есть не изменяют ту же строку, где будут конфликты для разрешения.
Как предлагали другие, создайте новую ветвь для каждой функции и используйте git rebase --interactive
чтобы включить нужные коммиты.
Чтобы никто не сбился с пути, создайте содержимое файлов git-rebase-todo
помощью
- редактирование списка всех желаемых коммитов и их классификация по функциям
- разделение списка коммитов на отдельные файлы
Вы можете создать список коммитов, используя команду как
git log --oneline --reverse 44e19^... > log.txt
отображать коммит 44e19 и далее. Это даст вам такой файл
44e1936 dSRGratuities (SummaryRecord)
67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
69d70e2 Receipt Report: Payment
....
который при редактировании (чтобы добавить классификацию: функция a, b, c и т.д.) может выглядеть как мой sorted.txt
c 44e1936 dSRGratuities (SummaryRecord)
a 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
b 69d70e2 Receipt Report: Payment
c abea7db Receipt Report: Cashback
a cf96185 Receipt Report: Gratuity
c 70e987a Receipt Report: use amount tendered for printing
a 7722ac8 Receipt Report: use amount tendered for calculations
c 47f1754 Receipt Report: store amount tendered
b b69a73f Receipt Report: Use enum Paym_FieldCount
a 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
c ad67e79 Use SharpReport enum
b 3c510c6 enum SharpReport
a e470e07 m_Gratuities m_dSSGratuities (SalesSummary)
b 4e0c3e4 m_Gratuities m_szGratuities (SalesSummaryRecord)
b bd054f7 _gx_fn_Cashback
Затем создайте сценарий на своем любимом языке сценариев, чтобы превратить отсортированный список в коллекцию файлов git-rebase-todo
. Ваш сценарий может напоминать тот, который я только что написал.
foreachline text sorted.txt {
set fields [split $text { }]
set branch [lindex $fields 0]
set commit [lindex $fields 1]
set comment [string range $text 10 end]
set command "echo pick $commit $comment"
exec cmd /S /C $command >> $branch.txt
}
Сценарий читает файл сортировки фиксации построчно и разделяется пробелом {}, чтобы получить branch
и commit
двух полей, и принимает подстроку (10 символов и более) для описания фиксации. Описание не обязательно, но нам, людям, полезно проверять ошибки.
Затем он помещает строку в соответствующий файл git-rebase-todo
, создавая один файл для каждой функции. Я взломал это, выполнив очень уродливую команду Windows echo string >> file
.
Это создает ряд файлов, например, мой файл a.txt
pick 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
pick cf96185 Receipt Report: Gratuity
pick 7722ac8 Receipt Report: use amount tendered for calculations
pick 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
pick e470e07 m_Gratuities m_dSSGratuities (SalesSummary)
Все это безобразно. Я не рекомендую это делать, если вы не обязаны это делать и не умеете писать сценарии.
Я написал текст выше некоторое время назад, и я немного переосмыслил вещи. Выше я подразумевал, что это большая работа, и ее не стоит делать, но с тех пор я видел ситуации, когда, похоже, кто-то делал выше, и это было очень полезно.
Я помню выпуски Visual Studio для MFC/C++, где каждый новый выпуск будет содержать изменения компилятора, IDE, улучшения MFC и работать в более поздней версии Windows. Это означало, что если вы хотите отвести свой компилятор от VS6 и Windows XP, вам, возможно, придется внести изменения в язык, чтобы удовлетворить компилятор, и изменения вызова функции, чтобы удовлетворить MFC и т.д.
Теперь предположим, что Microsoft создавала еженедельные резервные копии при разработке Visual Studio, а кто-то методично брал старые резервные копии и фиксировал изменения кода в системе контроля версий, такой как Git. Затем они начали классифицировать изменения...
Microsoft могла бы создать ветки для каждого из них и начать использовать новейшую и самую лучшую IDE (c
включена), работающую на новейшей Windows и способную компилировать старые унаследованные программы с использованием языка (нет a
) и библиотек (нет b
), которые они были написаны для.
Разработчики, ранее привязанные к устаревшему программному обеспечению, могли затем вносить улучшения логическим и поэтапным образом, например, изменения языка и библиотеки независимо друг от друга, и делать это в самой последней и самой лучшей Visual Studio без необходимости проходить через все промежуточные версии.
пример
<LanguageStandard>stdcpp14</LanguageStandard>
Сейчас я не говорю, что это произошло, но мне кажется, что последние версии Visual Studio гораздо лучше позволяют обновлять устаревшие программы, а не выбрасывать и (никогда?) Переписывать, и мне кажется, из-за контроля версий и организации старых изменений программного обеспечения в логические ветки: версии компилятора, версии DLL/библиотеки.
Итак, я могу видеть случаи, когда стоит разделить огромное количество старых коммитов на отдельные ветки.
На Visual Studio 2019 я могу добавить строку
<PlatformToolset>v141_xp</PlatformToolset>
к файлу конфигурации и управлять скомпилированием и запуском старой программы Windows, которая не смогла скомпилировать и связать с VS 2015 и VS 2017. Очень похоже на то, что кто-то из Microsoft переместил улучшения производительности и безопасности на некоторое старое программное обеспечение, не обращая внимания на breaking changes
которые часто приходят с модернизацией.