Создайте репозиторий подмодуля из папки и сохраните его историю коммитов git

111

У меня есть веб-приложение, которое исследует другие веб-приложения определенным образом. Он содержит несколько веб-демонстраций в demosпапке, и одна из демонстраций теперь должна иметь собственный репозиторий. Я хотел бы создать отдельный репозиторий для этого демонстрационного приложения и сделать егоподпакет подмодуль из основного репозитория без потери истории коммитов.

Можно ли сохранить историю коммитов из файлов в папке репозитория и создать из него репозиторий и вместо этого использовать его как подмодуль ?

ГабЛеРу
источник
Я искал, как переместить каталог 1 из репозитория Git A в репозиторий Git B. +1 для ссылки на статью.
Четабахана
1
Дубликат? stackoverflow.com/questions/12514197/…
naught101
Да, это действительно очень похоже, решения немного отличаются, спасибо, что поделились этим
GabLeRoux

Ответы:

191

Подробное решение

См. Примечание в конце этого ответа (последний абзац) для быстрой альтернативы подмодулям git с использованием npm;)

В следующем ответе вы узнаете, как извлечь папку из репозитория и создать из нее репозиторий git, а затем включить его в качестве подмодуля вместо папки.

На основе статьи Герга Байера « Перемещение файлов из одного репозитория Git в другой с сохранением истории»

Вначале у нас есть что-то вроде этого:

<git repository A>
    someFolders
    someFiles
    someLib <-- we want this to be a new repo and a git submodule!
        some files

В указанные ниже шаги, я буду называть это someLibтак <directory 1>.

В итоге у нас будет что-то вроде этого:

<git repository A>
    someFolders
    someFiles
    @submodule --> <git repository B>

<git repository B>
    someFolders
    someFiles

Создайте новый репозиторий git из папки в другом репозитории

Шаг 1

Получите новую копию репозитория для разделения.

git clone <git repository A url>
cd <git repository A directory>

Шаг 2

Текущая папка будет новым репозиторием, поэтому удалите текущий пульт.

git remote rm origin

Шаг 3

Извлечь историю желаемой папки и зафиксировать ее

git filter-branch --subdirectory-filter <directory 1> -- --all

Теперь у вас должен быть репозиторий git с файлами из directory 1корня вашего репо со всей связанной историей фиксации.

Шаг 4

Создайте свой онлайн-репозиторий и продвигайте новый репозиторий!

git remote add origin <git repository B url>
git push

Возможно, вам потребуется установить upstreamветку для вашего первого нажатия

git push --set-upstream origin master

Чистый <git repository A>(необязательно, см. Комментарии)

Мы хотим удалить следы (файлы и историю фиксации) <git repository B>из, <git repository A>чтобы история для этой папки была только один раз.

Это основано на удалении конфиденциальных данных из github.

Перейдите в новую папку и

git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <directory 1> -r' --prune-empty --tag-name-filter cat -- --all

Замените <directory 1>папкой, которую хотите удалить. -rбудет делать это рекурсивно внутри указанного каталога :). Теперь нажмите на origin/masterс--force

git push origin master --force

Уровень босса (см. Примечание ниже)

Создать подмодуль из <git repository B>в<git repository A>

git submodule add <git repository B url>
git submodule update
git commit

Убедитесь, что все работает должным образом, и push

git push origin master

Заметка

После всего этого я понял, что в моем случае более целесообразно использовать npm для управления моими собственными зависимостями. Мы можем указать URL-адреса и версии git, см. URL-адреса git package.json как зависимости .

Если вы делаете это таким образом, хранилище вы хотите использовать в качестве требования должно быть модулем НПМ , поэтому он должен содержать package.jsonфайл , или вы получите эту ошибку: Error: ENOENT, open 'tmp.tgz-unpack/package.json'.

tldr (альтернативное решение)

Возможно, вам будет проще использовать npm и управлять зависимостями с помощью URL-адресов git :

  • Переместить папку в новый репозиторий
  • запустить npm initв обоих репозиториях
  • запустить npm install --save git://github.com/user/project.git#commit-ishтам, где вы хотите, чтобы ваши зависимости были установлены
ГабЛеРу
источник
39
Шага «Очистить <git repository A>» следует избегать. Сделав это, вы не сможете полностью восстановить / проверить более старые версии / коммиты из своей истории. Вам нужно просто git rm папку и добавить подмодуль. Таким образом, вы убедитесь, что имеете полностью рабочую копию при проверке старых коммитов.
Cybot
Разве вы не должны делать это cd someLibдо шага 2? Вы говорите: «Текущая папка будет новым репозиторием», но на самом деле это не так; новый репозиторий (подмодуль) находится внутри этой папки.
Jago
1
Подтверждаю: да, работает более чем с одним подмодулем. Большое спасибо за подробный ответ. Кроме того, не нужно было использовать npm.
Брено Инохоса,
2
Я бы добавил информацию о том, refs/original/...что создается на шаге 3.
Эмиль Бержерон
6
GitHub сделал статью о том, как добиться извлечения папки в новый репозиторий: help.github.com/articles/…
jrobichaud
9

Решение @GabLeRoux сжимает ветки и связанные с ними коммиты.

Простой способ клонировать и сохранить все эти дополнительные ветки и коммиты:

1 - Убедитесь, что у вас есть этот псевдоним git

git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t'

2 - Клонируйте пульт, вытяните все ветки, смените пульт, отфильтруйте каталог, нажмите

git clone git@github.com:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm origin
git remote add origin git@github.com:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git push --all
git push --tags
Оодавид
источник
3

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

Понимая это, я считаю, что для меня работает следующее решение:

cp .gitattributes .git/info/attributes

Копирование того, .gitattributesчто git lfs использует для отслеживания больших файлов в .git/каталог, чтобы избежать их удаления.

Когда filter-branch завершено, не забудьте вернуть, .gitattributesесли вы все еще хотите использовать git lfs для нового репозитория:

mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'
ls.
источник