Skip to content

Instantly share code, notes, and snippets.

@marcows
Last active November 13, 2020 12:22
Show Gist options
  • Save marcows/49680ecb1e89a808c050 to your computer and use it in GitHub Desktop.
Save marcows/49680ecb1e89a808c050 to your computer and use it in GitHub Desktop.
Create a git repository on top of a Subversion working copy.
#!/bin/sh
# Create a git repository on top of a Subversion working copy (all files added,
# including files in different SVN repositories checked out via svn:externals
# property). Additionally .gitginore files are added according to svn:ignore
# properties.
# Used for local git workflow ability with official SVN repo. Alternative to
# 'git-svn' with less possibilities, but faster and without compatibility
# concerns. The git repo is meant to be a throw-away repository.
#
# This is a Q&D script, using git porcelain rather than plumbing and other
# quirks.
#
# Limitations/TODO:
# - Cleanup is not yet automated.
# - Maybe use Subversion API and libgit2?
#
# Usage:
# - Put this script into a directory included in the PATH environment variable
# so that 'git' can find it and rename it to 'git-ontop'.
# - Invoke 'git ontop' without parameters (parameters/commands will be added in
# the future).
svn info >/dev/null || exit 1
if [ $(LANG=C svn status | grep -v "^Performing\|^?\|^X\|^$\|^.$" | wc -l) -gt 0 ]
then
echo "error: Subversion working copy dirty"
exit 1
fi
git init
# we do not care about line endings, just keep them as is to avoid hassle
git config --local core.autocrlf false
# creation of ignorefiles
echo -e "# generated by git-ontop\n/.gitignore" > .gitignore
# svn propget output looks like this (including the leading spaces between blocks):
# Properties on 'Source':
# svn:ignore
# Main.o
# Module.o
#
LANG=C svn propget -Rv svn:ignore | awk ' \
/^Properties on/ { \
dir = $3; \
gsub("^.|.:\r?$", "", dir); \
ignorefile = dir "/.gitignore"; \
if (ignorefile != "/.gitignore") \
print "# generated by git-ontop\n/.gitignore" > ignorefile; \
} \
/^ [^ ]/ { \
untrackedfile = $1; \
if (ignorefile != "/.gitignore") \
print "/" untrackedfile >> ignorefile; \
} \
'
# global ignores
echo ".svn/" >> .gitignore
# add all files belonging to the Subversion repository
# spaces in filenames are handled
# do not pass all files in one invocation to prevent 'git add' failing: /libexec/git-core/git: Bad file number
IFS=$'\n'
FILES_PACKET=()
CNT=0
for i in $(LANG=C svn status -v | grep -v "^Performing\|^?\|^X\|^$\|^.$" | awk '{ if ($4 != ".") { $1=$2=$3=""; sub(/^ +/, ""); print $0 } }')
do
if [ ! -d "$i" ]
then
FILES_PACKET+=("$i")
CNT=$((CNT + 1))
if [ $CNT -gt 100 ]
then
git add -f ${FILES_PACKET[@]}
FILES_PACKET=()
CNT=0
fi
fi
done
git add -f ${FILES_PACKET[@]}
git add -u
git commit -m"SVN revision $(LANG=C svn info | awk '/^Revision:/ { print $2 }')"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment