Migrating to Git from other version control systems requires planning and understanding of how Git differs from your current system. This guide helps teams successfully transition to Git.
Understanding Git’s Differences
Before migrating, understand how Git differs from centralized VCS:
Distributed vs. Centralized
Traditional VCS (CVS, SVN):
- Single central repository
- Commits go directly to server
- Need network for most operations
- Linear history model
Git:
- Every clone is a complete repository
- Commits are local operations
- Work offline, sync later
- Branch-based history model
Key Conceptual Differences
Commits are snapshots, not deltas
Git stores complete snapshots of your project, not just changes. This makes operations like branching extremely fast.
Branches are lightweight
Creating a branch in Git is instant and cheap. Branches are fundamental to Git workflows, not expensive operations to avoid.
Staging area
Git has an intermediate staging area (index) between your working directory and repository. This provides fine-grained control over what you commit.
No repository is special
While you can designate a central repository, technically all clones are equal. This enables flexible workflows.
Migration Strategies
Assessment Phase
Before migrating, assess your current setup:
Inventory your repositories
- How many repositories?
- How large are they?
- What’s the branching structure?
- Are there large binary files?
Identify dependencies
- Build scripts referencing VCS
- Deployment processes
- CI/CD pipelines
- Developer tools and IDEs
Plan the transition
- Phased migration vs. big bang
- Training schedule
- Pilot projects
- Rollback plan
Planning Considerations
Timeline:
- Allow time for learning and adjustment
- Plan for lower productivity during transition
- Schedule training sessions
- Have Git experts available for questions
Resources:
- Allocate time for training
- Set up Git infrastructure (hosting, CI/CD)
- Prepare documentation
- Assign migration champions
Migrating from CVS
Using git-cvsimport
Install dependencies
# Install cvsps (version 2.1 or higher)
# From https://github.com/andreyvit/cvsps
Import CVS repository
# From CVS working directory
git cvsimport -C <destination> <module>
# Example:
cd /path/to/cvs/checkout
git cvsimport -C ~/git/project myproject
Review imported history
cd ~/git/project
git log --oneline
git branch -a
Create a bare repository
git clone --bare project project.git
scp -r project.git server:/git/repositories/
CVS to Git Command Mapping
# CVS # Git equivalent
cvs checkout project git clone user@server:project.git
cvs update git pull
cvs commit git commit -a && git push
cvs add file.txt git add file.txt
cvs remove file.txt git rm file.txt
cvs diff git diff
cvs log git log
cvs tag RELEASE_1_0 git tag v1.0
cvs status git status
Workflow Translation
CVS workflow:
cvs update
# Make changes
cvs commit
Git equivalent:
git pull
# Make changes
git add changed-files
git commit -m "message"
git push
In Git, commit and push are separate operations. You can make multiple local commits before pushing to the central repository.
Migrating from Subversion
Using git-svn
Clone SVN repository
# Standard layout (trunk, branches, tags)
git svn clone -s https://svn.example.com/project
# Non-standard layout
git svn clone https://svn.example.com/project \
--trunk=main \
--branches=feature-branches \
--tags=release-tags
# Large repository (start from recent revision)
git svn clone -s -r 1000:HEAD https://svn.example.com/project
Clean up the import
# Convert SVN tags to Git tags
git for-each-ref refs/remotes/origin/tags | \
while read sha type ref; do
tag=$(echo $ref | sed 's|refs/remotes/origin/tags/||')
git tag -a "$tag" -m "Tag $tag" "$ref"
git branch -r -d "origin/tags/$tag"
done
# Convert remote branches to local branches
git for-each-ref refs/remotes | \
while read sha type ref; do
branch=$(echo $ref | sed 's|refs/remotes/origin/||')
git branch "$branch" "$ref"
done
Create bare repository
git clone --bare project project.git
SVN to Git Command Mapping
# SVN # Git equivalent
svn checkout url git clone url
svn update git pull
svn commit git commit -a && git push
svn add file git add file
svn delete file git rm file
svn copy ^/trunk ^/branch git branch branch
svn switch ^/branch git switch branch
svn merge git merge
svn diff git diff
svn log git log
svn info git remote show origin
svn status git status
Hybrid Approach
During transition, maintain both SVN and Git:
# Keep syncing with SVN while using Git
git svn clone -s https://svn.example.com/project
cd project
# Work in Git
git checkout -b feature
# Make changes
git commit -am "Implement feature"
# Sync with SVN
git svn rebase
git svn dcommit
When using git-svn, avoid using Git merge commits. SVN doesn’t understand merge history, so use rebase instead.
Migrating from Mercurial
Using fast-export
Install fast-export
git clone https://github.com/frejr/fast-export.git
Convert repository
# Create new Git repo
mkdir project-git
cd project-git
git init
# Import from Mercurial
../fast-export/hg-fast-export.sh -r /path/to/hg/project
# Clean up
git checkout HEAD
Verify conversion
git log --oneline
git branch -a
Mercurial to Git Command Mapping
# Mercurial # Git equivalent
hg clone git clone
hg pull git fetch
hg update git pull
hg commit git commit -a
hg push git push
hg add git add
hg remove git rm
hg branch git branch
hg merge git merge
hg diff git diff
hg log git log
hg status git status
hg tag git tag
Setting Up Git Infrastructure
Choosing a Hosting Solution
Self-hosted options:
- GitLab: Full DevOps platform, CI/CD included
- Gitea: Lightweight, easy to deploy
- Gogs: Minimal resource requirements
Cloud-hosted options:
- GitHub: Largest community, excellent integrations
- GitLab: Integrated CI/CD, flexible plans
- Bitbucket: Integrates with Atlassian tools
- Azure DevOps: Microsoft ecosystem integration
Creating a Central Repository
Set up a shared bare repository:
Create bare repository
# On the server
mkdir -p /git/repositories/project.git
cd /git/repositories/project.git
git init --bare --shared
Configure access
# SSH access
# Add developers' public keys to ~/.ssh/authorized_keys
# Or use git-shell for restricted access
chsh -s $(which git-shell) gituser
Push initial content
# From migrated repository
git remote add origin user@server:/git/repositories/project.git
git push -u origin --all
git push -u origin --tags
HTTP(S) Access
Set up HTTP(S) access with git-http-backend:
# Apache configuration
<VirtualHost *:443>
ServerName git.example.com
SetEnv GIT_PROJECT_ROOT /git/repositories
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
<Location /git>
AuthType Basic
AuthName "Git Access"
AuthUserFile /etc/apache2/git-users
Require valid-user
</Location>
</VirtualHost>
Team Training
Training Plan
Basic Git concepts (1-2 hours)
- Repositories, commits, branches
- Distributed model
- Staging area
- Basic commands
Daily workflow (2-3 hours)
- Cloning, pulling, pushing
- Creating branches
- Making commits
- Merging changes
Team workflow (1-2 hours)
- Pull requests
- Code review
- Resolving conflicts
- Team conventions
Advanced topics (optional)
- Rebasing
- Cherry-picking
- Stashing
- History rewriting
Hands-on Exercises
Provide practical exercises:
# Exercise 1: Basic workflow
# Clone, branch, commit, push, pull request
# Exercise 2: Resolving conflicts
# Create conflicting changes, merge, resolve
# Exercise 3: Fixing mistakes
# Amend commits, reset, revert
# Exercise 4: Working with history
# View logs, diff between branches, blame
Migration Checklist
Pre-Migration
During Migration
Post-Migration
Common Migration Challenges
Large Binary Files
Problem: Git doesn’t handle large binary files efficiently.
Solution: Use Git LFS (Large File Storage)
# Install Git LFS
git lfs install
# Track large files
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "*.zip"
# Migrate existing files
git lfs migrate import --include="*.psd,*.mp4"
Huge Repository History
Problem: Importing decades of history takes too long.
Solutions:
# Option 1: Shallow import
git svn clone -s -r 1000:HEAD https://svn.example.com/project
# Option 2: Split by date
# Archive old history separately
# Import recent history into Git
# Option 3: Use shallow clones for developers
git clone --depth 100 https://github.com/org/project.git
Complex Branch Structures
Problem: SVN branch structure doesn’t map cleanly to Git.
Solution: Simplify during migration
# Map to standard Git structure
trunk -> main
branches -> feature branches
tags -> Git tags
# Archive inactive branches
# Consolidate redundant branches
Team Resistance
Problem: Team members resist change.
Solutions:
- Start with pilot projects
- Provide extensive training
- Have Git champions on each team
- Allow time for learning curve
- Demonstrate benefits (speed, offline work, better branching)
Maintaining Both Systems
During transition, you might need to maintain both:
Bidirectional Sync
# Set up git-svn
git svn clone -s https://svn.example.com/project
# Work in Git
git commit -am "Changes"
# Push to Git remote
git push origin main
# Sync back to SVN
git svn rebase
git svn dcommit
Migration Period Best Practices
- Designate one system as source of truth
- Minimize changes to old system
- Set a firm cutover date
- Communicate clearly which system to use
- Provide clear migration status updates
Post-Migration Optimization
Repository Cleanup
# Remove unnecessary files
git filter-repo --path unwanted/ --invert-paths
# Clean up history
git reflog expire --expire=now --all
git gc --prune=now --aggressive
Establish Workflows
# Document your chosen workflow
# - Feature branch workflow
# - Gitflow
# - Forking workflow
# Set up branch protection
# - Require reviews
# - Require status checks
# - Prevent force pushes to main
Optimize for Your Team
Review and refine
After a few weeks, gather feedback and adjust workflows.
Automate workflows
Set up hooks, CI/CD, and automated checks.
Document conventions
Create a CONTRIBUTING.md with your team’s Git conventions.
Continuous improvement
Regularly review and update practices based on team needs.
Successful migration is as much about people and process as it is about technology. Invest in training and allow time for adjustment.