Migrate from Subversion to GitLab: what the move involves
If your team has years of Subversion history and needs GitLab merge requests and CI/CD running in infrastructure you control, plan for a conversion step before anything reaches GitLab. GitLab has no native Subversion importer, and the import documentation points to external conversion tools, so the work is to turn each Subversion repository into Git history that GitLab can accept, then push it. That conversion is where most of the effort sits. The effort is driven less by how many repositories you have than by three things: the quality of the history, the cleanliness of author identities, and how much binary content has been committed over the years. A single repository with a messy trunk, inconsistent usernames and a decade of committed release archives can take longer than twenty tidy ones. Ask the team to inventory layout (standard trunk, branches and tags folders or something custom), count distinct committer names, and measure the size of the repository on disk, including binaries that were later deleted, since they still sit in history.
Cost has two parts. You pay for the conversion and review work, which is one-time, and you pay for the platform that runs afterward, which recurs. GitLab Free, Premium and Ultimate are all available for self-managed installations, and the GitLab pricing page lists the per-user price for Premium and says Ultimate is custom priced. DeployOpen does not publish prices. A quote follows from a written scope that names the repositories, the history problems you already know about, the author mapping approach, the cutover window and the GitLab tier you intend to run, so ask for those items to be stated explicitly in any proposal.
Which Subversion concepts map cleanly to GitLab and which do not
This table compares Subversion concepts with their Git and GitLab equivalents and marks whether the conversion tool decides the result or a person must decide it. Read the right-hand column first, because those rows need an owner before conversion starts. Expect that some Subversion metadata will not survive as-is, and plan a written record of what was mapped, dropped or rebuilt.
| Subversion concept | Git and GitLab equivalent | Who decides and what to plan |
|---|---|---|
| Trunk and branches | Branch refs such as main and feature branches, created by the converter from copy operations | Tool decides the basic shape, but a person must confirm which copied paths become long-lived branches and which are retired |
| Tags | Annotated or lightweight Git tags, usually created from copies under tags/ | Tool creates tags when it recognizes the layout; a person must confirm tags that were edited or copied from working paths |
| svn:externals | Git submodules or subtree merges, which need a deliberate design | Human decision: externals do not convert to a single equivalent, so choose the replacement per external and test builds |
| svn:ignore | A .gitignore file, typically one per directory | Tool can translate many patterns, but a person should review them because ignore rules can hide files people still need |
| Commit author identities | Git author and committer fields, mapped to GitLab accounts through an author map | Human decision: every Subversion username needs a name and email mapping, and unmapped users need a policy before import |
| Revision properties (svn:log and custom revprops) | Commit messages and commit trailers, with most custom properties not carried over | Tool keeps the log message in most cases; custom revision properties usually need a human decision on whether to record them in messages |
| Locks | No native equivalent in Git; GitLab offers file locking as a separate feature that is not a conversion target | Human decision: confirm who relies on locks, then set a team process for binary and exclusive-edit files |
| Path-based permissions | Project and group permissions in GitLab, which apply to whole repositories rather than subpaths | Human decision: map each access rule to a project boundary, and accept that finer rules may need separate repositories |
| Binary files and large history | Git LFS for large binaries, with migration of existing blobs as a separate step | Human decision: choose which binaries move into LFS, which are removed from history and how storage is sized |
| Merge tracking (svn:mergeinfo) | Git merge commits, which the converter may only partly reconstruct | Tool reconstructs some merges; a person should verify merged branches in the target before retiring Subversion |
Conversion tools and the import paths GitLab documents
Subversion history reaches GitLab only after it is converted to Git, because GitLab's import documentation names Subversion as needing external conversion tools. The cards below cover the two conversion tools teams commonly use, the Git push that follows, and the import paths GitLab documents for other sources.
git svn for layout-driven conversion
The git svn clone command reads trunk, branches and tags from a Subversion layout and writes them as Git branches and tags. It fits repositories with a conventional layout and modest history. Check whether the standard trunk, branches and tags structure holds across the whole history, because irregular moves and copies are where layout-driven conversion usually breaks. Ask the maintainers of git svn, which ships with Git, to confirm the current version and supported options before you plan the run.
reposurgeon for history rewriting
reposurgeon is a history editor that reads a Subversion dump or repository and lets you rewrite commits, authors, branches and tags before the result is written to Git. It is the usual choice when the layout is irregular, when commit messages or author mappings need cleanup, or when large binary history must be dealt with. Confirm the current release and supported input formats with its maintainer, and rehearse the conversion on a copy of the repository.
Author mapping before any conversion
Subversion records authors as plain usernames, while Git records a name and email on every commit. Build the author map from the Subversion user list and the people who need to be credited in GitLab, then apply it in both git svn and reposurgeon runs. Unmapped authors often end up as placeholders in the converted history. Confirm with the team which email domain each contributor should use so later GitLab account matching works.
Git push into a GitLab project
Once the converted repository is clean, create the target GitLab project and push all branches and tags with git push --mirror or an explicit refspec. Verify branch and tag counts on both sides before anyone pushes new work. Set default branch, protected branch rules and tag protection in GitLab before developers start using the project, since the converted history does not carry those settings across.
Import paths GitLab documents
GitLab's import documentation lists GitHub, Bitbucket, Gitea, other GitLab instances, Git repositories by URL or manifest, and Jira and FogBugz issues as supported sources. Subversion is not on that list, so the conversion above is the route you plan. Use the documented importers for any non-Subversion projects that share the same migration wave, and confirm which importer versions your instance supports before scheduling.
Large binary history and LFS
Subversion repositories often hold large binaries committed years ago. Converted to Git, that history can make clones slow and the server repository large. Decide before conversion whether binaries move into Git LFS, are stripped from history, or stay in an archive. Ask your GitLab administrator to confirm storage limits and Git LFS settings on your instance, since those limits decide which option is practical.
How history conversion works before anything reaches GitLab
The conversion itself is a sequence of decisions that must be settled before any Git history is pushed to GitLab. The first is the author map: every Subversion username must resolve to a name and email address that will match a GitLab user, because git svn and reposurgeon both write commit authors from that mapping. Build the map from the full revision log rather than from the directory listing, then review every entry that maps to a shared or service account, since those commits will otherwise appear under a person who did not write them. Next, decide the layout. Confirm which paths are trunk, which directories are branches and which are tags, and whether any tag was ever edited after creation. Standard trunk, branches and tags layouts convert predictably; irregular ones need explicit rules so that a copied directory becomes a branch or tag and not a stray commit.
Empty and deleted paths need their own rules. Subversion permits empty directories and records deletions as ordinary revisions, while Git tracks only file content, so a directory with no files disappears unless you add placeholders deliberately. Decide which deleted paths were sensitive and must be purged from history, and which are merely retired code that should stay visible for archaeology. Record each decision in the conversion configuration so that a rerun produces the same result. Validation then compares the converted repository with Subversion itself: check that selected revisions produce identical trees, that tag and branch counts match the layout you chose, and that a sample of commit messages and authors appears correctly. Ask the converter's maintainers or your team to confirm the exact checks their tool supports for your version.
Run the converted history through a scratch GitLab group before the production push. A scratch group lets reviewers browse branches, open a merge request against a converted branch, and confirm that the default branch, protected branch settings and tag names look right without affecting any team. It also exposes problems that only appear inside GitLab, such as rejected large files, commit author emails that do not link to accounts, or unexpected history size. Treat the scratch run as a rehearsal: capture the exact commands, configuration and the list of checks, then repeat the same procedure for production. Plan for at least one full rehearsal, because a conversion that is corrected by hand after the push is hard to reproduce and hard to audit.
Sequence for a Subversion to GitLab cutover with a parallel run
This sequence moves a Subversion estate into a self-managed GitLab group in controlled stages, so each repository is inventoried, converted, reviewed and cut over with a known rollback path. The parallel run window, set by your team and its dependents, determines how much risk the final switch carries.
Inventory repositories, size and dependencies
List every Subversion repository, its trunk, branch and tag layout, revision count, total history size and large binary content, and record who commits to it and which build jobs, scripts or external tools read from it. Owners of each repository sign off on the list. The output is a register with one row per repository, showing its conversion method, target GitLab project path and owner. The step is done when no repository is unassigned and every owner has confirmed their row.
Run a pilot conversion on one representative repository
Choose one repository that has typical branching, a meaningful number of authors and some binary history, then convert it with git svn or reposurgeon and push it to a test project on your self-managed GitLab instance. The team checks commit counts, tag and branch names, file modes, line endings and whether large binaries were handled as intended. Record every defect and the fix. The step is done when a reviewer can clone the pilot project and reproduce the expected history from Subversion revisions.
Sign off the author mapping
Build an authors file that maps each Subversion username to a name and email address that the organization accepts for Git commits. Include service accounts and former staff, and decide how unmapped names are handled. Compare the mapping with your identity records so that the GitLab accounts that will later own commits can be matched. Security and engineering leads approve the file in writing. The step is done when the approved file is versioned with the migration records and reused unchanged for every full conversion.
Convert and push all repositories to a GitLab group
Run the approved conversion for every repository in the register, using the same tool version and authors file as the pilot. Push the results to the target group on your self-managed GitLab, set default branch, protected branch and tag rules, and apply group-level settings from your hardening baseline. Compare revision-to-commit counts and tag lists against Subversion for each project. The step is done when every project passes these checks and the owners confirm their histories in GitLab.
Start the parallel run with Subversion read-write
Announce a defined parallel run window in which teams keep committing to Subversion while they practice the GitLab workflow. Establish a repeatable sync, either by re-running the conversion for changed repositories or by applying incremental updates, and record which system is authoritative for each project at each point. Monitor drift between the two systems and resolve each divergence by a named owner. The step is done when drift is reported daily and any unplanned commit to GitLab has a documented resolution. The length of this window is set by your change calendar and the teams that depend on each repository, and it determines most of the cutover risk, so agree it with the owners rather than fixing it from a template.
Cut over with Subversion set read-only
Freeze the repositories in a scheduled change window, run a final incremental sync, and set Subversion to read-only so that no new revisions can be written. Repoint build jobs, scripts and developer workstations to GitLab, and confirm that CI runners and integrations authenticate against the new project paths. Keep the read-only Subversion server online for lookup and rollback. The step is done when a smoke test of clone, push, merge request and pipeline succeeds for each project and the change record shows the final revision matched.
Decommission Subversion after the agreed retention period
After the retention period agreed with compliance and the repository owners, take a verified backup of the Subversion repositories and dumps, record their location and checksums, then remove write paths, scheduled jobs and access grants. Confirm that archived data is restorable from the backup and that audit requirements for historic commits are met in GitLab. Retire the host only after no team relies on it. The step is done when the backup restore test passes and the decommission record is signed by the system owner.
What drives the cost and duration of a Subversion conversion
This table lists the factors that change how much work a Subversion to Git conversion takes and whether each cost is paid once or recurs. Use it to see which facts your quote depends on and what to collect before asking for one. The main takeaway is that history size, author mapping and the length of the parallel run usually matter more than the repository count alone.
| Driver | Why it changes effort | One-time or recurring | What to ask for or confirm |
|---|---|---|---|
| Number of repositories | Each repository needs its own conversion run, layout review and verification, and many small repositories can share one pattern. | One-time | Itemized repository list with owners and whether each is active or archived |
| Revision count and history depth | Long histories take longer to convert and verify, and old revisions often contain layout changes that need special handling. | One-time | Revision counts per repository and the earliest revision to be kept |
| Layout irregularity | Repositories that do not follow trunk, branches and tags conventions need hand-written rules to map paths to Git branches and tags. | One-time | Sample of non-standard layouts and the naming rules your teams expect |
| Committers needing author mapping | Every Subversion username needs a Git name and email, and unmapped or shared accounts need a decision before conversion. | One-time, with ongoing review if new committers join during the parallel run | Committer list, who approves mappings and how unknown users are handled |
| Large binary history | Large or frequently changed binaries inflate clone size and may need Git LFS or history rewriting, which affects storage and the conversion approach. | One-time for conversion, recurring for storage and LFS hosting | Largest files by size, their change frequency and whether history must keep them |
| Externals and svn:externals | External references must be turned into submodules, subtrees or separate repositories, each needing a decision and a test. | One-time | Count of externals per repository and the expected consumers |
| Hooks and integrations | Commit hooks, build triggers and issue links tied to Subversion must be found, then rebuilt as GitLab CI/CD, webhooks or integrations. | One-time build, recurring operation of any integration | Inventory of hooks, build servers and issue trackers that reference the repositories |
| Length of the parallel run | Teams keeping Subversion and GitLab in use together require sync checks, freeze rules and support time for the overlap period. | Recurring for the duration of the overlap, then ends at cutover | Planned overlap window, who owns each system during it and the cutover criteria |
What usually goes wrong in Subversion history conversions
Most Subversion-to-GitLab problems appear after the first conversion looks clean. The risks below cover identity, branch structure, repository size, dual writes and pipelines that still point at the old system. Each one has a check you can run before cutover.
Unmapped authors create orphan commits
Subversion records only a username, so every committer needs an explicit mapping to a name and email before conversion. Unmapped names produce commits with placeholder identities that no GitLab user can claim, which breaks blame history and contribution records. Prevention: build the authors file from the full svn log, review every entry against your identity directory, and confirm that a sample of converted commits shows the expected author in GitLab.
Wrong trunk choice loses branches
Subversion has no enforced branch model, so trunk, branches and tags are conventions that differ between repositories. Choosing the wrong root path, or converting only trunk, leaves active release lines behind. Prevention: list every top-level path and copy source before conversion, agree the branch and tag mapping with the owning teams, and check that each long-lived branch exists in the converted repository with its expected tip commit.
Large binaries bloat the Git repository
Subversion stores binary files as full revisions, and a naive conversion copies every version into Git objects, which can make clones slow for every contributor. Measure the largest blobs in the source history first and decide per file type what stays in history. Git LFS is an option to evaluate for large binaries, with the trade-offs in storage, client setup and history rewriting weighed against your team's needs.
Dual commits during the parallel run
During the parallel run, some developers keep committing to Subversion while others push to GitLab, and the two histories diverge silently. Set a written freeze date, make Subversion read-only with a server-side hook or repository permission change, and keep a final incremental sync that is verified against the last revision number. Confirm that no new commits land in Subversion after the freeze.
Pipelines still point at Subversion paths
Build scripts, deployment jobs, release tooling and checkout steps often hard-code svn URLs or trunk paths. After cutover these jobs fail, or worse, keep building from a frozen copy and ship stale code. Inventory every job, script and external tool that references the Subversion URL, switch each one to its GitLab project, and run a test build from the new repository before the old server is retired.
Questions teams ask before moving Subversion history to GitLab
Can GitLab import a Subversion repository directly?
No. The GitLab import documentation lists GitHub, Bitbucket, Gitea, other GitLab instances, Git repositories by URL or manifest, FogBugz and Jira, and it states that Subversion needs external conversion tools. The usual path is to convert the Subversion history to Git first, using git svn or reposurgeon, then push the resulting repositories to a self-managed GitLab project. The conversion step is where most of the decisions sit, including author mapping, branch and tag layout and how large binaries are handled, so plan it as a separate piece of work from the GitLab setup itself.
What drives the cost of a Subversion to GitLab conversion?
The cost follows from the amount of conversion work, not from the GitLab license. GitLab Free is available for self-managed installations at no charge, and the GitLab pricing page lists Premium at 29 US dollars per user per month billed annually, so the license line is separate from migration effort. The main drivers are the number of repositories, the age and size of the history, how many layout variants exist, how many authors need mapping, and how much binary history must be cleaned or moved to Git LFS. Ask for a written quote that lists each repository, the conversion method, the review steps, the cutover support and which items are one-time and which recur, such as ongoing support retainers.
How long does a Subversion to Git conversion take?
The duration depends on the repository count, history length, layout irregularity and how quickly the internal team can answer decisions. A repository with a clean trunk, branches and tags converts far faster than one where projects were moved between paths over many years. Plan separate time for a test conversion, a review of the result by people who know the code, the full conversion, and a parallel run before the cutover. Ask any partner to show the phases and dependencies in the written scope, and to name which steps wait on your team. We do not publish a timeline for this work, so confirm the duration against your own repository inventory.
What does our internal team need to provide for the migration?
Three inputs decide most of the outcome. First, an author list that maps Subversion usernames to real identities and, where needed, to email addresses used in GitLab. Second, layout decisions: which Subversion paths are projects, which are branches, which are tags, and whether any repositories should be split or combined. Third, sign-off from named owners who confirm that the converted history, branch list and tag list are correct before the old server is made read-only. Name these owners early, because a conversion that is technically complete can still fail if nobody accepts it.
Can our team run a Subversion to GitLab migration alone?
Often yes, if the team has someone comfortable with Git internals, git svn and the history rewriting tools, and if the repository count is small with regular layouts. The harder cases involve many repositories, long histories with inconsistent structure, large binaries and a tight cutover window. Your team would then carry the conversion scripts, the verification checks and the rollback plan alongside its normal work. Decide this by listing the skills and hours available, then comparing that with a fixed-scope proposal from a partner. DeployOpen plans, implements and documents this work in the client's own infrastructure, and most engagements are fixed-scope with the scope agreed in writing before work starts.
How do we handle large binary files in Subversion history?
Large binaries need a deliberate decision before conversion, because they can make the Git history heavy and slow to clone. Options include keeping them out of the history entirely, moving them to Git LFS, or converting them with the history rewritten so that old blobs are removed. Each option changes what developers see after cutover, so list the binary types, their total size and which releases still need them. Check that your self-managed GitLab instance has storage planned for LFS objects, and confirm the approach with the teams that depend on those files. Be cautious about rewriting history that has already been shared, because it changes commit identifiers that other systems may reference.
How do we run Subversion and GitLab side by side during cutover?
Run them in a defined sequence rather than letting developers choose freely. Keep Subversion read-only for the repositories being moved once the final conversion is verified, then keep the converted GitLab projects as the only place for new commits. Before that point, run a test conversion repeatedly so that the differences between the two histories are known. Agree on a rollback window in writing, and decide who can reopen Subversion if a serious problem appears. Also confirm which CI jobs, hooks and build scripts point to Subversion paths, because those will fail quietly if they are not updated.
What should we ask for in a quote for this migration?
Ask for a written scope that lists every repository, its size and history length, the conversion method (git svn or reposurgeon), the author mapping process, the branch and tag rules, and the handling of large binaries. The quote should separate one-time conversion and cutover work from any recurring support or retainer work, and it should name the acceptance steps and who signs them. Request the assumptions in plain language, such as what your team must supply and by when. Also ask what is excluded, for example CI pipeline rewrites or issue imports, which belong to other migration work. Compare quotes on that written basis rather than on headline totals.
How DeployOpen scopes and delivers a Subversion to GitLab migration
DeployOpen plans, implements, integrates, documents and supports self-hosted open-source platforms inside your own infrastructure, including the self-managed GitLab instance that receives your converted history. For a Subversion migration, the work starts with a written scope that defines which repositories, branches, tags and history depth move, and how cutover is run.
How we scope
- Inventory every Subversion repository, its layout and its branch and tag conventions before any conversion starts.
- Agree the author mapping source, the history depth to keep and the handling of large binary files in the written scope.
- Define which CI jobs, hooks and external tools are in scope, and which are left for a later phase.
How we build
- Run conversions on copies of each repository, using git svn or reposurgeon as the scope requires, and keep the tooling under version control.
- Check converted history against Subversion revisions, confirming commit counts, tags and branch heads for each sample repository.
- Configure the target GitLab projects, groups and access settings in your self-managed instance, aligned with your hardening baseline.
How we hand over
- Deliver a runbook covering the conversion commands, author mapping file, verification results and rollback steps.
- Document the cutover sequence for running Subversion and GitLab side by side, including the read-only date for each repository.
- Train the teams that will own the GitLab projects after handover, and record open items with owners.
How we support
- Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts.
- Ongoing support, upgrades and continuous testing are available as a retainer after handover.
- Ask for a written quote based on your repository count, history size and cutover plan before committing to a schedule.

