Repository Migration
This final chapter is the natural endpoint of the series — and a direct, larger-scale relative of Course 1, Chapter 9's "moving your project folder" scenario. Instead of moving a folder on disk, this is about restructuring entire repositories: splitting one into several, merging several into one, or moving a whole project to a different hosting provider — all while keeping the history that makes git useful in the first place.
The Three Migration Types
git subtree.Splitting a Repo with History Intact — git filter-repo
Naively copying a subfolder into a new repo and running git init loses everything — every commit, every "why was this written this way" buried in old commit messages. git filter-repo (the modern, recommended replacement for the older, slower git filter-branch) rewrites history to extract just one path's story.
$ git clone https://github.com/you/big-monorepo.git extracted-project
$ cd extracted-project
$ # Keep ONLY history relevant to this one subfolder
$ git filter-repo --path frontend/web-app
Parsed 1,847 commits
New history written in 4.2 seconds...
$ # This clone's history now ONLY contains commits touching that path,
$ # with paths rewritten as if it had always been the repo root
$ git log --oneline | wc -l
312 # only the commits that actually touched frontend/web-app
$ git remote add origin https://github.com/you/web-app.git
$ git push -u origin main
Merging Repos While Preserving Both Histories
Chapter 4's git subtree command is the practical tool here — merging another repository's full history into a subfolder of your current one, rather than losing it.
Without --squash (contrast with Chapter 4's earlier example), this preserves the full individual commit history of the merged-in repository, interleaved into your main repo's own history — useful when that history itself still has ongoing value, not just the current file state.
Moving Between Hosting Providers
git clone --mirror <old-url> — captures every branch, tag, and ref exactly, not just the default branch a normal clone would give you.git push --mirror <new-url> — transfers every branch, tag, and the complete commit history.What doesn't transfer automatically
--mirror doesn't automatically carry LFS-tracked file content (Chapter 7) — run git lfs fetch --all then git lfs push --all <new-remote> explicitly.Command Reference
| Command | What it does |
|---|---|
| git filter-repo --path <path> | Rewrites history to keep only commits touching the given path |
| git subtree add --prefix=<path> <url> <branch> | Merges another repo's full history into a subfolder (no --squash) |
| git clone --mirror <url> | Clones every branch, tag, and ref exactly — for host migration |
| git push --mirror <url> | Pushes a complete mirror to a new host |
| git lfs fetch --all / push --all | Explicitly transfers LFS object content, which --mirror alone doesn't carry |
Chapter 10 Quick Reference — and Series Wrap-Up
- git filter-repo --path — extracts one subfolder's history into a standalone repo; always on a throwaway clone
- git subtree add (no --squash) — merges another repo's full history into a subfolder, preserving both
- git clone --mirror / git push --mirror — the correct pair for moving a complete repo between hosts
- Doesn't transfer automatically: issues/PR history, branch protection settings, Actions secrets, LFS objects (needs explicit lfs fetch/push), submodule URLs pointing at old locations
- Keep the old host accessible, read-only, for a transition period after migrating
- Series recap (Course 3): internals (Ch1) → interactive rebase (Ch2) → reflog/recovery (Ch3) → submodules/subtrees (Ch4) → advanced Actions (Ch5) → securing a repo (Ch6) → large repos (Ch7) → bisect (Ch8) → team force-push recovery (Ch9) → full migration (Ch10)
- Full series complete: 30 chapters across Foundations, Teams, and Advanced Mastery — from "what is git" to recovering a team from a history-rewrite disaster