Working with Git-SVN: SVN checkout and GitHub mirror
These notes cover creating a Git repository from an existing Subversion (SVN) repository without importing the full history, while keeping the ability to push and pull from SVN and also push new commits to GitHub. They also cover keeping the same Git-SVN repository in sync across multiple machines. This is the same pattern the UpdateFolderAsGitSvnRepo function in the update script relies on.
Checking out SVN and adding to GitHub
The goal is to start the Git history at a recent SVN revision (so old history stays only in SVN), while the git-svn bridge keeps working for ongoing push/pull to SVN, and GitHub receives the truncated history going forward.
Do not try to truncate an existing full clone. git-svn maps Git commits to SVN revisions using the git-svn-id: trailer in each commit message plus a local rev-map keyed on commit SHAs. Rewriting history changes every SHA and invalidates that metadata. Re-cloning from SVN at a chosen revision avoids the problem entirely.
1. Find the revision to start from. For essentially “no history”, use the current head revision.
svn info <svn-url> # note the "Revision: NNNN" value
2. Clone from that revision onward. Use --stdlayout for the standard trunk/branches/tags layout. The first commit is a full snapshot of the tree at rNNNN; everything before it stays in SVN.
git svn clone -r NNNN:HEAD --stdlayout <svn-url> myproject
3. Confirm the bridge works.
cd myproject
git svn rebase # pull from SVN
git svn info # sanity check
4. Add the GitHub remote and push.
git remote add origin https://github.com/<orgName>/<repo>.git
git push -u origin master
Critical ordering. git svn dcommit rewrites local commits — it appends the git-svn-id trailer, which changes their SHAs. Always dcommit to SVN first, then push to GitHub. Pushing to GitHub before dcommitting makes the branches diverge and forces a git push --force every time.
Everyday cycle for ongoing work:
# make changes, commit locally, then:
git svn dcommit # 1. push to SVN FIRST (finalizes commit SHAs)
git push origin # 2. THEN push the finalized commits to GitHub
# to pull from SVN:
git svn rebase # fetch + rebase from SVN
git push origin # mirror the update to GitHub
Keep GitHub as a push mirror rather than a second source of truth. git-svn expects a linear history to dcommit cleanly, so merge commits introduced on the GitHub side (for example from merged pull requests) should be rebased onto the git-svn branch before being dcommitted back to SVN.
Having a Git-SVN repo on multiple machines
The hard part of using git-svn from more than one machine is that two independent git svn clone operations of the same SVN repo produce commits with different SHAs, even from the same revision. Git then treats the two histories as unrelated. The fix is to clone from SVN only once, share the resulting Git repository, and rebuild only the local rev-map on the other machines.
git-svn identifies which Git commit maps to which SVN revision using two things: the git-svn-id: <svn-url>@<rev> <uuid> trailer inside each commit message (this travels with the commit because it is part of the SHA), and a local rev-map under .git/svn/ (this does not travel and is rebuilt per machine). Because the trailer is in the commit, any machine can rebuild the rev-map from an existing Git history — as long as every machine shares the same commits.
Machine A (once) — the single canonical git-svn clone:
git svn clone -r NNNN:HEAD --stdlayout <svn-url> myproject
cd myproject
git remote add origin https://github.com/<orgName>/<repo>.git
git push -u origin master
Every other machine — clone from Git (not from SVN), then rebuild the git-svn bridge against those existing commits:
git clone https://github.com/<orgName>/<repo>.git myproject
cd myproject
# 1. Point this repo at the same SVN URL / layout as Machine A
git svn init --stdlayout <svn-url>
# 2. Rebuild the local rev-map from the existing git-svn-id trailers
git svn fetch
Running git svn init then git svn fetch on a repo that already contains the git-svn history rebuilds .git/svn/ to point at the existing SHAs, rather than creating new divergent commits. After that, git svn rebase and git svn dcommit work on that machine against the identical history.
These must be identical on every machine, or git-svn will treat the histories as different:
- The SVN URL — exactly (protocol, host, port, trailing slash), because it is baked into the
git-svn-idtrailer. - The layout flags —
--stdlayoutvs explicit--trunk/--branches/--tags. - The starting revision — automatic once other machines clone from Git rather than SVN.
- Reasonably aligned Git versions.
Verify the machines agree — the top-of-branch SHA should match across machines:
git svn info # same URL and revision
git log --format='%H %s' -1 # SHAs must match across machines
git svn dcommit --dry-run # confirms the SVN mapping is known
Do not run git svn clone on each machine (that guarantees mismatched SHAs), and do not copy .git/svn/ between machines (it holds absolute paths and can be stale). Regenerate it with git svn init + git svn fetch instead.
When more than one machine commits, treat SVN as the serialization point: run git svn rebase (pull the latest from SVN) before dcommitting, and push to GitHub only after a successful dcommit. That keeps every machine and GitHub converging on the same SHAs.