I have a repository and I would like to detach one of its directories into a new repo. This is a perfect place to get started, there is one caveat, however: the directory th
We (Matthew Flatt and me) wrote a program to do this: https://github.com/samth/git-slice
git filter-branch
can operate on ranges of commits; so what we can do is filter the 'before' and 'after' separately, and use grafts to tack them together:
git branch rename $COMMIT_ID_OF_RENAME
git branch pre-rename rename~
## First filter all commits up to rename, but not rename itself
git filter-branch --subdirectory-filter $OLDNAME pre-rename
## Add a graft, so our rename rev comes after the processed pre-rename revs
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
## The first filter-branch left a refs backup directory. Move it away so the
## next filter-branch doesn't complain
mv .git/refs/original .git/refs/original0
## Now filter the rest
git filter-branch --subdirectory-filter $NEWNAME master ^pre-rename
## The graft is now baked into the branch, so we don't need it anymore
rm .git/info/grafts
This is marginally more complex if you need to filter multiple branches or tags; branches before the rename can be included into the first filter-branch, while ones after must be included before the ^rename
in the second filter-branch.
Another option would be to add an index filter (or tree filter) instead that checks for both directories, old and new, and keeps whichever is present.
Since you haven't provided a test repository, here's a quick sanity-check script for this scenario:
#!/bin/bash
set -u
set -e
set -x
rm -rf .git x y foo
git init
mkdir x
echo initial > x/foo
git add x/foo
git commit -m 'test commit 1'
echo tc2 >> x/foo
git commit -a -m 'test commit 2'
mv x y
git rm x/foo
git add y/foo
git commit -a -m 'test rename'
git branch rename HEAD
echo post rename >> y/foo
git commit -a -m 'test post rename'
git branch pre-rename rename~
git filter-branch --subdirectory-filter x pre-rename
echo `git rev-parse rename` `git rev-parse pre-rename` >> .git/info/grafts
mv .git/refs/original .git/refs/original0
git filter-branch --subdirectory-filter y master ^pre-rename
rm .git/info/grafts
git log -u
If this procedure does not work for you, then there is likely to be something else odd about your repository history that you haven't described, such as another rename hiding in the history.