Git filter branch with index filter not working and remove directories as expected

Git repo foo structure in main branch

foo/refs/a.txt foo/bar/refs/b.txt 

In other branches refs/ may be in many other places

goal

To remove all instances of refs directories (and their contents) from Git (history) Environment: Windows 7 with Git Bash

Removing refs (Git is not involved, tried it just to make sure that it works on its own)

 find . -name refs -depth -exec rm -rf {} \; 

Success, all refs/ and their contents are deleted (if I do not use -depth , find will report an error that dirs does not exist, even if they were deleted correctly).

Removing Git Links

 git filter-branch --index-filter \ 'find . -name refs -depth -exec git rm -rf --cached --ignore-unmatch {} \;' \ --prune-empty --tag-name-filter cat -- --all 

Removing directory refs from Git by rewriting the Git history

As you can see in the figure (think temp/a as temp/foo ), the command starts and overwrites all commits, but does not delete refs/ , so the find output does not return to filter-branch --index-filter as expected.

Things like this seem to work for others.
What am I missing?

PS. Yes, I read hundreds of posts, articles, etc. Hours and hours about it, but it still doesn't work for me.

+6
source share
1 answer

Update

Although my old answer seems to have helped the original poster partially solve its problem, it seems like I really can't be right if --index-filter only works with Git commands, because in the documentation for git filter-branch , it gives an example of a filter used with non-Git shell commands, in addition to Git commands:

 git filter-branch --index-filter \ 'git ls-files -s | sed "s-\t\"*-&newsubdir/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD 

It is possible that if you intend to use Git commands with --index-filter , then they should work with the repository index, as shown in the above example from the documentation.

So, in principle, I'm not sure why the original index filter of the original poster did not work, but maybe he was trying to access the part of the repository that the index filter does not allow, or that any non-Git command that he used did not actually change index.

Also, as I point out in the comments ,

Git actually stores all its links in .git/refs/ in non-bare repositories, in the root copy of the working copy ... so the find . -name refs -depth find . -name refs -depth will also dig these directories.

So maybe something went wrong during the filter branch?

Old answer

I think the problem may be that you are trying to use shell tools without Git with the filter-branch --index-filter option instead of the --tree-filter option:

 git filter-branch --index-filter \ 'find . -name refs -depth -exec git rm -rf --cached --ignore-unmatch {} \;' \ --prune-empty --tag-name-filter cat -- --all 

Unlike --tree-filter , which checks the new working directory for each commit and runs the passed script shell on it, --index-filter only works with the index file of the Git repository itself (it does not check the working copy for work) ... therefore, only Git commands will work with it.

You are probably lucky with this because it passed the Git commands to filter-branch --index-filter :

 git filter-branch --index-filter \ 'git rm -f --cached --ignore-unmatch *.zip && \ git rm -rf --cached --ignore-unmatch refs' \ --prune-empty --tag-name-filter cat -- --all 

This is the documentation for git -filter-branch (1) --tree-filter :

This is a filter for overwriting a tree and its contents. The argument is evaluated in a shell with a working directory installed in the root of the tree being cut.

and this is the documentation for --index-filter (my selection):

This is a filter for rewriting an index. It looks like a tree filter, but does not check the tree , which makes it much faster. Often used with git rm --cached --ignore-unmatch ... , see EXAMPLES below. For hairy cases see git -update-index (1) .

+4
source

All Articles