Moving a directory with history from one repository to another while renaming
- From
- Andy Parkins <andyparkins@gmail.com>
- Date
- Jun 21, 2007, 12:37 UTC
- Message-ID
- <200706211337.32978.andyparkins@gmail.com>
Hello,
I'm sure this has come up before, and I'm sure the answer is git-filter-branch.
I have repositoryA, which has a subdirectory, say "repoA_directory", and I've done some development in it. I now wish I'd done this development in a different repository, repositoryB and that it would have been in a different directory, "sub/dir/repoB_directory".
What's the best way to do this?
*** Stop press (I tried a bit harder before sending the above email) ***
This is what I did, and am reporting here for future googlers; and in case you're all interested in git-filter-branch success stories (which, incidentally is a fabulous little tool).
In repositoryA...
git-filter-branch --subdirectory-filter "repoA_directory" directoryonly
Now, the branch "directoryonly" contains repoA_directory (and history) as a new root commit, and as the root directory of the repository.
git checkout directoryonly
git-filter-branch --tree-filter "mkdir -p sub/dir/repoB_directory; \
mv file1 file2 file3 sub/dir/repoB_directory" directorymovedNow, the branch "directorymoved" contains repoA_directory (and history) alone, moved to "sub/dir/repoB_directory".
In repositoryB...
git-fetch /path/to/repositoryA directorymoved:repoAbranch
repositoryB now contains a new, independently rooted, branch containing only sub/dir/repoB_directory. We would ideally at this point just rebase that independent branch to the appropriate point in the main development branch of repoB, but we can't because repoAbranch doesn't share a common ancestor with any of the repositoryB branches.
That is to say, we have these two branches:
* --- * --- * --- * --- * (master)
B --- * --- * (repoAbranch)
but we want:
* --- * --- * --- * --- * (master)
\
B --- * --- * (repoAbranch)Find the commit hash of the first commit in repoAbranch, B, and apply that one commit as a patch to your mainline branch (probably making a temporary branch on your way, to preserve your current master)
git checkout -b temp git show --pretty=email hash-of-B | git-am
* --- * --- * --- * --- * (master)
\
B' (temp)B --- * --- * (repoAbranch)
We've now got a commit that will serve as a common ancestor.
git-rebase --onto temp hash-of-B repoAbranch git-branch -D temp
* --- * --- * --- * --- * (master)
\
B' --- *' --- *' (repoAbranch)B --- * --- * [orphan branch]
Voila. repoAbranch is now the original repoA_directory, but stored at sub/dir/repoB_directory and includes the development history.
git-gc --prune will get rid of the orphan branch if you're bothered about the storage.
Andy
-- Dr Andy Parkins, M Eng (hons), MIET andyparkins@gmail.com