1   In short


SRCREPO=/path/to/src_repo
NEWREPO=/path/to/new_repo
EXT=in-repo-path/to/dir/file
NEWROOT=in-repo-path/to/dir
hg convert --filemap <(cat <<EOF
include "$EXT"
rename "$NEWROOT" .
EOF

) "$SRCREPO" "$NEWREPO"

The command does:

  1. Extracting $EXT file from $SRCREPO into newly created $NEWREPO. You can list as many as you like with include, $EXT can be file or directory.
  2. Re-rooting in-repo-path/to/dir as new root, this is optional. You can use rename to remap file or directory with new name.

After processing, you need to:


cd $NEWREPO
hg update

You may want to read the command I use in the real example if you have some files are not in revision control in the extracted directory.

2   Real example

I have a Hg repository on Google Code Hosting, which contains with many small pieces of code, unrelated to each other. I can tell you, such is not a good idea, don’t put small pieces into one repository. Why, because I constantly have to move them out when they gets bigger.

Now, I just did another one. Before this time, I only copied the files into a new repository, which didn’t contain the commits. To me, it’s really not a big deal, I could always go back to the old repository to look up the history if I want to. But if you can bring the commits to new repository, then why not?

Here is a real case command I issued:


~/p $ hg convert --filemap <(cat <<EOF
> include "GoogleAppEngine/yjl-im"
> rename "GoogleAppEngine/yjl-im" .
> EOF
> ) yjl yjl.im
initializing destination yjl.im repository
scanning source...
sorting...
converting...
599 Initial directory structure.
[snip]
1 Fix background color of image with caption
0 Fix template download with link from dashboard.

~/p $ cd yjl.im
~/p/yjl.im $ hg update

~/p/yjl.im $ cd ~/p/yjl/GoogleAppEngine/yjl-im
~/p/yjl/GoogleAppEngine/yjl-im $ hg st -i . | cut -f 2- -d ' ' | while read f; do d=~/p/yjl.im/"$(dirname "$f")"; mkdir -p "$d"; cp -a "$f" "$d"; done

The first part is to extract by using hg convert from ~/p/yjl/GoogleAppEngine/yjl-im to ~/p/yjl.im. I use Here Docment and Process Substitution (see man bash), so I don’t need to create a file for --filemap option.

After I ran hg update to get a local working copy, I realized the ignored files were not included during the process since they were ignored and not even in the repository. So I ran that long one-liner to copy the files. You probably can just copy -ra from the old repository to new repository. I was thinking too much at that moment.

I think you can also use hg convert to extract other VCS repositories. One more thing to mention: the changesets hashes are not the same.