У меня есть репозиторий, и я хотел бы отделить один из его каталогов в новое репо. This - идеальное место для начала работы, есть одно предостережение: директория, которую я хочу отделить, была переименована в какой-то момент. И если я последую за решением этой должности с новым именем каталога, то кажется, что я теряю историю перед повторным именем. Любые идеи о том, как заставить его работать в этой ситуации?Отсоединить подкаталог (который был переименован!) В новый репо
ответ
git filter-branch
может работать на диапазонах коммитов; так что мы можем сделать, это фильтровать «до» и «после» по отдельности, и использовать трансплантаты лавировать их вместе:
git branch rename $COMMIT_ID_OF_RENAME
git branch pre-rename rename~
## First filter all commits up to rename, but not rename itself
git filter-branch --subdirectory-filter $OLDNAME pre-rename
## Add a graft, so our rename rev comes after the processed pre-rename revs
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
## The first filter-branch left a refs backup directory. Move it away so the
## next filter-branch doesn't complain
mv .git/refs/original .git/refs/original0
## Now filter the rest
git filter-branch --subdirectory-filter $NEWNAME master ^pre-rename
## The graft is now baked into the branch, so we don't need it anymore
rm .git/info/grafts
Это немного сложнее, если вам нужно фильтровать несколько ветвей или меток; ветви до переименования могут быть включены в первую ветвь фильтра, а одни после должны быть включены до ^rename
во вторую ветвь фильтра.
Другой вариант - добавить фильтр индекса (или фильтр дерева) вместо этого, который проверяет обе каталоги, старые и новые, и сохраняет то, что присутствует.
Поскольку вы не предоставили тестовый репозиторий, вот быстрый здравомыслие проверка сценарий для этого сценария:
#!/bin/bash
set -u
set -e
set -x
rm -rf .git x y foo
git init
mkdir x
echo initial > x/foo
git add x/foo
git commit -m 'test commit 1'
echo tc2 >> x/foo
git commit -a -m 'test commit 2'
mv x y
git rm x/foo
git add y/foo
git commit -a -m 'test rename'
git branch rename HEAD
echo post rename >> y/foo
git commit -a -m 'test post rename'
git branch pre-rename rename~
git filter-branch --subdirectory-filter x pre-rename
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
mv .git/refs/original .git/refs/original0
git filter-branch --subdirectory-filter y master ^pre-rename
rm .git/info/grafts
git log -u
Если эта процедура не работает для вас, то есть, вероятно, будет что-то другое нечетное о вашей истории репозитория, которую вы не описали, например, о другом переименовании, скрывающемся в истории.
Мы (Матфей Flatt и я) написали программу, чтобы сделать это: https://github.com/samth/git-slice
Хм, я попробовал ваш метод с трансплантатами (что я ничего не знаю о), и это не работает для меня. После обработки один из «до» коммитов стал пустым, другие файлы были перемещены в корень репо; Я не могу понять это. Я думал раньше, используя древовидный фильтр, но не имею никакого опыта с этим; не могли бы вы уточнить, покажите мне несколько указателей? – akoprowski
Вы уверены, что перед фиксацией использовался правильный subdir? Можете ли вы опубликовать свой git-репо где-нибудь? – bdonlan
Yup, переименование было на фиксации, которая переименовала и предварительно переименовала непосредственно перед этим. Репо огромно и частично частно, поэтому я не могу его опубликовать нигде: | – akoprowski