Извлечь git подкаталог, сохраняя историю с переименованиями

Я разбиваю большое исходное дерево на два отдельных компонента и общий подмодуль. Чтобы подготовиться к этому расколу, я сначала перевел общий материал в один "общий" каталог, обновил все ссылки и совершил коммит. Все идет нормально. Теперь я хотел бы извлечь этот каталог в подмодуль.

Обычно я делаю это с помощью

git filter-branch --subdirectory-filter

Но в этом случае вся интересная история произошла за пределами этого подкаталога, поэтому история теряется.

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

Есть ли способ сохранить поведение ветки фильтра при сохранении истории отдельных файлов?

Ответ 1

Не совсем. --subdirectory-filter - это особый случай, поскольку он существенно модифицирует содержание деревьев (поскольку он перемещает объекты на один или несколько уровней вложенности каталогов).

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

Помните, что filter-branch полностью переписывает вашу историю - вывод представляет собой совершенно новый набор коммитов, и нет никаких "связей" со старыми коммитами, поэтому любая дополнительная информация должна быть выражена как часть новые коммиты.

Ответ 2

Вот как я просто решил аналогичную проблему. Я начал проект в квази-частном репозитории "misc", переименовал некоторые файлы, а затем я захотел загрузить проект в GitHub по адресу https://github.com/kragen/aikidraw.

$ git clone misc aikidraw
$ cat > aikidraw-wanted
aikidraw.js
aikidraw.html
caposketchra.html
caposketchra.js
jquery-1.2.6.js
^D
$ cd aikidraw
$ git filter-branch --tree-filter 'bash -c "comm -23 <(/bin/ls | sort) <(sort ~/devel/aikidraw-wanted) | xargs rm -rf"' HEAD

Кажется, что до сих пор все было в порядке, кроме того, что они не удаляли dotfiles (например, .git, good и .gitignore, bad), но, по-видимому, моя версия Git (1.6.0.4) не имеет git filter-branch --prune-empty. Итак, теперь я клонирую новое меньшее репо (чтобы ускорить его копирование по сети) и скопируйте репо на другую машину, на которой Git 1.7.2.5:

$ time git clone aikidraw aikidraw-smaller
$ du -sh aikidraw/.git aikidraw-smaller/.git
8.6M    aikidraw/.git
1.2M    aikidraw-smaller/.git

$ time rsync -Pav aikidraw-smaller panacea.canonical.org:devel/aikidraw/
real    1m23.251s

И затем на panacea.canonical.org:

$ cd ~/devel/aikidraw/aikidraw-smaller  # Oops. I hate rsync sometimes.
$ git checkout  # otherwise I get "Cannot rewrite branch(es) with a dirty working directory."
$ git filter-branch --prune-empty HEAD
$ cd ../..
$ mv aikidraw i-hate-rsync
$ mv i-hate-rsync/aikidraw-smaller/ aikidraw

Затем вернитесь на мой нетбук:

$ mv aikidraw aikidraw-big
$ git clone panacea.canonical.org:devel/aikidraw
$ du -sh aikidraw/.git
268K    aikidraw/.git

Теперь, если вы делали это с двумя каталогами вместо пяти файлов, вы могли бы в этот момент переименовать все внутри оставшегося подкаталога в корень репозитория, используя git mv. В моем случае я уже переименовал.

$ git remote add github [email protected]:kragen/aikidraw.git
$ git push github master

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