#!/bin/bash # Convert an SVN dumpfile into a Git repository. (Note: an # "SVN dumpfile" is a file created with 'svnadmin dump'.) # # ########################################################### # #### ##### # #### HEY, INSTEAD OF USING THIS SCRIPT, JUST USE ##### # #### JOHN ALBIN'S 'git-svn-migrate' SCRIPTS, AT: ##### # #### ##### # #### https://john.albin.net/git/git-svn-migrate ##### # #### https://github.com/JohnAlbin/git-svn-migrate ##### # #### ##### # #### HE'S ALREADY SOLVED EVERYTHING. JUST USE HIS. ##### # #### ##### # ########################################################### # # This script isn't even fully working yet, due to an unfixed # bug; search for "TODO: THIS IS WHERE THE PROBLEM IS" below # for details. # # ########################################################### # # This requires the 'git-svn' package to be installed. If you don't # know whether you have it or not, run the command 'git svn help'. If # you get some help output, then all is good. If you don't, then do # 'sudo apt-get install git-svn' (on Debian-flavored systems). # # Usage: # # $ ./svndump2git foo.dump # # That produces Git repository 'git-foo-repos'. Or it would, if it # weren't for the above-mentioned bug. I was writing this to help # Leonard Richardson with some repository conversions, with guidance # from https://john.albin.net/git/convert-subversion-to-git/, and then # Leonard and I discovered that at the end of that blog post the the # author links to https://john.albin.net/git/git-svn-migrate, where # he's scripted everything up. # License: Let's say GNU GPL v3 for now. But again, don't use this, # because it's not ready. Use John Albin's git-svn-migrate scripts. # Historically this is "master", but lately there has been momentum # towards "main" instead, which is why this is adjustable here. GIT_DEFAULT_BRANCH_NAME="master" if [ -z "${1}" ]; then echo "ERROR: SVN dumpfile argument required; should end with \".dump\"" >&2 exit 1 fi SVN_DUMPFILE="${1}" REPOS_BASENAME=`basename "${1}" .dump` if [ "${SVN_DUMPFILE}" = "${REPOS_BASENAME}" ]; then echo "ERROR: SVN dumpfile name must end with \".dump\"" >&2 exit 1 fi SVN_REPOS_PATH=svn-"${REPOS_BASENAME}-repos" SVN_REPOS_URL="file://`pwd`/${SVN_REPOS_PATH}" GIT_REPOS_PATH=git-"${REPOS_BASENAME}-repos" AUTHORS_TRANSFORM_FILE="${REPOS_BASENAME}"-authors-transform.txt # Make sure neither repository exists yet. SOMETHING_IS_IN_THE_WAY="no" if [ -f "${SVN_REPOS_PATH}" -o -d "${SVN_REPOS_PATH}" ]; then echo "'${SVN_REPOS_PATH}' exists. Please move it out of the way." >&2 SOMETHING_IS_IN_THE_WAY="yes" fi if [ -f "${GIT_REPOS_PATH}" -o -d "${GIT_REPOS_PATH}" ]; then echo "'${GIT_REPOS_PATH}' exists. Please move it out of the way." >&2 SOMETHING_IS_IN_THE_WAY="yes" fi if [ "${SOMETHING_IS_IN_THE_WAY}" != "no" ]; then exit 1 fi svnadmin create "${SVN_REPOS_PATH}" # You could add '--quiet' here to suppress the noisy # revision-by-revision progress output. svnadmin load "${SVN_REPOS_PATH}" < "${SVN_DUMPFILE}" # Create the authors-transform file. svn log -q "${SVN_REPOS_URL}" \ | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' \ | sort -u \ > ${AUTHORS_TRANSFORM_FILE} echo "" echo "Now I will pause while you edit \"${AUTHORS_TRANSFORM_FILE}\"" echo "to supply real names and email addresses for as many of the committers" echo "as you can. After you're done, press Return to continue the conversion." echo "" read # Start by creating a non-bare temporary Git repository, in which we will # set up .gitignore based on svn:ignore properties. rm -rf "${GIT_REPOS_PATH}-tmp" git svn clone "${SVN_REPOS_URL}" --no-metadata -A "${AUTHORS_TRANSFORM_FILE}" --stdlayout "${GIT_REPOS_PATH}-tmp" # Now set up the ignores. # # ##### TODO: THIS IS WHERE THE PROBLEM IS ##### # # The command 'git svn show-ignore > .gitignore' below produces an # error: # # config --get svn-remote.svn.fetch :refs/remotes/git-svn$: command returned error: 1 # # I don't know the cause, and as of 2020-06-24 haven't debugged it, # because then Leonard and I discovered that John Albin had scripted # this all already, so why are you even here? Just go use John's. (cd "${GIT_REPOS_PATH}-tmp"; \ git svn show-ignore > .gitignore; \ git add .gitignore; \ git commit -m 'Convert svn:ignore properties to .gitignore.'; \ ) # Create the *real* repository, as a bare repository, and # set its default branch to match SVN's "trunk" branch name. git init --bare ${GIT_REPOS_PATH} (cd ${GIT_REPOS_PATH}; \ git symbolic-ref HEAD "refs/heads/trunk"; \ ) # Push everything from the tmp repository to the real one. (cd "${GIT_REPOS_PATH}-tmp"; \ git remote add bare "../${GIT_REPOS_PATH}"; \ git config remote.bare.push 'refs/remotes/*:refs/heads/*'; \ git push bare; \ ) # We're done with the tmp repository. rm -rf "${GIT_REPOS_PATH}-tmp" # Rename trunk to the Git default branch name. (cd "${GIT_REPOS_PATH}"; \ git branch -m trunk "${GIT_DEFAULT_BRANCH_NAME}"; \ ) # This part is totally untested. cd "${GIT_REPOS_PATH}" git for-each-ref --format='%(refname)' refs/heads/tags | cut -d / -f 4 | while read ref do git tag "$ref" "refs/heads/tags/$ref"; git branch -D "tags/$ref"; done cd ..