Skip to main content

Git: Move Subdirectory to New Repository

I recently published my Brief emulation mode for Emacs to the MELPA Emacs package repository. This is code I wrote well over twenty years ago and have been using daily since.

I hadn't published it before partly because it was languishing in a sub-directory of my main Emacs repo (and partly because I never had the time before). To become a package in its own right though, it had to have its own repo.

Splitting out a subdirectory to a new repo used to be a complex task in Git (usually involving complicated invocations of git filter-branch), but these days it's reasonably straightforward with the git subtree command (well at least as straightforward as anything else in Git 😀).

The other reason I like the subtree method is it's non-destructive - you can back out at any point and still get back to where you started, plus all the history is retained.

Here's how it works:

Step 1: Create a new branch in the main repo with just the sub-directory commits

$ cd <main-dir>
$ git subtree split -P <sub-dir> -b <new branch>

Step 2: Create new repo in the sub-directory

$ cd <sub-dir>
$ git init

Step3: Pull branch into new repo

$  git pull <main-dir> <branch>

Step 4: Create new remote repo

  • Using your upstream repo of choice.

Step 5: Push new repo to remote

$ git remote add origin <remote ref>
$ git push -u origin master

Step 6: Remove sub-directory from original repo

$ cd <main-dir>
$ git rm -r --cached <sub-dir>
$ git commit

(Optional) Step 7: Delete branch from original repo

$ git branch -d <branch>

Comments

Popular posts from this blog

Merging Git Repositories

No project of significant size that I've ever seen has retained its initial structure. Restructuring projects is a fact of life, but unfortunately Git doesn't make it easy. Fundamentally this stems from the way Git works, treating changes as a succession of snapshots and not storing any other metadata. Of course this is part of what makes Git fast and efficient, but at the expense of making some common operations more difficult for users. Git really is a perfect 21st century illustration of the classic  "Worse Is Better"  paradigm of successful software 😀 Previously I discussed how to split a Git project apart into separate repositories . Now I'm going to discuss how to do the opposite and merge separate repositories into one. On the face of it, this would seem a simpler task as Git has powerful support for merging... Let's take the opposite example to my splitting apart article - say you have a main Git repo (ProjA) and a second repo (ProjB) in...

East Devon Continued

Some iPhone pictures: Seaton Bay from Beer Hill at Sunset Gulls on Beer Beach We also had a pair of Pheasants in the garden, which was a bit of a surprise. There are always plenty of rabbits and wild birds, but this is the first time I've seen game birds. Here is the male, sitting on the garden wall, wondering what I'm up to: Male Pheasant I also spotted these attractive white Cyclamen in the garden: Cyclamen

Renaming Files in Git

Renaming Files I recently had to rename a lot of files in brf-mode for submission into MELPA . These files have 10+ years of version control history I wanted to keep. In the process I realised retaining all that history in Git isn't as simple as I thought 😀 I thought it was as simple as using git mv rather than filesystem  mv and Git would know everything had been renamed. It turns out I was wrong and I should have known that from my knowledge of how Git works 😖 In reality, Git works by storing snapshots rather than file or directory metadata and git mv is just a convenience shortcut for typing: $ mv <old name> <new name> $ git rm <old name> $ git add <new name> That's all there is to it! Now the "magic" happens when you git log or git blame a file and Git works out the file was renamed by diffing the contents.  If files have the same contents (within a certain threshold %) it thinks a rename happened. See here in the  Gi...