Правильный способ удалить ненужные файлы с помощью git filter-branch без сбоя git rm

У меня есть проект агента SNMP, в котором вместе с ним были разработаны соответствующие файлы MIB (файлы * .smiv2), но теперь я хочу, чтобы они были в отдельном репозитории git.

Чтобы не потерять историю файлов MIB, поскольку они не запускались в том же каталоге, что и сейчас, я не мог просто использовать --subdirectory-filter filter-branch, поэтому я попробовал подход --filter-index, основанный на этот вопрос. Идея заключалась бы в том, чтобы удалить все файлы, которые не заканчиваются на .smiv2 (очевидно, на новом клоне исходного проекта, который должен быть помещен в мой новый репозиторий MIB к концу процесса).

Чтобы упростить задачу, я выбрал ls-files вместо ls-tree, поэтому вместо:

git filter-branch --prune-empty --index-filter 'git ls-tree -r --name-only \
--full-tree $GIT_COMMIT | grep -v ".smiv2$" | xargs git rm --cached \
--ignore-unmatch -r'

Я использовал это:

git filter-branch --prune-empty --index-filter 'git ls-files | \
grep -v ".smiv2$" | xargs git rm --cached --ignore-unmatch'

но любой из них не удался при первой фиксации, поскольку кажется, что git rm не было передано никаких аргументов (я полагаю, --ignore-unmatch будет работать нормально, если предоставленные аргументы не найдены, но не в том случае, если аргументы не предоставлены):

$ git filter-branch --prune-empty --index-filter 'git ls-files | \
>     grep -v ".smiv2$" | xargs git rm --cached --ignore-unmatch'
Rewrite 4cd2f1c98dbaa96bc103ae81fbd405bd1d991d9a (1/418)usage: git rm [options] [--] <file>...

    -n, --dry-run         dry run
    -q, --quiet           do not list removed files
    --cached              only remove from the index
    -f, --force           override the up-to-date check
    -r                    allow recursive removal
    --ignore-unmatch      exit with a zero status even if nothing matched

index filter failed: git ls-files | \
    grep -v ".smiv2$" | xargs git rm --cached --ignore-unmatch

Я заставил его работать, упаковывая git rm в сценарий, который возвращает успех, даже если он терпит неудачу из-за отсутствия аргументов (сохранил его в /usr/local/bin/gitrm_alt):

#!/bin/sh
git rm --cached --ignore-unmatch "$@" 
exit 0

а затем вызовите это вместо git rm:

git filter-branch --prune-empty --index-filter 'git ls-files | \
    grep -v ".smiv2$" | xargs gitrm_alt'

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


person Claudio    schedule 29.08.2012    source источник
comment
Почему бы не передать git rm --ignore-unmatched лишний фиктивный аргумент, которого никогда не было, например | xargs rm --cached --ignore-unmatched DoesNotExistInMyProject?   -  person CB Bailey    schedule 29.08.2012
comment
хе-хе .. идеальный @CharlesBailey, как я не мог этого увидеть? Разве ты не хочешь превратить это в ответ, чтобы я мог его принять? Спасибо!   -  person Claudio    schedule 29.08.2012


Ответы (4)


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

E.g.

... | xargs git rm --cached --ignore-unmatch DoesNotExistInMyProject
person CB Bailey    schedule 29.08.2012

Флаг -r | --no-run-if-empty xargs мог бы быть чище:

... | xargs --no-run-if-empty git rm --cached --ignore-unmatched

person jthill    schedule 23.04.2014

Полный ответ для использования в будущем

git filter-branch --prune-empty --index-filter 'git ls-files | \
grep -v ".smiv2$" | xargs git rm --cached --ignore-unmatch DoesNotExistInMyProject'
person jdr0dn3y    schedule 23.04.2014

Также можно использовать переключатель -I.

some command | xargs -I % rm % 
person Stewie    schedule 12.02.2015