Skip to content

Instantly share code, notes, and snippets.

@blitzrk
Last active March 11, 2016 19:23
Show Gist options
  • Save blitzrk/600e004c0bfb246dfe21 to your computer and use it in GitHub Desktop.
Save blitzrk/600e004c0bfb246dfe21 to your computer and use it in GitHub Desktop.
Bash (>=4.0) script for syncing SVN to git repo
#!/bin/bash
usage="\
Sync svn repo to git repo in working dir or PATH
Usage: svn-sync.sh [OPTION]... [PATH]
Options:
-h, --help: Show this help and exit
-t, --tags: Import tags as well as branches
-v, --verbose: Show verbose output
-vv: Increase verbosity
NOTE: This tool is meant to be used after the initial 'git svn clone'
to keep the git repository synced. During this period of syncing, do
NOT make any commits to the git repo.
"
ref=`git rev-parse --abbrev-ref HEAD`
if [ "$ref" == "HEAD" ]
then
ref=`git describe --all 2>/dev/null || git show-ref -s --head HEAD` [57/656]
fi
# Parse arguments
_T=0
_V=0
_PATH="."
while [ "$#" -gt 0 ]
do
args=$1
while [ -n "${args[0]}" ]; do
arg=${args[0]}
case $arg in
--help|-h)
echo "$usage"
exit 0
;;
-[^-]*)
if [ -n "${arg//[vt-]}" ]; then
echo "Unknown option(s) '${arg//[vt-]}'"
exit 1
elif [ ${#arg} -gt 2 ]; then
args=( `echo $arg | grep -o '[^-]' | awk '{print "-" $1}'` )
continue
fi
;;&
--tags|-t)
_T=1
;;
--verbose|-v)
_V=`expr $_V + 1`
;;
*)
if [[ "$arg" = --* ]]; then
echo "Unknown option '${arg//-}'"
exit 1
fi
;;&
*)
if [ ! -d $arg ]; then
echo "'$arg' is not a directory"
exit 2
else
_PATH=$1
fi
;;
esac
args=("${args[@]:1}")
done
shift
done
# Fetch updates
pushd $_PATH >/dev/null
git svn fetch `test $_V -lt 2 && echo -q` || { echo "Fetch failed. Exiting."; exit 1; }
# Force update all branches, importing if necessary
echo "Importing branches"
test $_V -ge 1 && echo
git branch -r |
grep -v '/tags/' |
while read -r remote
do
local=${remote#*/}
if [ "$local" == "trunk" ]; then
local=master
fi
if [[ ! `git branch -q --list $local` ]]; then
test $_V -ge 1 && echo "Importing $remote"
git checkout -b $local $remote
elif [ `git show-ref -s refs/heads/$local` != `git show-ref -s refs/remotes/$remote` ]; then
test $_V -ge 1 && echo "Updating $local"
git checkout -q $local
git config merge.renamelimit 9999999
git merge -q -X theirs --no-commit $remote
git reset -q --hard $remote # Just in case a merge commit happened (manually)
git config --unset merge.renamelimit
else
test $_V -ge 2 && echo "Skipping $local - already up to date"
fi
done
test $_V -ge 1 && echo
if [ $_T -eq 1 ]
then
echo "Importing tags"
test $_V -ge 1 && echo
git for-each-ref refs/remotes/origin/tags |
sed 's/\t/ /' |
cut -d ' ' -f 1,3 --output-delimiter ' ' |
sed 's|refs/remotes/||' |
while read -r line; do
commit=${line##* }
tag=${line#*tags/}
if git tag -l | grep ^$tag$ >/dev/null; then
test $_V -ge 2 && echo "Skipping $tag"
else
test $_V -ge 1 && echo "Importing $tag"
git checkout -q $commit && git tag $tag >/dev/null
fi
done
test $_V -ge 1 && echo
fi
echo "Returning to $ref"
git checkout -q $ref
popd >/dev/null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment