threads / discuss / 8673

Moving a directory with history from one repository to another while renaming

Subject: Moving a directory with history from one repository to another while renaming

## tl;dr

4 messages between Jun 21, 2007 and Jun 21, 2007.

replies: 3people: 3as markdown or json

Andy Parkins· Jun 21, 2007, 12:37 UTC · lore
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" directorymoved

Now, 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
Jeff King· Jun 21, 2007, 13:01 UTC · re: Andy Parkins · lore

Re: Moving a directory with history from one repository to another while renaming

On Thu, Jun 21, 2007 at 01:37:30PM +0100, Andy Parkins wrote:
>  git checkout directoryonly
>  git-filter-branch --tree-filter "mkdir -p sub/dir/repoB_directory; \
>     mv file1 file2 file3 sub/dir/repoB_directory" directorymoved

You can do this much more efficiently by just operating on the index. Something like:

git-filter-branch --index-filter \
 'git-ls-files -s | sed -n 's/change/paths/p' | git-update-index --index-info' \
 directorymoved
-Peff
Andy Parkins· Jun 21, 2007, 13:57 UTC · re: Jeff King · lore

Re: Moving a directory with history from one repository to another while renaming

On Thursday 2007 June 21, Jeff King wrote:
Show 6 quoted lines
> You can do this much more efficiently by just operating on the index.
> Something like:
>
> git-filter-branch --index-filter \
>  'git-ls-files -s | sed -n 's/change/paths/p' | git-update-index
> --index-info' \ directorymoved
:-D  Even better.  I am definitely in the "fan of git-filter-branch" camp.

Thanks for sharing that line; I've actually found it instructive for more than just git-filter-branch. I definitely hadn't appreciated the fact that the index can be so easily manipulated.

Andy
-- 
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com
Johannes Schindelin· Jun 21, 2007, 14:05 UTC · re: Andy Parkins · lore

Re: Moving a directory with history from one repository to another while renaming

Hi,
On Thu, 21 Jun 2007, Andy Parkins wrote:
Show 14 quoted lines
> On Thursday 2007 June 21, Jeff King wrote:
> 
> > You can do this much more efficiently by just operating on the index.
> > Something like:
> >
> > git-filter-branch --index-filter \
> >  'git-ls-files -s | sed -n 's/change/paths/p' | git-update-index
> > --index-info' \ directorymoved
> 
> :-D  Even better.  I am definitely in the "fan of git-filter-branch" camp.
> 
> Thanks for sharing that line; I've actually found it instructive for more than 
> just git-filter-branch.  I definitely hadn't appreciated the fact that the 
> index can be so easily manipulated.

You have to adapt the line minimally: As is, it will possibly catch the wrong names, and it does not _move_ the directory, but rather _copy_ it.

So I think something like
git-ls-files -s | sed "s-\t-&newsubdir/-" |
  GIT_INDEX_FILE="$GIT_INDEX_FILE".new git-update-index --index-info &&
mv "$GIT_INDEX_FILE".new "$GIT_INDEX_FILE"
is needed.

Ciao, Dscho

← back to recent threads