Подтвердить что ты не робот

Как удалить все файлы в репозитории Git, которые не находятся в рабочем каталоге?

Я в процессе разделения старого набора приложений, который изначально находился в одном репозитории Subversion.

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

В идеале то, что я хотел бы сделать, - это пройти через весь репозиторий и удалить любые файлы или папки, отсутствующие в рабочем каталоге, а также любую связанную с ними историю. Это оставило бы меня с содержанием HEAD и историей фиксаций, затрагивающих эти файлы. Однако я не сталкивался с этим способом (сиротство HEAD не помогает, поскольку оно не сохраняет историю).

Возможно ли это? Я знаю, как удалить один файл или папку из всей истории через git -filter-branch, но слишком много файлов и папок для этого - практический подход... если нет способа фильтрации на всех файлах, в HEAD?

4b9b3361

Ответ 1

Здесь вы можете использовать git filter-branch, чтобы избавиться от всех файлов, которые вам не нужны:

  • Получить список имен файлов, которые вы не хотите отображать в истории, как старые имена, так и новые имена в случае переименований. Например, поместите их в файл с именем toberemoved.txt

  • Запустите git filter-branch следующим образом:

    $ git filter-branch --tree-filter "rm -f `cat toberemoved.txt`" branch1 branch2 ...
    

Здесь соответствующая справочная страница из git filter-branch:

   --tree-filter <command>
       This is the filter for rewriting the tree and its contents. The
       argument is evaluated in shell with the working directory set to
       the root of the checked out tree. The new tree is then used as-is
       (new files are auto-added, disappeared files are auto-removed -
       neither .gitignore files nor any other ignore rules HAVE ANY
       EFFECT!).

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

Update:

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

$ git log --raw |awk '/^:/ { if (! printed[$6]) { print $6; printed[$6] = 1 }}'|while read f;do if [ ! -f $f ]; then echo Deleted: $f;fi;done

Это $6 - это имя файла, который был затронут в фиксации, показанном в режиме -raw журнала.

См. параметр -diff-filter для git журнала, если вы хотите узнать, что произошло ([D] eleted, [R] enamed, [M] официровано и т.д.) для каждого файла для каждой фиксации.

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

Ответ 2

Я сделал это несколько раз - извлечение фиксирует для одного файла и создает из них новый репозиторий. Это примерно так:

$ c=10; for commit in $(git log --format=%h -- path/to/file|tac); do
      c=$((c+1))
      git format-patch -1 --stdout $commit > $c.patch
  done

Это создает файлы исправлений 11.patch, 12.patch и т.д. Затем я редактирую эти патчи (используя vim или perl в зависимости от того, что лучше всего подходит для задания), удаляя целые hunks для файлов, которые мне не интересны, и, возможно, исправляет имена также в случае переименований в заголовке diff hunk.

Я бы использовал git am в патчах в новом репозитории git. Если что-то не срабатывает правильно, я запускаю новый репозиторий git и снова редактирую патчи и повторяю git am.

Причина, по которой я начинаю считать с 10, состоит в том, что я ленив, чтобы добавить ведущую 0 к последовательности патчей и для совершения более 99 я начинаю только с 99.

Ответ 3

Помогает во втором ответе: "Возможно, другие могут прослушивать, как узнать предыдущее имя отслеживаемого файла в случае переименований".

Это вернет файлы в вашем проекте и файлы, из которых они были переименованы.

for file in `git ls-files`; do git log --follow --name-only --pretty=format: $file | sort -n -b | uniq | sed '/^\s*$/d'; done

Вы можете использовать их для исключения из списка.

Все решение:

for file in `git ls-files`; do git log --follow --name-only --pretty=format: $file | sort -n -b | uniq | sed '/^\s*$/d'; done > current.txt

git log --raw |awk '/^:/ { if (! printed[$6]) { print $6; printed[$6] = 1 }}'|while read f;do if [ ! -f $f ]; then echo $f;fi;done | sort > hist.txt

diff --new-line-format="" --unchanged-line-format="" hist.txt current.txt > for_remove.txt