Sorry this page looks weird. It was automatically migrated from my old blog, which had a different layout and different CSS.

Moving A Subdirectory Into A Separate Git Repository

Like many people I have my dotfiles under version control. Until today I kept my Vim configuration in that repo too, but this morning I promoted the Vim stuff to its own repo.

Although this was relatively straightforward, the submodules in my vim/bundle directory added some complexity.

This was the directory layout I started with:

dotfiles
|-- .gitmodules
|-- bashrc
|-- [...etc...]
|-- vim
|   |-- README.md
|   |-- autoload
|   |   `-- pathogen.vim
|   |-- bundle
|   |   |-- vim-cucumber
|   |   `-- [...etc...]
|-- gvimrc
`-- vimrc

I wanted to move vimrc, gvimrc, and vim/ to a new dotvim repo, preserving their history. This Stack Overflow question, “Detach subdirectory into separate Git repo”, was invaluable.

Moving the subdirectory to a separate Git repo

First we clone the dotfiles repo to a new dotvim repo.

$ git clone --no-hardlinks /path/to/dotfiles /path/to/dotvim

Next we discard everything other than the subdirectory we want, vim, promoting it to the root level.

$ cd /path/to/dotvim
$ git filter-branch --subdirectory-filter vim HEAD -- --all
$ git reset --hard

Now we get rid of the objects we are no longer interested in.

$ git gc --aggressive
$ git prune

Next we replace the reference to the original repo, dotfiles, with our new remote repo on GitHub.

$ git remote rm origin
$ git remote add origin git@github.com:airblade/dotvim.git

Now we can push everything up to GitHub.

$ git push origin master

To make this easier in future, I ran a little script which I have come to love:

$ git track
tracking origin/master

Now I can git push without worrying about the remote name or branch name.

Fixing the submodules in the new repo

Although the submoduled directories are there in the new repo, they are empty because the repo doesn’t know they are submodules. Rectify this by copying the .gitmodules file from the original repo and editing it to correct the submodules' paths.

$ cp /path/to/dotfiles/.gitmodules /path/to/dotvim
$ cat /path/to/dotvim/.gitmodules

[submodule "vim/bundle/vim-cucumber"]
  path = vim/bundle/vim-cucumber
  url = https://github.com/tpope/vim-cucumber.git

...etc...

Fix all the paths, e.g. edit in Vim and :%s|vim/||. You want:

[submodule "bundle/vim-cucumber"]
  path = bundle/vim-cucumber
  url = https://github.com/tpope/vim-cucumber.git

Now you can do:

$ git add .gitmodules
$ git bundle update --init
$ git commit -m "Update bundles."

Removing the subdirectory from the original repo

Now we have moved the subdirectory into its own repo, we want to remove it from the original repo. If it didn’t contain any git submodules, there would be two ways to do this.

To simply remove it:

$ cd /path/to/dotfiles
$ rm -rf vim
$ git rm -r vim
$ git commit -m "Extracted vim into its own repo."

This would leave the vim subdirectory in the repo’s history. If instead you wanted dotfiles to look as if vim had never been there, you would do:

$ cd /path/to/dotfiles
$ git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch vim" --prune-empty HEAD

However we do have submodules and we need to remove those first (probably – I’m not certain).

Thanks again, Stack Overflow.

Now we can remove the vim subdirectory as above.

Moving the files vimrc and gvimrc to the new repo

The protocol above discards everything other than the vim subdirectory including, unfortunately, the vimrc and gvimrc files. I couldn’t see a neat way to keep those as well as the subdirectory.

However I didn’t care too much about migrating their histories, so I just copied them across.

$ cp /path/to/dotfiles/{vimrc,gvimrc} /path/to/dotvim/
$ cd /path/to/dotfiles
$ git rm {vimrc,gvimrc}
$ git commit -m "Moved vimrc and gvimrc to dotvim repo."
$ cd /path/to/dotvim
$ git commit -am "Moved from dotfiles repo.  See there for their history."

Done

That’s it. You can see my new dotvim repo kept its history, and the original dotfiles repo is without Vim.

Andrew Stewart • 5 November 2010 • GitVim
You can reach me by email or on Twitter.