Подтвердить что ты не робот

Объединить хранилище git в подкаталоге

Я хотел бы объединить удаленный репозиторий git в моем рабочем репозитории git в качестве его подкаталога. Я хотел бы, чтобы результирующий репозиторий содержал объединенную историю двух репозиториев, а также то, что каждый файл объединенного репозитория сохраняет свою историю, как в удаленном репозитории. Я попытался использовать стратегию поддерева, как указано в Как использовать стратегию слияния поддерева, но после выполнения этой процедуры, хотя результирующий репозиторий содержит действительно объединенные история двух репозиториев, отдельные файлы, поступающие с удаленного, не сохранили свою историю (` git log 'на любом из них просто показывает сообщение "Объединенная ветка..." ).

Также я не хочу использовать подмодули, потому что я не хочу, чтобы два комбинированных репозитория git были отделены больше.

Можно ли объединить удаленный репозиторий git в другой как подкаталог с отдельными файлами, поступающими из удаленного хранилища, сохраняющим их историю?

Большое спасибо за любую помощь.

EDIT: В настоящее время я пытаюсь найти решение, использующее ветвь git filter-branch для перезаписи истории слияния в репозитории. Кажется, он работает, но мне нужно проверить его еще немного. Я вернусь, чтобы сообщить о моих выводах.

ИЗМЕНИТЬ 2: В надежде, что я сделаю все более ясным, я даю точные команды, которые я использовал с стратегией поддерева git, что приводит к очевидной потере истории файлов удаленного репозитория. Пусть A - это git repo, в котором я сейчас работаю, и B git repo, который я хотел бы включить в в качестве его подкаталога. Он сделал следующее:

git remote add -f B <url-of-B>
git merge -s ours --no-commit B/master
git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master
git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in."

После этих команд и перехода в каталог subdir/Iwant/to/put/B/in, я вижу все файлы B, но git log на любом из них отображается только сообщение фиксации "Объединить B как подкаталог в subdir/Iwant/к/ставить/B/в". Их история файлов, как и в B, теряется.

Что, кажется, работает (поскольку я новичок в git, я могу ошибаться):

git remote add -f B <url-of-B>
git checkout -b B_branch B/master  # make a local branch following B master
git filter-branch --index-filter \ 
   'git ls-files -s | sed "s-\t\"*-&subdir/Iwant/to/put/B/in/-" |
        GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD 
git checkout master
git merge B_branch

Вышеприведенная команда для ветвления фильтра взята из git help filter-branch, в которой я только изменил путь subdir.

4b9b3361

Ответ 1

Получив более полное объяснение того, что происходит, я думаю, что понимаю, и в любом случае внизу у меня есть обходной путь. В частности, я считаю, что обнаружение переименования обманывается слиянием поддерева с --prefix. Вот мой тестовый пример:

mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA
cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB
cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
git read-tree --prefix=bdir -u B/master
git commit -m "subtree merge B into bdir"
cd bdir
echo BBB>>B
git commit -a -m BBB

Мы создаем директории git a и b с несколькими коммитами каждый. Мы выполняем слияние поддерева, а затем делаем окончательный коммит в новом поддереве.

Запуск gitk (в z/a) показывает, что история действительно появляется, мы можем видеть это. Запуск git log показывает, что история действительно появляется. Однако при поиске конкретного файла возникает проблема: git log bdir/B

Ну, у нас есть трюк. Мы можем посмотреть историю переименования определенного файла, используя --follow. git log --follow -- B Это хорошо, но не очень, так как не удается связать историю pre -M erge с постом -M erge.

Я пытался играть с -M и -C, но не смог заставить его следовать одному конкретному файлу.

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

Сначала создайте репозиторий "А" и сделайте несколько коммитов:

mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA

Во-вторых, создайте репозиторий "B" и сделайте несколько коммитов:

cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB

И хитрость в том, чтобы заставить это работать: заставить Git распознавать переименование, создав подкаталог и переместив в него содержимое.

mkdir bdir
git mv B bdir
git commit -a -m bdir-rename

Вернитесь в репозиторий "A", получите и объедините содержимое "B":

cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
# According to Alex Brown and pjvandehaar, newer versions of git need --allow-unrelated-histories
# git merge -s ours --allow-unrelated-histories --no-commit B/master
git read-tree --prefix= -u B/master
git commit -m "subtree merge B into bdir"

Чтобы показать, что они теперь объединены:

cd bdir
echo BBB>>B
git commit -a -m BBB

Чтобы доказать, полная история сохраняется в связной цепочке:

git log --follow B

После этого мы получаем историю, но проблема в том, что если вы на самом деле сохраняете старый репозиторий "b" и время от времени сливаетесь с ним (скажем, на самом деле это репо с отдельным сторонним репо), то у вас проблемы с этим третьим лицом не сделал бы переименование. Вы должны попытаться объединить новые изменения в вашей версии b с переименованием, и я боюсь, что это не пройдет гладко. Но если б уходит, вы выиграете.

Ответ 2

git-subtree - это script, предназначенный именно для этого случая слияния нескольких репозиториев в один, сохраняя историю (и/или разбивая историю поддеревьев, хотя это, по-видимому, не имеет отношения к этому вопросу). Он распространяется как часть дерева git начиная с версии 1.7.11.

Чтобы объединить репозиторий <repo> в редакции <rev> в качестве подкаталога <prefix>, используйте git subtree add следующим образом:

git subtree add -P <prefix> <repo> <rev>

git -subtree реализует стратегию слияния поддерева более удобным образом.

Ответ 3

Если вы действительно хотите сшить вещи вместе, найдите прививку. Вы также должны использовать git rebase --preserve-merges --onto. Существует также возможность сохранить дату автора для информации об участниках.

Ответ 4

я хотел

  1. вести линейную историю без явного слияния и
  2. сделать так, чтобы файлы объединенного хранилища всегда существовали в подкаталоге, а в качестве побочного эффекта заставить git log -- file работать без --follow.

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

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

git checkout -b tmp_subdir

Затем используйте git filter-branch как описано в разделе Как переписать историю, чтобы все файлы, кроме уже перемещенных, находились в подкаталоге? :

git filter-branch --prune-empty --tree-filter '
if [ ! -e foo/bar ]; then
    mkdir -p foo/bar
    git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files foo/bar
fi'

Шаг 2: Переключитесь на целевой репозиторий. Добавьте исходный репозиторий как удаленный в целевой репозиторий и извлеките его содержимое.

git remote add sourcerepo .../path/to/sourcerepo
git fetch sourcerepo

Шаг 3: Используйте merge --onto чтобы добавить коммиты переписанного исходного репозитория поверх целевого репозитория.

git rebase --preserve-merges --onto master --root sourcerepo/tmp_subdir

Вы можете проверить журнал, чтобы увидеть, что это действительно дает вам то, что вы хотели.

git log --stat

Шаг 4: После ребазирования вы находитесь в состоянии "отсоединенная ГОЛОВА". Вы можете быстро перенести мастера на новую голову.

git checkout -b tmp_merged
git checkout master
git merge tmp_merged
git branch -d tmp_merged

Шаг 5: Наконец некоторая очистка: Удалите временный пульт.

git remote rm sourcerepo

Ответ 5

Вы пытались добавить дополнительный репозиторий в качестве подмодуля git? Он не объединит историю с содержащим репозиторием, на самом деле это будет независимый репозиторий.

Я упоминаю об этом, потому что вы этого не сделали.

Ответ 6

Я нашел для меня следующее решение. Сначала я перехожу в проект B, создаю новую ветку, в которой уже все файлы будут перемещены в новый подкаталог. Затем я переношу эту новую ветвь в начало. Затем я перехожу к проекту A, добавляю и извлекаю удаленный элемент B, затем проверяю перемещенную ветку, возвращаюсь в мастер и сжимаю:

# in local copy of project B
git checkout -b prepare_move
mkdir subdir
git mv <files_to_move> subdir/
git commit -m 'move files to subdir'
git push origin prepare_move

# in local copy of project A
git remote add -f B_origin <remote-url>
git checkout -b from_B B_origin/prepare_move
git checkout master
git merge from_B

Если я перейду в подкаталог subdir, я могу использовать git log --follow и все еще иметь историю.

Я не эксперт git, поэтому я не могу прокомментировать, является ли это особенно хорошим решением или если он имеет оговорки, но пока все кажется прекрасным.