2

I have been using commands like:

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

to move a directory tree from a subdirectory "subdir" to the top-level. In order to clean up the repo after a different and also successful filter-tree, I've tried using:

git filter-branch --tag-name-filter cat -- --all
git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' HEAD
git reflog expire --all --expire=now
git gc --prune=now --aggressive      

This mixes a couple of recommendations from hereabouts. However, after doing this filter-branch no longer works:

Rewrite 07436df7a2795910fb0b718d1a1b84e195cfabea (1/113) (0 seconds passed, remaining 0 predicted)    mv: cannot stat ‘somepathhere/.git-rewrite/t/../index.new’: No such file or directory
index filter failed: git ls-files -s | sed "_subdir/__" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
 mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"

I'm am not at all clear why this should be or which of the 'voodoo' clean up commands I used was responsible. Obviously some knowledge is missing from my git-fu. Can someone suggest what that could be?

Bruce Adams
  • 4,953
  • 4
  • 48
  • 111
  • Does commit `07436df7a2795910fb0b718d1a1b84e195cfabea` have the write subdirectory in it? – Daniel H Oct 09 '17 at 17:21
  • the command is to move the contents of the repo from "subdir" to the root of the directory. The root directory must exist for every commit if that's what you mean by "write" subdirectory. I believe the sub directory exists for all commits as well as I rewrote using --prune-empty. However .git-rewrite does not exist and of course should not for any commit either. – Bruce Adams Oct 10 '17 at 00:22
  • Actually, I somehow used a homophone; I meant the "right" subdirectory. Does `subdir/` exist in the tree of the commit it mentions? What do you get if you `git checkout 07436df; ls`? (There's some way to just look at the tree for a commit, but I don't remember what it is and don't have `git` available at the moment) – Daniel H Oct 10 '17 at 00:29
  • I think you may be on to something there. subdir does not exist for the first commit after all. The commit has no files at all. I thought I had deleted all empty commits with `git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' HEAD` but that command does not seem to have touched them. – Bruce Adams Oct 10 '17 at 09:44

1 Answers1

3

The rewrite was failing because there was at least one commit where 'subdir' didn't exist. The fix that works for me is to alter the filter to ignore erorrs by adding "; /bin/true"

git filter-branch --index-filter \
           'git ls-files -s | sed "s_subdir/__" |
                   GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                           git update-index --index-info &&
            mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; /bin/true' HEAD

This would seem to be the equivalent of --ignore-unmatch for --index-filter.

I am still unsure why the empty commits were not removed by the previous:

git filter-branch --prune-empty --tag-name-filter cat -- --all
git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' HEAD

However there is a solution to that (from this question):

git filter-branch --parent-filter "sed 's/-p <the_commit>//'" HEAD

This snips off the initial commit which is just a comment with no files (as a result of earlier rewriting). Once this is done the ";/bin/true" trick may no longer be required.

Bruce Adams
  • 4,953
  • 4
  • 48
  • 111