Proper way to remove unwanted files with git filter-branch without git rm failing

StackOverflow https://stackoverflow.com/questions/12179611

  •  29-06-2021
  •  | 
  •  

سؤال

I have a project of an SNMP agent where the related MIB files (*.smiv2 files) were developed along with it, but now I want them in a separate git repository.

In order not to lose any of the MIB files history, since they didn't start in the same directory they are now, I couldn't just use --subdirectory-filter filter-branch, so I tried the --filter-index approach, based on this question. The idea would be to remove every file which doesn't end with .smiv2 (obviously on a fresh clone of the original project, which shall be pushed to my new MIBs repo by the end of the process).

To make it simpler, I chose using ls-files over ls-tree, so instead of:

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'

I used this:

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

but any of these failed in the first commit, since it appears git rm was fed no arguments at all (I suppose --ignore-unmatch will work fine if the supplied arguments are not found, but not in the case no arguments are supplied):

$ 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

I got it working wrapping git rm in a script which returns success even when it fails due to lack of arguments (saved it in /usr/local/bin/gitrm_alt):

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

and then calling that instead of git rm:

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

but I found that extremely ugly and clunky, so I'd like to ask if there's a more direct/proper way to do this.

هل كانت مفيدة؟

المحلول

The simplest solution would be to add a dummy argument to git rm so that it always has at least one file parameter.

E.g.

... | xargs git rm --cached --ignore-unmatch DoesNotExistInMyProject

نصائح أخرى

xargs's -r|--no-run-if-empty flag might be cleaner:

... | xargs--no-run-if-emptygit rm --cached --ignore-unmatched

Full Answer, for future reference

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

An -I switch can also be used.

some command | xargs -I % rm % 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top