Skip to content

Instantly share code, notes, and snippets.

@allen-ball
Last active February 13, 2022 07:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save allen-ball/90c2b14ac640ac397d8453c33b96c985 to your computer and use it in GitHub Desktop.
Save allen-ball/90c2b14ac640ac397d8453c33b96c985 to your computer and use it in GitHub Desktop.
#!/bin/bash
# ----------------------------------------------------------------------------
# SVN-to-GitHub.bash
# ----------------------------------------------------------------------------
export SVNREPO="$1"
export GITPERLLIB=/usr/local/Cellar/git/2.35.1/share/perl5:/usr/local/lib/perl5/site_perl/5.30.3/darwin-thread-multi-2level
SOURCE=${BASH_SOURCE[0]}
while [ -h "${SOURCE}" ]; do
DIR=$(cd -P "$( dirname "${SOURCE}" )" >/dev/null 2>&1 && pwd)
SOURCE=$(readlink "${SOURCE}")
[[ ${SOURCE} != /* ]] && SOURCE=${DIR}/${SOURCE}
done
DIR=$(cd -P "$(dirname "${SOURCE}")" >/dev/null 2>&1 && pwd)
url="$(svn info --show-item url ${SVNREPO})"
export SVNURL="${url}"
export SVNURL="${SVNURL%/trunk}"
export SVNURL="${SVNURL%/branches}"
export SVNURL="${SVNURL%/tags}"
if [ "${SVNURL}" != "${url}" ]; then
export STDLAYOUT=true
else
export STDLAYOUT=false
fi
unset url
export REPONAME="${SVNURL##*/}"
export SVNCLONEREPO="$(pwd)/${REPONAME}-clone"
export GITREPO="$(pwd)/${REPONAME}.git"
#svn log -q ${SVNURL} \
# | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' \
# | sort -u > "${DIR}/authors-file.txt"
#sed -i '' 's/<ball>/Allen D. Ball <ball@hcf.dev>/g' "${DIR}/authors-file.txt"
#
# Create clone of Subversion repository:
#
defaultBranch="$(git config --global --get init.defaultBranch)"
git config --global init.defaultBranch "${defaultBranch:=trunk}"
mkdir ${SVNCLONEREPO}
if [ "${STDLAYOUT}" = true ]; then
layoutargs="--stdlayout"
fi
git svn clone --prefix svn/ --authors-file ${DIR}/authors-file.txt \
${layoutargs} ${SVNURL} ${SVNCLONEREPO}
#
# Add .gitignore
#
cd ${SVNCLONEREPO}
git svn show-ignore > .gitignore
git add .gitignore
git commit --message "Convert svn:ignore properties to .gitignore."
#
# Create new bare repository and push
#
git init --bare ${GITREPO}
cd ${GITREPO}
if [ "${STDLAYOUT}" = true ]; then
git symbolic-ref HEAD refs/heads/${defaultBranch}
fi
cd ${SVNCLONEREPO}
git remote add bare ${GITREPO}
git config remote.bare.push 'refs/remotes/*:refs/heads/*'
git push bare
#
# Rename tags and branches
#
cd ${GITREPO}
branches=$(git branch --list)
for branch in ${branches}; do
target="${branch##*/}"
case ${target} in
([0-9]*)
target="v${target}"
;;
(*)
;;
esac
case ${branch} in
(${defaultBranch})
;;
(svn/git-svn | svn/${defaultBranch})
git branch --move "${branch}" "${defaultBranch}"
;;
(svn/*@*)
git branch --delete --force "${branch}"
;;
(svn/tags/*)
git branch --move "${branch}" "${target}"
;;
(svn/*)
git branch --delete --force "${branch}"
;;
(*)
git branch --delete --force "${branch}"
;;
esac
done
#
# Convert bare repository to regular repository
#
cd ${GITREPO}
mkdir .git
mv * .git
git config --local --bool core.bare false
git reset --hard
git gc --aggressive
git checkout "${defaultBranch}"
#
# Create a gh-pages (orphan) branch
#
cd ${GITREPO}
git checkout --orphan gh-pages
git rm -rf .
cat > .gitignore <<EOF
_site
.sass-cache
.jekyll-cache
.jekyll-metadata
vendor
EOF
git add .gitignore
git commit --all --message "Created gh-pages branch."
#
# Push to GitHub
#
export GITHUB_USER="$(gh api /user | jq -r .login)"
cd ${GITREPO}
gh repo create --private "${GITHUB_USER}/${REPONAME}"
git remote add origin "https://github.com/${GITHUB_USER}/${REPONAME}.git"
git push origin --all
git push origin --tags

SVN to GitHub Migration Script

Before running, create an authors-file.txt in the same directory as the script:

svn log -q ${SVNURL} \
    | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' \
    | sort -u > authors-file.txt

To get something like:

ball = ball <ball>

And then replace with actual e'mail addresses:

sed -i '' 's/<ball>/Allen D. Ball <ball@hcf.dev>/g' authors-file.txt
ball = ball Allen D. Ball <ball@hcf.dev>

Make sure git and gh are configured. To run:

bash SVN-to-GitHub.bash [SVNURL | local copy]

Argument can either be an SVN repository URL or a working directory. The script attempts to detect if the repository is in the "standard layout." To aid the detection process when specifying a URL, append /trunk if the repository is in the standard layout.

For repositories in "standard layout," branches are ultimately ignored but tags are preserved as git branches. An orphaned gh-pages branch is also created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment