2016-12-05 7 views
2

Моя ситуация в том, что у меня есть два репозитория Git, которые мне нужно объединить в один репозиторий (на самом деле есть больше репозиториев, но я могу начать с двух).Как объединить несколько репозиториев Git в одну и чередующиеся истории

Два хранилища являются:

  • Основной репозиторий, .
  • Второй репозиторий, B.

Код в хранилище B имеет зависимость от кода в репозитории (но не наоборот), и истории обоих хранилищ следуют друг за другом в хронологическом порядке - примерно (т.е. конкретная фиксация в репо B обычно требует фиксации из репо A с очень близким временем фиксации).

В обоих хранилищах существуют конфликтующие имена ветвей и тегов (нет гарантий, что они принадлежат друг другу), но необходимо сохранить только ссылки от A.

Требования, предъявляемые к новому хранилище, С, являются:

  1. всех рефов (ответвления и метки) от должны быть сохранены.
  2. Необходимо сохранить только основную ветку от B (т. Е. Фиксации, о которых сообщается git log --first-parent master).
  3. файлы из каждого исходного хранилища должны быть введены в подпапки нового хранилища (т.е. файлы из должны идти в A/ и файлы образуют B должен идти в B/).
  4. При проверке специфично фиксации (в том числе коммитов сделать до того слияния) в хранилище C (например, выпуск таг) совместимые файлы образуют оба источника хранилища должны быть найдены в каталогах A/ и B/ (по крайней мере, в пределах совершить или два).

До сих пор я пытался несколько подходов, в том числе и thisgit-stitch-repo без успеха (они не отвечают указанным выше требованиям).

В этот момент мне удалось:

  • Переместить все файлы в каждом репозитории в подкаталог с помощью GIT фильтра-ветвь. Например.для репо :
 
mkdir A 
mv * .gitignore A/ 2> /dev/null 
git commit -a -m 'DROPME' > /dev/null 
git filter-branch --tag-name-filter cat --index-filter 'git ls-files -s | sed "s-\t\"*-&A/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" ||:' -- --all 
git reset --hard origin/master 
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 
  • Импорт репо B в с использованием git fast-export/fast-import.
  • Устройство способ генерации отображения таким образом, что для данного SHA в , существует список нулевой, один или более SHA: с, которые должны быть вставлены из B.

Что я ожидал бы сейчас, что некоторые умные использование git filter-branch должны позволить мне вставить выбранные коммиты из B в основной ветви . Но как?

ответ

1

Решение оказалось гораздо более активным, чем я надеялся. Он включает в себя управление и объединение вывода двух (или более) потоков git fast-export и их импорт в новый репозиторий с использованием git fast-import.

Короче говоря, поток fast-import генерируется путем перемещения двух входных потоков и переключения между ними на основе сортированного по дате журнала из основных ветвей.

Я реализовал решение в сценарии Python под названием join-git-repos.py, который я разместил в репозитории GitHub here.

1

Сначала переместите все в репо A в подкаталог A /. Ничего необычного, всего git mv. Это сохраняет все ветки и теги и фиксирует идентификаторы в A.

Затем используйте git subtree, чтобы главная ветвь B была поддеревом A в каталоге B /.

git subtree add -P B/ <remote for B> master 

И все готово.

Если вы хотите, чтобы старые теги релиза на A также отражали то, что было бы в B в то время ... oy. Вы можете сделать это, не испортив свою историю слишком плохо, объединив B в A непосредственно перед каждым тегом релиза.

У вас есть это.

  * - * - *   * - * - * branch 
    v1 /  \ v2 /
* - * - * - * - * - * - * - * - * - * master 
           /
    * -- * ---- * - * - * --------- * 

Нижняя строка фиксации - это фиксации B. B, поэтому они выстраиваются во времени с помощью A.

И вы хотите что-то вроде этого.

  * - * - *   * - * - * branch 
    v1 /  \ v2 /
* * * - * - * - * - * * * - * - * - * master 
    |     |   /
    * -- * ---- * - * - * --------- * 

Это объединило B в A непосредственно перед каждым релизным тегом. Это позволяет избежать искусственной истории развития A и B вместе.

Я не знаю, как это сделать автоматическим способом. Проблема rebase не сохраняет теги, только сливается. Таким образом, добавление компиляции слиянием в v1 потеряет тег v2, и я не уверен, как определить, что такое первоначальная фиксация переустановленной фиксации.

Удачи.

+1

Я попробую, но я не вижу, как это решение может удовлетворить требование 4 в вопросе. Или я чего-то не хватает? –

+0

@ m-bitsnbites Вам нужны старые теги релиза из репо A, чтобы угадать, что было в репо B в то время? Это испортит вашу историю. Я не знаю, возможно ли это логически возможно, сохранив также историю ветвлений A. – Schwern

+0

@ m-bitsnbites. Я собрал иллюстрацию результирующей структуры репозитория, которая является наилучшим компромиссом IMO, но я не знаю, как это сделать. трансформировать в автоматическом режиме. – Schwern