Skip to content

Instantly share code, notes, and snippets.

@CJHarmath
Created November 16, 2024 04:44
Show Gist options
  • Save CJHarmath/ff1af5a66b4582541b4bb997166d998b to your computer and use it in GitHub Desktop.
Save CJHarmath/ff1af5a66b4582541b4bb997166d998b to your computer and use it in GitHub Desktop.
svn to git migration
#!/bin/bash
# SVN to Git Migration Script
# ==========================
#
# This script performs a complete migration from SVN to Git while preserving
# history, usernames, branches, and tags.
#
# Usage:
# ./svn-to-git-migrate.sh <SVN_REPO_URL> <GIT_REPO_NAME>
#
# Examples:
# ./svn-to-git-migrate.sh http://svn.example.com/repo my-project
# ./svn-to-git-migrate.sh svn://svn.example.com/repo/trunk project-name
# ./svn-to-git-migrate.sh file:///path/to/local/svn/repo local-project
#
# Prerequisites:
# - git
# - git-svn
# - svn
#
# The script will:
# 1. Create an authors mapping file (authors.txt)
# 2. Convert SVN history to Git format
# 3. Convert SVN branches and tags to Git format
# 4. Create a server-ready Git repository
# 5. Provide instructions for pushing to GitHub/GitLab
#
# Important Notes:
# - Review authors.txt before proceeding with migration
# - Ensure sufficient disk space (at least 2x the SVN repository size)
# - Large repositories may take several hours to migrate
# - The script assumes standard SVN layout (trunk/branches/tags)
# - Have your GitHub/GitLab repository URL ready for the final push
#
# Output:
# - authors.txt: SVN to Git username mapping
# - migration.log: Detailed migration log
# - temp_migration/: Temporary working directory
# - <GIT_REPO_NAME>.git/: Final server-ready Git repository with complete history
#
# Post-Migration:
# The script will provide instructions for pushing to GitHub/GitLab:
# 1. Create an empty repository on GitHub/GitLab (DO NOT initialize with README)
# 2. Follow the provided commands to push all branches and tags
#
# Example authors.txt format:
# svnuser = Git User <[email protected]>
# john = John Doe <[email protected]>
#
set -e
SVN_REPO_URL=""
GIT_REPO_NAME=""
AUTHORS_FILE="authors.txt"
TEMP_DIR="temp_migration"
LOG_FILE="migration.log"
# Function to show usage
show_usage() {
grep '^#' "$0" | tail -n +2 | cut -c 3-
exit 1
}
# Function to log messages
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Function to verify prerequisites
check_prerequisites() {
log_message "Checking prerequisites..."
# Check for required commands
commands=("git" "git-svn" "svn")
for cmd in "${commands[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log_message "ERROR: $cmd is not installed"
exit 1
fi
done
}
# Function to create authors file
create_authors_file() {
log_message "Creating authors mapping file..."
if [ -f "$AUTHORS_FILE" ]; then
log_message "Authors file already exists, skipping..."
return
}
svn log -q "$SVN_REPO_URL" | \
awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2}' | \
sort -u | \
while read -r author; do
echo "$author = $author <[email protected]>"
done > "$AUTHORS_FILE"
log_message "AUTHORS_FILE created. Please review and update email addresses!"
exit 1
}
# Function to display post-migration instructions
show_post_migration_instructions() {
local repo_name="$1"
echo
echo "=== Post-Migration Instructions ==="
echo
echo "Your repository is ready! Follow these steps to push to GitHub or GitLab:"
echo
echo "1. Create a new empty repository on GitHub or GitLab"
echo " - DO NOT initialize it with a README, license, or .gitignore"
echo " - GitHub: Click 'New' at github.com/yourname?tab=repositories"
echo " - GitLab: Click 'New project' at gitlab.com/projects/new"
echo
echo "2. Push the repository (replace REMOTE_URL with your GitHub/GitLab URL):"
echo
echo " cd ${repo_name}.git"
echo " # For GitHub:"
echo " git remote add origin https://github.com/YOUR_USERNAME/${repo_name}.git"
echo " # OR for GitLab:"
echo " git remote add origin https://gitlab.com/YOUR_USERNAME/${repo_name}.git"
echo
echo " # Push all branches and tags:"
echo " git push origin --all"
echo " git push origin --tags"
echo
echo "3. Verify the migration:"
echo " - Check the repository on GitHub/GitLab"
echo " - Verify branches and tags are present"
echo " - Review commit history"
echo " - Clone a fresh copy and check the contents:"
echo " git clone https://github.com/YOUR_USERNAME/${repo_name}.git"
echo
echo "4. Clean up local migration files (optional):"
echo " cd .."
echo " rm -rf temp_migration"
echo " # Keep ${repo_name}.git if you want a local backup"
echo
echo "Migration log is available in: migration.log"
echo
}
# Function to perform the migration
perform_migration() {
log_message "Starting migration process..."
# Create and enter temporary directory
mkdir -p "$TEMP_DIR"
cd "$TEMP_DIR"
# Initialize git-svn
log_message "Initializing git-svn..."
git svn init "$SVN_REPO_URL" --no-metadata \
--authors-file="../$AUTHORS_FILE" \
--trunk=trunk \
--tags=tags \
--branches=branches \
--prefix=origin/
# Fetch SVN repository
log_message "Fetching SVN repository (this may take a while)..."
git svn fetch
# Fix tags
log_message "Converting SVN tags to Git tags..."
git for-each-ref refs/remotes/origin/tags | cut -d / -f 5- | \
while read -r tag; do
git tag "$tag" "origin/tags/$tag^" || true
git branch -r -d "origin/tags/$tag" || true
done
# Fix branches
log_message "Converting SVN branches to Git branches..."
git for-each-ref refs/remotes/origin | cut -d / -f 4- | \
while read -r branch; do
if [ "$branch" != "trunk" ]; then
git branch "$branch" "refs/remotes/origin/$branch" || true
git branch -r -d "origin/$branch" || true
fi
done
# Create master from trunk
log_message "Creating master branch from trunk..."
git branch -m trunk master
# Clean up
log_message "Cleaning up..."
git gc --aggressive
git prune
# Create server-ready repository
log_message "Creating server-ready repository with complete history..."
cd ..
git clone --bare "$TEMP_DIR" "$GIT_REPO_NAME.git"
# Verify repository integrity
cd "$GIT_REPO_NAME.git"
log_message "Verifying repository integrity..."
git fsck --full
log_message "Migration completed successfully! Repository is ready for GitHub/GitLab."
# Return to original directory
cd ..
# Show instructions for pushing to GitHub/GitLab
show_post_migration_instructions "$GIT_REPO_NAME"
}
# Main execution
main() {
# Show usage if --help flag is passed or no arguments provided
if [ "$1" = "--help" ] || [ "$1" = "-h" ] || [ -z "$1" ] || [ -z "$2" ]; then
show_usage
fi
SVN_REPO_URL="$1"
GIT_REPO_NAME="$2"
# Initialize log file
echo "=== Migration Log Started $(date) ===" > "$LOG_FILE"
check_prerequisites
create_authors_file
perform_migration
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment