Вы действительно можете использовать фильтр подкаталогов, за которым следует индексный фильтр, чтобы вернуть содержимое в подкаталог, но зачем беспокоиться, когда вы можете просто использовать фильтр индекса самостоятельно?
Вот пример со страницы человека:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
Это просто удаляет одно имя файла; то, что вы хотите сделать, это удалить все, кроме заданного подкаталога. Если вы хотите быть осторожным, вы можете явно перечислить каждый путь, чтобы удалить, но если вы хотите просто пойти олл-ин, вы можете просто сделать что-то вроде этого:
git filter-branch --index-filter 'git ls-tree -z --name-only --full-tree $GIT_COMMIT | grep -zv "^directory-to-keep$" | xargs -0 git rm --cached -r' -- --all
Я ожидаю, что, вероятно, более элегантный способ ; если у кого-то есть что-нибудь, предложите это!
Несколько замечаний по этой команде:
- фильтр-ветвь внутренне устанавливает GIT_COMMIT тока фиксации sha1
- Я не ожидал бы
--full-tree
быть необходимыми, но, видимо, фильтр-отрасль работает индекс -фильтр из каталога .git-rewrite/t
вместо верхнего уровня репо.
- grep, вероятно, перебор, но я не думаю, что это проблема скорости.
--all
применяет это ко всем реф. Я полагаю, вы действительно этого хотите. (--
отделяет его от опций фильтрации)
-z
и -0
сообщают ls-tree, grep и xargs, чтобы использовать завершение NUL для обработки пробелов в именах файлов.
Редактировать, намного позже: Томас полезным образом предложил способ удалить теперь пустые коммиты, но теперь он устарел. Посмотрите на истории изменений, если у вас есть старая версия мерзавца, но с современным мерзавцем, все, что вам нужно сделать, это липкость на этом варианте:
--prune-empty
Это будет удалить все коммиты, которые пусты после применение индексного фильтра.
Помимо вложенных одинарных кавычек (что я взял на себя смелость заменить), это работало почти идеально. Единственная проблема заключалась в том, что пустые записи фиксируют, что в журнале остаются несуществующие каталоги. Я удалил их с помощью 'git filter-branch -f -commit-filter ', если [z $ 1 = z \' git rev-parse $ 3^{tree} \ ']; затем skip_commit "$ @"; else git commit-tree "$ @"; fi '"$ @" ', который я нашел по адресу http://github.com/jwiegley/git-scripts/blob/master/git-remove-empty-commits – Thomas
@Thomas: Спасибо, что исправил мою неосторожную ошибку! Кроме того, вы должны иметь возможность использовать фильтр фиксации в той же команде, что и фильтр индекса. Фильтры запускаются в порядке, указанном в документации; commit-фильтр, естественно, после фильтров, которые изменяют содержимое фиксации. Вероятно, вы также захотите использовать '--remap-to-ancestor', что приведет к тому, что refs, указывающие на пропущенные коммиты, будут перемещены в ближайший предк, а не исключать их. – Cascabel
@Jefromi: аргумент 'index-filter' должен быть более легко выражен как' git rm -r -f --cached --ignore-unmatch $ (ls! (Directory-to-keep)) ', см. Мои ответы http : //stackoverflow.com/a/8079852/396967 и http://stackoverflow.com/a/7849648/396967 – kynan