TL;DR

Two ways to move a subdirectory to a new repository while preserving commit history:

  • git subtree split - Safe, non-destructive, built-in
  • git filter-repo - Powerful, requires installation, rewrites history

Why This Rocks

I was working on a monorepo and needed to split out a subdirectory into its own repository. Found two great methods - one safe and built-in, another more powerful but requires external tools.

Method 1: Git Subtree Split (Safe & Built-in)

This is the safer, non-destructive method using built-in Git commands.

Step 1: Create New Branch with Subdirectory

In your original repository:

git subtree split --prefix=<path/to/your/subdirectory> -b <new-branch-name>

For example, to split my-app into a branch called my-app-split:

git subtree split --prefix=my-app -b my-app-split

Step 2: Create New Remote Repository

Create a new empty repository on GitHub/GitLab and get its URL.

Step 3: Push Branch to New Repo

git push <new-repo-url> <new-branch-name>:main

Example:

git push https://github.com/user/new-app-repo.git my-app-split:main

Step 4: Clean Up

Remove the temporary branch from original repo:

git branch -D my-app-split

Method 2: Git Filter-Repo (Powerful & Clean)

This method rewrites history but gives cleaner results.

Step 1: Install git-filter-repo

pip install git-filter-repo

On macOS you can also use brew install git-filter-repo

Step 2: Clone Fresh Copy

git clone --mirror <original-repo-url> temp-repo
cd temp-repo

Step 3: Filter History

git filter-repo --path <path/to/your/subdirectory>

For example, if your subdirectory is my-app:

git filter-repo --path my-app/

Step 4: Create New Remote

Create a new empty repository on GitHub/GitLab and get its URL.

Step 5: Push Filtered History

git remote set-url origin <new-repo-url>
git push --mirror

That’s it! Your new repo now has only the subdirectory and its complete history.

Cleanup (Optional)

To remove the subdirectory from the original repo:

# In fresh clone of original repo
git filter-repo --invert-paths --path <path/to/your/subdirectory>
git push origin --force --all

Which Method to Choose?

Feature git subtree split git filter-repo
Safety Non-destructive - Creates new branch, leaves original untouched ⚠️ Rewrites history - Must use on clone
Installation Built-in - No extra tools needed Requires install - pip install git-filter-repo
Process Creates branch in existing repo, push to new remote Creates new repo folder locally, then push
Best for Quick, safe splits without touching original Clean history and complex migrations

Bottom line: Use git subtree split for safe, simple splits. Use git filter-repo when you need the most powerful tool and plan to clean up the original repo too.

References