Search code examples
git

git move directory to another repository while keeping the history


First - apologies for asking this question. There are a lot of topics about it already. But I'm not having much luck with them. My lack of familiarity with git is not much help.

I'm moving a folder from one git repo to another (which already exists). e.g.

repo-1
---- dir1
---- dir2
---- dir3
---- dir-to-move
---- dir5

repo-2
---- dir1
---- dir2
---- dir3

In the end I want the repos to look like

repo-1
---- dir1
---- dir2
---- dir3
---- dir-to-move
---- dir5

repo-2
---- dir1
---- dir2
---- dir3
---- dir-to-move

i.e. For a time dir-to-move will exist in both repos. But eventually I'll migrate the latest changes to repo-2 and remove dir-to-move from repo-1.

My initial research made me believe that I needed to use filter-branch. e.g.

How to move files from one git repo to another preserving history using `git format-patch`and `git am`

I've since learnt that subtree superseded that approach. However it's not doing what I expected. I thought I'd be able to do something like

In repo-1 workspace

git subtree split -P dir-to-move -b split

to filter the split branch down to only dir-to-move and it's history. Then in repo-2 workspace

git remote add repo-1 repo-1-url.git
git subtree add --prefix dir-to-move split

This does move the code across. It also, sort of, includes the history

e.g.

cd repo-2
git log

Shows commits from repo-1

but

cd repo-2
git log dir-to-move

Shows only an 'Add dir-to-move from commit ....'

i.e. The history is included but does not show up when checked for the specific files/directories.

How can I do this properly?


Solution

  • I can't help you with git subtree, but with filter-branch it's possible.

    First you need to create a common repository that will contain both source and destination branches. This can be done by adding a new "remote" beside "origin" and fetching from the new remote.

    Use filter-branch on the source branch to rm -rf all directories except dir-to-move. After that you'll have a commit history that can be cleanly rebased or merged into the destination branch. I think the easiest way is to cherry-pick all non-empty commits from the source branch. The list of these commits can be obtained by running git rev-list --reverse source-branch -- dir-to-move

    Of course, if the history of dir-to-move is non-linear (already contains merge commits), then it won't be preserved by cherry-pick, so git merge can be used instead.

    Example create common repo:

    cd repo-2
    git remote add source ../repo-1
    git fetch source
    

    Example filter branch

    cd repo-2
    git checkout -b source-master source/master
    CMD="rm -rf dir1 dir2 dir3 dir5"
    git filter-branch --tree-filter "$CMD"
    

    Example cherry-pick into destination master

    cd repo-2
    git checkout master
    git cherry-pick `git rev-list --reverse source-master -- dir-to-move`