6

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.

Community
  • 1
  • 1
Claudio
  • 2,191
  • 24
  • 49
  • Why not pass an extra dummy argument that never exists to `git rm --ignore-unmatched`, e.g. `| xargs rm --cached --ignore-unmatched DoesNotExistInMyProject`? – CB Bailey Aug 29 '12 at 14:58
  • hehe.. perfect @CharlesBailey, how couldn't I see that? Don't you want to turn that into an answer so I can accept it? Thanks! – Claudio Aug 29 '12 at 18:57

4 Answers4

8

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
jdr0dn3y
  • 413
  • 4
  • 4
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
5

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

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

jthill
  • 55,082
  • 5
  • 77
  • 137
3

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'
jdr0dn3y
  • 413
  • 4
  • 4
0

An -I switch can also be used.

some command | xargs -I % rm % 
Stewie
  • 3,103
  • 2
  • 24
  • 22