Gabriel
Gabriel

Reputation: 9432

filter-branch --tree-filter with .gitignore

I am out of luck and don't know why git keeps adding the files to the index in my filter-branch workflow.

filterBranch.sh:

initDir="$1"
find . \( -name "*.gitignore" -or -name "*.gitkeep" -or -name "*.gitattributes" \) -exec rm -rf {} \; &>/dev/null # remove all git ignore stuff

cp -fR "$initDir"/* ./ && # Populate directory with initDir (new .gitignore)
    git rm --cached -qrf . && # Remove all files from index.
    git clean -fdqX || exit 1 # Clean all untracked files...

if [ "$(ls -1A "./storage" | wc -l)" != "1" ]; then
    echo "storage contains still more files....??"
    exit 1
fi

which I use in

git filter-branch --tree-filter "bash filterBranch.sh /tmp/iniDir" --prune-empty -- --all

I checked the added/overwritten $initDir/storage/.gitignore:

*
!.gitignore

which should remove all files in ./storage except .gitignore. However somehow git does not remove subfolder or files in ./storage and the history gets not cleaned resulting in exit 1 above...

What is wrong here?

Upvotes: 0

Views: 206

Answers (1)

torek
torek

Reputation: 488213

The tree filter never uses your .gitignore at all. If you want your .gitignore obeyed, do not use the tree filter; if you want to use the tree filter, make sure every invocation leaves exactly the set of files you'd like behind, in the temporary tree that the filter is invoked upon.

(The filtering command you've written seems to be aimed more at an index filter, which would be much faster. But note that an index filter does not have a work-tree to work with: it must do all of its work within Git's index.)

Note that the tree filter is incredibly slow, since it works by having Git literally check out every commit into a temporary directory (not your normal work-tree), then running the tree filter in that temporary directory. Whatever files remain after the tree filter exits, those are the files that go in the new commit. If there is a .gitignore file in that directory, that files' content goes into the new commit, but its content is itself ignored: all other files that are in that temporary directory also go into the new commit. Then the temporary directory is destroyed, and a new temporary directory is created for the next commit to be copied.

(Remember, git filter-branch works by copying every original commit to a new-and-improved one, running your filters before making the new one. The index filter is faster than the tree filter because this "copy" process consists only of copying to Git's index, letting you modify Git's index, and then committing whatever remains in Git's index afterward. All of these operations take place with a temporary index and, if using tree-filter, temporary work-tree, in a temporary sub-directory. Use the -d option to filter-branch to place this temporary sub-directory in a "fast" location to speed up filter-branch. Better yet, switch to the new git filter-repo instead.)

Upvotes: 1

Related Questions