Объединение нескольких Git-репозиториев - PullRequest
203 голосов
/ 10 ноября 2008

Допустим, у меня есть установка, похожая на

phd/code/
phd/figures/
phd/thesis/

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

cd phd/code
git commit 
cd ../figures
git commit

Было бы (сейчас) приятно просто выполнить

cd phd
git commit

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

cd phd
git init
git add [[everything that's already in my other repositories]]

но это не похоже на однострочник. Есть ли в git что-нибудь, что может мне помочь?

Ответы [ 12 ]

143 голосов
/ 06 марта 2009

Вот решение, которое я дал здесь :

  1. Сначала сделайте полную резервную копию вашего каталога phd: я не хочу нести ответственность за ваши потерянные годы тяжелой работы! ; -)

    $ cp -r phd phd-backup
    
  2. Переместите содержимое phd/code в phd/code/code и исправьте историю, чтобы она выглядела так, как будто она всегда была там (используется команда git filter-branch ):

    $ cd phd/code
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s#\t#&code/#" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    
  3. То же самое для содержимого phd/figures и phd/thesis (просто замените code на figures и thesis).

    Теперь ваша структура каталогов должна выглядеть следующим образом:

    phd
      |_code
      |    |_.git
      |    |_code
      |         |_(your code...)
      |_figures
      |    |_.git
      |    |_figures
      |         |_(your figures...)
      |_thesis
           |_.git
           |_thesis
                |_(your thesis...)
    
  4. Затем создайте репозиторий git в корневом каталоге, вытяните все в него и удалите старые репозитории:

    $ cd phd
    $ git init
    
    $ git pull code
    $ rm -rf code/code
    $ rm -rf code/.git
    
    $ git pull figures --allow-unrelated-histories
    $ rm -rf figures/figures
    $ rm -rf figures/.git
    
    $ git pull thesis --allow-unrelated-histories
    $ rm -rf thesis/thesis
    $ rm -rf thesis/.git
    

    Наконец, теперь у вас должно быть то, что вы хотели:

    phd
      |_.git
      |_code
      |    |_(your code...)
      |_figures
      |    |_(your figures...)
      |_thesis
           |_(your thesis...)
    

Одной из приятных сторон этой процедуры является то, что она оставит не версионные файлы и каталоги на месте.

Надеюсь, это поможет.


Только одно предупреждение: если в вашем каталоге code уже есть подкаталог или файл code, все может пойти не так (конечно же, для figures и thesis). Если это так, просто переименуйте этот каталог или файл перед выполнением всей этой процедуры:

$ cd phd/code
$ git mv code code-repository-migration
$ git commit -m "preparing the code directory for migration"

И когда процедура будет завершена, добавьте этот последний шаг:

$ cd phd
$ git mv code/code-repository-migration code/code
$ git commit -m "final step for code directory migration"

Конечно, если в подкаталоге или файле code нет версий, просто используйте mv вместо git mv и забудьте о git commit s.

76 голосов
/ 10 ноября 2008

git-stitch-repo обработает вывод git-fast-export --all --date-order в репозиториях git, указанных в командной строке, и создаст поток, подходящий для git-fast-import, который создаст новый репозиторий, содержащий все коммиты в новом дереве коммитов, которое учитывает историю всех исходных репозиториев.

20 голосов
/ 23 апреля 2009

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

$ cd phd/code
$ mkdir code
# This won't work literally, because * would also match the new code/ subdir, but you understand what I mean:
$ git mv * code/
$ git commit -m "preparing the code directory for migration"

, а затем объединить три отдельных репозитория в одно новое, выполнив что-то вроде:

$ cd ../..
$ mkdir phd.all
$ cd phd.all
$ git init
$ git pull ../phd/code
...

Тогда вы сохраните свои истории, но продолжите с одним репо.

18 голосов
/ 10 февраля 2011

Вы можете попробовать стратегию объединения поддерево . Это позволит вам объединить репо B с репо A. Преимущество перед git-filter-branch заключается в том, что вам не нужно переписывать историю репо A (ломая суммы SHA1).

7 голосов
/ 26 июля 2010

Решение git-filter-branch работает хорошо, но учтите, что если ваше git-репо происходит из SVN-импорта, оно может завершиться с таким сообщением, как:

Rewrite 422a38a0e9d2c61098b98e6c56213ac83b7bacc2 (1/42)mv: cannot stat `/home/.../wikis/nodows/.git-rewrite/t/../index.new': No such file or directory

В этом случае вам необходимо исключить начальную ревизию из ветви фильтра - то есть изменить HEAD в конце на [SHA of 2nd revision]..HEAD - см .:

http://www.git.code -experiments.com / блог / 2010/03 / слияния-ГИТ-repositories.html

5 голосов
/ 25 ноября 2013

git-stitch-repo из Ответ Аристотеля Пагальциса работает только для репозиториев с простой линейной историей.

Ответ MiniQuark работает для всех репозиториев, но не обрабатывает теги и ветви.

Я создал программу, которая работает так же, как описывает MiniQuark, но она использует один коммит слияния (с N родителями), а также воссоздает все теги и ветви, чтобы указать на эти коммиты слияния.

См. git-merge-repos репозиторий для примеров, как его использовать.

5 голосов
/ 25 марта 2013

@ Решение MiniQuark мне очень помогло, но, к сожалению, оно не учитывает теги, которые есть в исходных репозиториях (по крайней мере, в моем случае). Ниже мое улучшение ответа @MiniQuark.

  1. Сначала создайте каталог, который будет содержать составные репо и объединенные репозитории, создайте каталог для каждого объединенного репозитория.

    $ mkdir new_phd
    $ mkdir new_phd / code
    $ mkdir new_phd / figure
    $ mkdir new_phd / диссертация

  2. Выполните извлечение каждого хранилища и извлеките все теги. (Представление инструкций только для подкаталога code)

    $ cd new_phd / code
    $ git init
    $ git pull ../../original_phd/code master
    $ git fetch ../../original_phd/code refs / tags / *: refs / tags / *

  3. (Это улучшение к пункту 2 в ответе MiniQuark) Переместите содержимое new_phd/code в new_phd/code/code и добавьте code_ префикс перед каждым тегом

    $ git filter-branch --index-filter 'git ls-files -s | sed "s- \ t \" * - & code / - "| GIT_INDEX_FILE = $ GIT_INDEX_FILE.new git update-index --index-info && mv $ GIT_INDEX_FILE.new $ GIT_INDEX_FILE '--tag-name-filter' sed" s -. * - код _ & - "'HEAD

  4. После этого будет вдвое больше тегов, чем было до выполнения filter-branch. Старые теги остаются в репо и добавляются новые теги с префиксом code_.

    $ git tag
    мойтег1
    code_mytag1

    Удалить старые теги вручную:

    $ ls .git / refs / tags / * | grep -v "/ code_" | xargs rm

    Повторите пункт 2,3,4 для других подкаталогов

  5. Теперь у нас есть структура каталогов, как в @MiniQuark anwser point 3.

  6. Выполните действия, описанные в пункте 4 приложения MiniQuark, но после выполнения извлечения и перед удалением .git dir извлеките теги:

    $ git fetch каталог refs / tags / *: refs / tags / *

    Продолжить ..

Это просто другое решение. Надеюсь, это поможет кому-то, это помогло мне:)

3 голосов
/ 10 мая 2014

На самом деле, git-stitch-repo теперь поддерживает ветки и теги, в том числе аннотированные теги (я обнаружил, что есть ошибка, о которой я сообщил, и она исправлена). Что я нашел полезным с тегами. Поскольку теги привязаны к коммитам, а некоторые решения (например, подход Эрика Ли) не справляются с тегами. Вы пытаетесь создать ветку из импортированного тега, и она отменяет любые мерзкие слияния / перемещения и отправляет вас обратно, как если бы консолидированный репозиторий был почти идентичен репозиторию, из которого пришел тег. Кроме того, существуют проблемы, если вы используете один и тот же тег в нескольких репозиториях, которые вы «объединили / объединили». Например, если у вас есть репозиторий A ad B, оба имеют тег rel_1.0. Вы объединяете репо A и репо B в репо AB. Поскольку теги rel_1.0 находятся на двух разных коммитах (один для A и один для B), какой тег будет виден в AB? Либо тег из импортированного репо A, либо из импортированного репо B, но не оба.

git-stitch-repo помогает решить эту проблему путем создания тегов rel_1.0-A и rel_1.0-B. Возможно, вы не сможете извлечь тег rel_1.0 и ожидать обоих, но по крайней мере вы можете увидеть оба, и теоретически вы можете объединить их в общую локальную ветвь, а затем создать тег rel_1.0 в этой объединенной ветке (при условии, что вы объединять, а не изменять исходный код). Лучше работать с ветками, так как вы можете объединять как ветки из каждого репо в локальные ветки. (dev-a и dev-b могут быть объединены в локальную ветку dev, которая затем может быть перенесена в источник).

3 голосов
/ 02 июня 2011

Я создал инструмент, который выполняет эту задачу. Используемый метод аналогичен (внутренне создает некоторые вещи, такие как --filter-branch), но более дружественен. Является ли GPL 2.0

http://github.com/geppo12/GitCombineRepo

2 голосов
/ 10 ноября 2008

Последовательность, которую вы предложили

git init
git add *
git commit -a -m "import everything"

будет работать, но вы потеряете историю коммитов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...