Объединить git-репозиторий в подкаталог

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

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

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

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

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

РЕДАКТИРОВАТЬ 2: В надежде прояснить ситуацию я даю точные команды, которые я использовал со стратегией поддерева git, что приводит к очевидной потере истории файлов удаленного репозитория. Пусть A будет git-репо, в котором я сейчас работаю, а B - git-репо, которое я хотел бы включить в A в качестве его подкаталога. Было сделано следующее:

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 /to /put /B /in». Их история файлов, как и в B, потеряна.

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

git remote add -f B <url-of-B>
git checkout -b B_branch B/master  # make a local branch following B's 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.

git
68 голосов | спросил christosc 21 J0000006Europe/Moscow 2011, 17:41:12

6 ответов


0

После получения более полного объяснения происходящего я думаю, что понимаю его, и в любом случае в нижней части у меня есть обходной путь. В частности, я считаю, что обнаружение переименования обманывается слиянием поддерева с --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. Это хорошо, но не очень, так как не удается связать историю предварительного слияния с последующим слиянием.

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

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

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

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
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 с переименованием, и я боюсь, что это не пройдет гладко. Но если б уходит, вы выиграете.

ответил Seth Robertson 22 J0000006Europe/Moscow 2011, 19:01:41
0

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

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

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

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

ответил kynan 21 stEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 21 Sep 2015 00:32:00 +0300 2015, 00:32:00
0

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

ответил Adam Dymitruk 22 J0000006Europe/Moscow 2011, 05:05:12
0

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

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

ответил Abizern 21 J0000006Europe/Moscow 2011, 17:46:48
0

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

# 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, поэтому я не могу комментировать, является ли это особенно хорошим решением или у него есть предостережения, но пока все выглядит хорошо.

ответил 0__ 22 SatEurope/Moscow2012-12-22T18:11:03+04:00Europe/Moscow12bEurope/MoscowSat, 22 Dec 2012 18:11:03 +0400 2012, 18:11:03
0

Я хотел

  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
ответил hfs 23 J000000Monday18 2018, 12:52:56

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132