How to migrate from Mercurial to Git
Migrating from Mercurial to Git preserves complete repository history including branches, tags, and commit metadata during transition. With over 25 years of software development experience and as the creator of CoreUI, I’ve migrated legacy Mercurial repositories to Git for modern workflows. Git’s fast-export and Mercurial’s hg-fast-export tools enable conversion with full history preservation and author attribution. This approach ensures seamless transition from Mercurial to Git with complete audit trail and repository integrity.
Use hg-fast-export or git-remote-hg to convert Mercurial repositories to Git preserving history, branches, and tags.
Basic migration with git-remote-hg:
# Install git-remote-hg
# On macOS
brew install git-remote-hg
# On Ubuntu
sudo apt-get install git-remote-hg
# Clone Mercurial repository as Git
git clone hg::https://bitbucket.org/user/hg-repo git-repo
cd git-repo
# Add Git remote
git remote add origin https://github.com/user/new-repo.git
# Push to Git
git push -u origin main
Migration with hg-fast-export:
# Install hg-fast-export
git clone https://github.com/frej/fast-export.git
cd fast-export
# Create empty Git repository
mkdir ../git-repo
cd ../git-repo
git init
# Import from Mercurial
../fast-export/hg-fast-export.sh -r /path/to/hg-repo
# Verify import
git log --oneline
git branch -a
git tag -l
# Add remote and push
git remote add origin https://github.com/user/repo.git
git push -u origin main
git push --all
git push --tags
Authors mapping:
# Create authors.txt
# Format: hgauthor=Git Author <[email protected]>
cat > authors.txt <<EOF
john=John Doe <[email protected]>
jane=Jane Smith <[email protected]>
bob=Bob Johnson <[email protected]>
EOF
# Use with hg-fast-export
hg-fast-export.sh -r /path/to/hg-repo -A authors.txt
Generate authors file:
# Extract all Mercurial authors
cd /path/to/hg-repo
hg log --template '{author}\n' | sort -u > ../hg-authors.txt
# Create mapping template
while read author; do
# Try to extract email if present
if [[ $author == *"<"* ]]; then
echo "$author=$author"
else
echo "$author=$author <$author@example.com>"
fi
done < ../hg-authors.txt > ../authors.txt
# Edit authors.txt to add proper names and emails
Complete migration script:
#!/bin/bash
# migrate-hg-to-git.sh
HG_REPO="/path/to/hg-repo"
GIT_REPO="/path/to/git-repo"
GIT_REMOTE="https://github.com/user/repo.git"
AUTHORS_FILE="authors.txt"
FAST_EXPORT="/path/to/fast-export"
echo "Starting Mercurial to Git migration..."
# 1. Generate authors file if doesn't exist
if [ ! -f "$AUTHORS_FILE" ]; then
echo "Generating authors file..."
cd "$HG_REPO"
hg log --template '{author}\n' | sort -u | while read author; do
echo "$author=$author <${author}@example.com>"
done > "$AUTHORS_FILE"
echo "Edit $AUTHORS_FILE with correct names and emails, then re-run"
exit 1
fi
# 2. Create empty Git repository
echo "Creating Git repository..."
mkdir -p "$GIT_REPO"
cd "$GIT_REPO"
git init
# 3. Import from Mercurial
echo "Importing from Mercurial..."
"$FAST_EXPORT/hg-fast-export.sh" -r "$HG_REPO" -A "$AUTHORS_FILE"
# 4. Clean up Mercurial tags
echo "Converting tags..."
git for-each-ref refs/tags | while read sha type ref; do
tag=${ref#refs/tags/}
# Remove Mercurial default tag
if [ "$tag" = "tip" ]; then
git tag -d tip
fi
done
# 5. Verify branches
echo "Branches:"
git branch -a
# 6. Verify tags
echo "Tags:"
git tag -l
# 7. Add remote
echo "Adding remote..."
git remote add origin "$GIT_REMOTE"
# 8. Push to Git
echo "Pushing to Git repository..."
git push -u origin main
git push origin --all
git push origin --tags
echo "Migration complete!"
echo "Verify the repository and update team"
Verify migration:
# Compare commit counts
cd /path/to/hg-repo
hg log | grep "changeset:" | wc -l
cd /path/to/git-repo
git log --oneline | wc -l
# Compare branches
hg branches
git branch -a
# Compare tags
hg tags
git tag -l
# Check specific commit
hg log -r <revision>
git show <commit-hash>
Handle Mercurial branches:
# List Mercurial branches
cd /path/to/hg-repo
hg branches
# After migration, Mercurial branches become Git branches
cd /path/to/git-repo
git branch -a
# Rename default branch if needed
git branch -m default main
Incremental migration:
# Initial migration
git clone hg::/path/to/hg-repo git-repo
cd git-repo
# Later, fetch new changes
git pull hg::/path/to/hg-repo
# Or with hg-fast-export
cd git-repo
../fast-export/hg-fast-export.sh -r /path/to/hg-repo --force
Handle subrepositories:
# List Mercurial subrepositories
cd /path/to/hg-repo
cat .hgsub
# Each subrepo needs separate migration
# Then add as Git submodules
cd /path/to/git-repo
git submodule add https://github.com/user/subrepo.git path/to/subrepo
Cleanup after migration:
# Remove Mercurial-specific files
cd git-repo
rm -rf .hg .hgignore .hgtags .hgsub .hgsubstate
# Convert .hgignore to .gitignore
# Mercurial uses regex, Git uses glob patterns
# Manual conversion required
# Example .hgignore
syntax: glob
*.pyc
*.log
# Becomes .gitignore
*.pyc
*.log
git add .gitignore
git commit -m "Add .gitignore converted from .hgignore"
Team transition:
# For team members to switch to Git
# 1. Clone new Git repository
git clone https://github.com/user/repo.git
# 2. Remove old Mercurial checkout
rm -rf old-hg-repo
# 3. Configure Git
git config user.name "Your Name"
git config user.email "[email protected]"
# 4. Learn Git workflow
# - git pull instead of hg pull && hg update
# - git push instead of hg push
# - git checkout -b feature instead of hg branch feature
Comparison and documentation:
# Mercurial to Git Command Mapping
| Mercurial | Git |
|--------------------------|------------------------------|
| hg clone | git clone |
| hg pull && hg update | git pull |
| hg commit | git commit -a |
| hg push | git push |
| hg status | git status |
| hg diff | git diff |
| hg log | git log |
| hg branch feature | git checkout -b feature |
| hg merge | git merge |
| hg rollback | git reset --soft HEAD^ |
| hg branches | git branch |
| hg tags | git tag |
Troubleshooting:
# If migration fails with encoding errors
export PYTHONIOENCODING=utf-8
hg-fast-export.sh -r /path/to/hg-repo
# If large files cause issues
# Remove large files from history first
hg convert --filemap filemap old-repo new-repo
# filemap content:
# exclude path/to/large/file
Verify integrity:
# Check Git repository integrity
cd git-repo
git fsck --full
# Verify all commits are reachable
git log --all --oneline | wc -l
# Check for missing objects
git count-objects -v
Best Practice Note
Use hg-fast-export or git-remote-hg for migration with history preservation. Create authors mapping file for proper Git attribution. Test migration on copy before final conversion. Verify commit counts and history after migration. Remove Mercurial-specific files after conversion. Convert .hgignore to .gitignore manually. Update team documentation with Git workflow. Train team on Git commands and concepts. This is how we migrate from Mercurial to Git—complete history preservation, proper author mapping, and team training ensuring smooth transition to Git with full repository integrity.



