Подтвердить что ты не робот

Как разделить большую ветвь Git на множество небольших ветвей?

Я импортировал из SVN в Git, теперь у меня одна большая ветвь, вот так:

  • работать с функцией C
  • работа над функцией B
  • работать с функцией C
  • работать с функцией C
  • работа над функцией B
  • работа над функцией A

Я хочу отдельные ветки функций для A, B, C. Я собираю вишню для новых ветвей, но это не удаляет их из исходной ветки, поэтому мне приходится вручную отслеживать, какие из них я вытащил.

Есть около 800 коммитов для разделения и, возможно, 50 исправлений/исправлений.

Было бы неплохо, чтобы те, которые я вытащил, так или иначе вошли в журнал git, поэтому я знаю, какие из них я уже сделал. Возможно ли это?

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

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

4b9b3361

Ответ 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. Затем они начали классифицировать изменения...

  • а. = изменения в компиляторе
  • б. = изменения библиотеки
  • с. = Изменения IDE
  • д. = улучшения безопасности

    и т.п.

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 которые часто приходят с модернизацией.