Skip to content

Instantly share code, notes, and snippets.

@danielhanold
Created February 24, 2020 15:20
Show Gist options
  • Save danielhanold/1bf84fdf9c27961fc4a69e5683542ee3 to your computer and use it in GitHub Desktop.
Save danielhanold/1bf84fdf9c27961fc4a69e5683542ee3 to your computer and use it in GitHub Desktop.
Convert SVN repos to Git and upload to GitHub
#! /bin/bash
# Determine target directory.
TARGET_DIR=$1
# Determine if this is the final processing, i.e. create all Git branches,
# tags, and garbage-collect.
PROCESS_MODE=${2:-FETCH_ONLY}
# Determine default domain for unmapped authors.
EMAIL_DOMAIN=${3:-example.com}
# Set authors file location.
AUTHORS_FILE=$4
# Define current directory as location for authors program.
AUTHORS_PROGRAM_DEFAULT="$(pwd)/authors-prog.sh"
# Set authors program for any unmapped authors.
AUTHORS_PROGRAM=${5:-$AUTHORS_PROGRAM_DEFAULT}
# Optionally, set a starting revision to reduce the size of the Git repository.
STARTING_REVISION=${6:-0}
# Optionally, disable deleting the temporary directory for uploading to GitHub.
DELETE_TEMP_DIRECTORY=${7:-TRUE}
# Determine log filename.
SCRIPT_START=$(date +%s)
echo "Process Mode: $PROCESS_MODE"
echo "Target Directory: $TARGET_DIR"
echo "Authors Program: $AUTHORS_PROGRAM"
echo "Email Domain: $EMAIL_DOMAIN"
echo "Authors File: $AUTHORS_FILE"
echo "Script start (UNIX): $SCRIPT_START ($(date))"
# Switch to target directory.
cd $TARGET_DIR
# Kick off import.
if [ -f "$AUTHORS_FILE" ]
then
export GIT_EMAIL_DOMAIN=$EMAIL_DOMAIN
git svn fetch \
--authors-file=$AUTHORS_FILE \
--authors-prog=$AUTHORS_PROGRAM \
--revision=$STARTING_REVISION:HEAD
else
git svn fetch \
--revision=$STARTING_REVISION:HEAD
fi
# If this isn't the first time this script runs, fast-forward the actual commits.
git svn rebase
prepare_for_github() {
local GIT_DIR=$1
local PREVIOUS_DIR=$(pwd)
echo "Switching into $1"
cd $1
# Create a true Git branch for every "ref" that's not a tag.
# Exclude: master branch, trunk, branches starting with "trunk", branches containing special character "%"
git for-each-ref --format="%(refname:short)" refs/remotes/origin | sed 's#origin/##' | grep -v '^tags' | grep -v '^trunk' | grep -v 'master' | grep -v '%' |
while read BRANCH_NAME
do
echo "Create branch name: $BRANCH_NAME"
git branch $BRANCH_NAME origin/$BRANCH_NAME
done
# Create true Git tags for all tags.
# Exclude: the "origin/tags/tags" tag
git for-each-ref --format="%(refname:short)" refs/remotes/origin/tags/ | grep -v 'origin/tags/tags' |
while read tag
do
GIT_COMMITTER_DATE="$(git log -1 --pretty=format:"%ad" "$tag")"
GIT_COMMITTER_EMAIL="$(git log -1 --pretty=format:"%ce" "$tag")"
GIT_COMMITTER_NAME="$(git log -1 --pretty=format:"%cn" "$tag")"
git tag -a -m "$(git for-each-ref --format="%(contents)" "$tag")" "$(echo "$tag" | sed 's#svn/tags/##')" "$tag" || exit 1
done
# Delete all local branches that have already been merged into master,
# i.e. are neither ahead or behind master.
git branch --merged master | grep -v 'master$' |
while read merged_branch_name
do
git branch -d $merged_branch_name
done
# Garbage-collect
git svn gc
git gc --aggressiv
# Switch back to previous directory.
cd $PREVIOUS_DIR
}
if [ "$PROCESS_MODE" == "PREPARE_CURRENT_FOR_GITHUB" ]
then
prepare_for_github $TARGET_DIR
elif [ "$PROCESS_MODE" == "CREATE_TEMP_AND_PUSH_TO_GITHUB" ]
then
# Create temporary directory and process files in directory.
REPO_TEMP=$(mktemp -d)
# Delete temporary files when program exits.
if [ "$DELETE_TEMP_DIRECTORY" == "TRUE" ]
then
echo "Temporary directory $REPO_TEMP will be deleted."
trap "exit 1" HUP INT PIPE QUIT TERM
trap "rm -rf $REPO_TEMP" EXIT
else
echo "Temporary directory $REPO_TEMP will not be deleted."
fi
# Rsync all files into separate directory
rsync -a --stats ${TARGET_DIR}/ ${REPO_TEMP}
# Create all branches in temporary directory.
prepare_for_github ${REPO_TEMP}
# Upload everything from temporary directory if
# 1. Key agent has at least 1 identity and is running and
# 2. Git remote is added to the repo
if ssh-add -l && git remote show origin
then
git -C $REPO_TEMP push --all --force
git -C $REPO_TEMP push --tags --force
else
echo "Either remote is not set up successfully or SSH key is not working."
fi
fi
# Log end date.
SCRIPT_END=$(date +%s)
echo "Script end (UNIX): $SCRIPT_END ($(date))"
SCRIPT_DURATION=$((($SCRIPT_END-$SCRIPT_START)/60))
echo "Migration took $SCRIPT_DURATION minutes."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment