Git: отделить директорию в отдельный репозиторий

Рубрика: IT. Сети. Связь
Метки: |
Суббота, 15 ноября 2014 г.
Просмотров: 6228
Подписаться на комментарии по RSS

Есть такая распространенная задача в Git — выделение некоторой (суб)директории в отдельный проект, т.е. в новый репозиторий.

При этом вы можете оставить папку в старом проекте, добавить её в .gitignore и работать с ней как с отдельным репозиторием (альтернатива git submodules), либо полностью удалить её из старого проекта.

В последних версиях Git это тривиальные задачи. Я опишу первый вариант.

 

1. Заходим в директорию, находящуюся под версионным контролем и выполняем команду:

git subtree split -P <path-to-folder> -b <name-of-new-branch>

Этим мы отделяем нужную директорию со всей историей её изменений в новую ветку <name-of-new-branch> . Обратите внимание, что <path-to-folder> не должен начинаться или оканчиваться какими-либо специальными символами вроде «/» или «.».

К примеру если наш репозиторий лежит в «D:\projects\my-project» и мы желаем отделить папку «D:\projects\my-project\modules\my-module», то пишем так:

cd D://projects/my-project
git subtree split -P modules/my-module -b my-module-branch

Новая ветка будет «висеть» отдельно, взгляните на пример реального проекта:

 

 

2. Создадим новый репозиторий

Поскольку он у нас будет располагаться всё в той же папке, заходим туда, удаляем все файлы (rm -rf ./* ) и инициализируем пустой репозиторий.

git init

Заполняем его содержимым нашей ветки:

git pull <path-to-old-repo> <name-of-new-branch>
<path-to-old-repo> — это просто путь на локальной машине. Например, если мы сидим в папке «D:\projects\my-project\modules\my-module», то можно написать «../../».

 

3. Старый репозиторий всё еще следит за изменениями в нашей папке. Отключим ревизионный контроль:

git rm -r --cached <path-to-folder>

Например, если вы находитесь в «D:\projects\my-project», то <path-to-folder> будет «modules/my-module». Добавьте «modules/my-module» также и в .gitignore. Этим мы удалим папку из-под ревизионного контроля старого репозитория, но физически оставим файлы на месте.

twitter.com facebook.com vkontakte.ru mail.ru friendfeed.com pikabu.ru blogger.com liveinternet.ru livejournal.ru memori.ru google.com bobrdobr.ru yandex.ru del.icio.us

Комментариев: 9

  1. 2014-11-25 в 13:43:11 | Максим

    Такой вопрос: я не хочу указывать десятки (а может и сотни) каталогов за которыми _не должен_ следить ГИТ, я хочу указать только те каталоги за которыми он должен следить. =) Возможно ли так?

  2. 2014-11-26 в 16:19:37 | Chewits
    ]]>]]>

    Максим, возможно все :)

    пропишите в .gitignore:

    /*
    !/foo
    !/bar

    Первая строчка добавляет в игнор вообще всё,

    а вторая и третья разрешают к индексации только нужные вам каталоги (foo и bar)

  3. 2014-11-28 в 01:19:15 | Максим

    Спасибо!

  4. 2014-12-10 в 19:53:41 | Василий

    Спасибо. Доходчиво весьма.

    Обрисую ситуацию.

    Дано: Есть репозиторий, обзовем core/. В нём была папка, обзовем core/plugins/. Всё это - master

    Задача: выгрузить историю коммитов относящихся к папке core/plugins/ в отдельный репос, удалить все упоминания о изменениях в core/plugins/ из master и настроить core/plugins/ на удаленный приватный репозиторий.

    Описанное выше решает эту задачу? Спасибо за ответ.

  5. 2014-12-11 в 12:28:25 | Chewits
    ]]>]]>

    Василий,

    описанное выше решает вашу задачу за исключением удаления истории коммитов для папки core/plugins/ из старого репозитория..

    Чтобы удалить папку вместе с её историей изменения из репозитория, используйте filter-branch. Я это не тестировал, так что создайте на всякий пожарный новую ветку от текущего master, а затем выполните:

    > git filter-branch --tree-filter 'rm --force -r plugins' HEAD

    Это должно удалить информацию о папке plugins из каждого коммита текущей ветки.

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

    Больше инфы по filter-branch ищите здесь (пока на английском, но процесс перевода идет):

    http://git-scm.com/book/ru/v2/Инструменты-Git-Rewriting-History#The-Nuclear-Option:-filter-branch

  6. 2014-12-11 в 13:38:11 | Василий

    ясно. спасибо )

  7. 2015-01-28 в 13:10:28 | Андрей

    а как отделить файл (с полной историей изменений) в отдельный репозиторий?

    Пробовал в --prefix указать имя файла, но получил сообщения:

    1/     42 (0)2/     42 (1)assertion failed:  [ blob = tree -o blob = commit ]
    3/     42 (2)assertion failed:  [ blob = tree -o blob = commit ]
    4/     42 (3)assertion failed:  [ blob = tree -o blob = commit ]
  8. 2015-01-28 в 13:25:08 | Андрей

    и в конце строчка:

    No new revisions were found
  9. 2016-03-20 в 12:13:31 | Chewits
    ]]>]]>

    Андрей, репозиторий - это всегда директория, в которой располагаются ваши файлы + каталог .git. Не может быть репозитория, "состоящего из одного файла". Этот файл всегда лежит в какой-то папке, за которой и следит Git.

    Т.е. в вашем случае следует отделить всю папку с нужным вам файлом (все как описано в статье), а дальше "почистить" историю нового репозитория, при необходимости - если вы хотите чтобы там осталась история только для вашего единственного файла. Для этого используйте git filter-branch:

    https://goo.gl/fMb5Bt

Оставьте комментарий!

Не регистрировать/аноним

Используйте нормальные имена.

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



(обязательно)