Detach subdirectory (that was renamed!) into a new repo
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 开发者_如何学Gois one caveat, however: the directory that I want to detach was renamed at some point. And if I follow the solution from that post with the new name of the directory then it seems I'm loosing the history before the re-name. Any ideas of a tweak to make it work in this situation?
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.
We (Matthew Flatt and me) wrote a program to do this: https://github.com/samth/git-slice
精彩评论