Реструктуризация Git repo с прототипом кода в фактический опубликованный проект

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

dir:root
 └ dir:feature-a
 └ dir:feature-b
 └ dir:feature-c
 └ dir:common
 └ file:build.gradle
 └ file:build.py

где каждая функция соответствует одному из суб-API. Стоит упомянуть, что каталоги не плоские, я просто пропустил подкаталоги для простоты.

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

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

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

Наконец, каталог common является немного особенным - я не против резать его историю версий, если есть его содержимое.

Ответ 1

Резюме

Если вы хотите сохранить историю некоторых общих ресурсов (build.*) и сохранить эти ресурсы в будущем легко, и вы хотите переписать/отфильтровать/удалить подмножество других деревьев в репозитории (feature-a, common) с помощью git filter-branch, вы должны сначала переписать свои существующие коммиты в следующем порядке:

  • Все общие коммиты до того, как проект был раздвоен из шаблона (это уже будет так).
  • Все совершает модификацию build.*, включая локальные изменения и слияния с вашей колыбелью вверх.
  • Наконец, все специфичные для проекта коммиты для feature-* и common.

Затем вы можете безопасно запустить git filter-branch на линии разработки проекта, не переписывая ни одну из предыстории ресурсов ресурсов. Если вы этого не сделаете, вы, вероятно, закончите повторную запись коммитов с использованием скриптов сборки, в том числе слияния-коммиты с восходящей Cradle, что будет препятствовать отслеживанию истории и будущим слияниям.

Detail

Похоже, у вас есть шаблон золотого проекта, назовите его T, и каждый раз, когда вы начинаете новый проект, вы открываете это репо (либо в традиционном смысле GitHub, либо просто создаете то, что будет расходящимся clone) назовите его Pn. Итак, Pn и T начинаются с одной и той же истории и общих коммитов (вызовите точку ветвления Pn-0).

Поскольку Pn разрабатывает свою кодовую базу, другие проекты могут определять улучшения базовой инфраструктуры шаблона проекта и вносить изменения в файл F в T. Любой проект Pn, который может составлять сотни коммитов перед шаблоном, все равно может объединить изменения в общих файлах из T.

Теперь вы хотите переписать историю в Pn. Поскольку Pn-0 вы сделали много коммитов, специфичных для проекта, затем слияние из T, а затем больше коммита проекта. Если вам пришлось переписать P на Pn-0, чтобы filter-branch, история слияния из T теряется, так как истории расходятся, а будущие слияния с T становятся адскими.

Описывает ли это вашу проблему?

Я думаю, вы видите, что использование подхода project-clone-from-template имеет свои ограничения, когда вы хотите иметь полную свободу перезаписи истории для реорганизации своего репо проекта. Если у вас есть история как до, так и после того, как слияние происходит от T, вам нужно будет сделать какую-то причудливую реорганизацию, чтобы сохранить общую историю. Это решение:

  • Пусть Tx является последним фиксатором T, который вы выполнили с полным слиянием в Pn.
  • Извлеките T в репозиторий Pn и создайте ветвь в Pn, которая начинается с commit Tx.
  • Восстановите текущую историю Pn на этой ветке, переместив ее с базы Pn-0 (общая фиксация с T) на Tx, последняя общая фиксация с помощью T.

Этот подход будет воспроизводить всю вашу историю в Pn, как если бы она начиналась с Tx вместо Pn-0, поэтому commit Pn-1 имеет новый родительский Tx. Конечно, каждая фиксация будет переписана, поэтому любые существующие клоны Pn сразу становятся сиротами.

После этого вы можете запустить git filter-branch, начиная с переписанного commit Pn-1, и удалить любую историю неполных модулей.

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

Одна вещь, которую вы, возможно, захотите рассмотреть, - есть ли способ, которым вы можете производить и потреблять свою колыбель без обмена источниками. Это может быть не так удобно, как Git -merging, но если ваш проект шаблона контролируется версиями, и вы организуете логику сборки и, возможно, используете общие скрипты, вы можете модулизовать проект шаблона, чтобы вы больше не зависели от дочерних проектов, поддерживающих общие истории источников, чтобы объединить их - они просто используйте вместо этого последние двоичные файлы шаблонов. Зависит много от того, что в шаблоне, кроме логики сборки.