Как разделить репозиторий мерзавца при сохранении подкаталогов?

То, что я хочу, подобно этому вопросу. Однако я хочу каталог, который разделяется на отдельный repo, чтобы остаться подкаталогом в этом repo:

У меня есть это:

foo/
  .git/
  bar/
  baz/
  qux/

И я хочу разделить его на два абсолютно независимых репозитория:

foo/
  .git/
  bar/
  baz/

quux/
  .git/
  qux/  # Note: still a subdirectory

Как сделать это в мерзавце?

Я мог использовать метод из этого ответа, если существует некоторый способ переместить содержание всего нового repo в подкаталог на протяжении всей истории.

20
задан Community 23 May 2017 в 12:34
поделиться

1 ответ

Вы действительно могли бы использовать фильтр подкаталога, за которым следует фильтр индекса, чтобы поместить содержимое обратно в подкаталог, но зачем это делать, если можно просто использовать фильтр индекса сам по себе?

Вот пример из man-страницы:

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

Я ожидаю, что, вероятно, есть более элегантный способ; если у кого-то есть что-то, пожалуйста, предложите это!

Несколько замечаний по этой команде:

  • filter-branch внутренне устанавливает GIT_COMMIT в SHA1 текущего коммита
  • Я не ожидал, что --full-tree понадобится, но, видимо, filter-branch запускает index-filter из каталога .git-rewrite/t, а не с верхнего уровня репозитория.
  • grep - это, вероятно, излишество, но я не думаю, что это проблема скорости.
  • --all применяет это ко всем репо; я полагаю, вам это действительно нужно. (опции -- отделяют его от опций filter-branch)
  • -z и -0 указывают ls-tree, grep и xargs использовать завершение NUL для обработки пробелов в именах файлов.

Редактирование, гораздо позже: Томас предложил способ удаления теперь уже пустых коммитов, но он уже устарел. Посмотрите историю правок, если у вас старая версия git'а, но в современном git'е всё, что вам нужно сделать, это добавить эту опцию:

--prune-empty

Это удалит все коммиты, пустые после применения индексного фильтра.

19
ответ дан 30 November 2019 в 00:51
поделиться
Другие вопросы по тегам:

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