From: Eddy Petrisor <eddy@xxxxxxxxxxxxxxxx> Current functionality: - fetches all the externals of an already svn-fetched repo - support for svn:externals refresh - if the location of the external has changed, the current working copy will be placed aside and a new directory will be created instead - if the remote URI is the same (maybe a verison bump, there will be a 'git svn rebase' - remove support (useful for testing purposes or clean restarts) - avoid zombie externals at all costs - in some repos empty svn:externals might exist; svn ignores such externals, so git should do the same TODO: - take into account the revision of an external, if it exists - do not do deep svn cloning, to avoid legthy operations, just pull HEAD - add shallow copies to git svn repos (one revision should be enough for most externals) - use submodules for externals --- .gitignore | 1 + Makefile | 1 + git-svn-externals.sh | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 0 deletions(-) create mode 100755 git-svn-externals.sh diff --git a/.gitignore b/.gitignore index bbaf9de..cd2c47d 100644 --- a/.gitignore +++ b/.gitignore @@ -123,6 +123,7 @@ git-status git-stripspace git-submodule git-svn +git-svn-externals git-symbolic-ref git-tag git-tar-tree diff --git a/Makefile b/Makefile index bf400e6..b130244 100644 --- a/Makefile +++ b/Makefile @@ -265,6 +265,7 @@ SCRIPT_SH += git-sh-setup.sh SCRIPT_SH += git-stash.sh SCRIPT_SH += git-submodule.sh SCRIPT_SH += git-web--browse.sh +SCRIPT_SH += git-svn-externals.sh SCRIPT_PERL += git-add--interactive.perl SCRIPT_PERL += git-archimport.perl diff --git a/git-svn-externals.sh b/git-svn-externals.sh new file mode 100755 index 0000000..38b7af6 --- /dev/null +++ b/git-svn-externals.sh @@ -0,0 +1,158 @@ +#!/bin/sh + +set -e + +GIT_SVN_LAST_DIR="$(pwd)" +trap "cd '$GIT_SVN_LAST_DIR'" INT EXIT KILL + + +USAGE='[help|init|refresh|show]' + +LONG_USAGE='git svn externals help + print this long help message. +git svn externals init [<pathspec>...] + pull all externals according to current repo state. +git svn externals refresh [<pathspec>...] + removes current externals and repulls them. +' + + +SUBDIRECTORY_OK=Sometimes +OPTIONS_SPEC= +. git-sh-setup +cd_to_toplevel +# this should never fail +require_work_tree + + +GIT_SVN_TOP_DIR="$(pwd)" + +svn_revision_to_numrevision () +#$1 - repository URI +#$2 - the revision to be transformed +{ + local REVSPEC + [ "$2" ] && REVSPEC="-r $2" || REVSPEC='' + [ "$1" ] || die "Internal error: no repository given in svn_revision_to_numrevision" + LANG=C svn info "$1" "$REVSPEC" | grep 'Revision' | cut -f 2 -d ':' | sed 's#^\ \ *##g' +} + +prune_inital_slashes () +{ + echo "$1" | sed 's#^//*##g' +} + +git_svn_externals_remove () +{ + local LASTDIR="$(pwd)" + cd_to_toplevel && TOPLEVELDIR="$(pwd)" + git svn show-externals | grep -vE '^(#.*|)$' | while read EXT_DIR REV EXT_SRC ; do + if [ -z "$REV" ] ; then + echo "Skipping illegal external '$EXT_DIR' which has no value" >&2 + continue + fi + EXT_DIR="$(prune_inital_slashes "$EXT_DIR")" + + if [ -z "$EXT_SRC" ] ; then + EXT_SRC="$REV" + REV="-rHEAD" + fi + REV=${REV#-r} + + echo "Removing local copy for external '$EXT_DIR' ( $EXT_SRC@$REV )" + rm -fr "$EXT_DIR" + done + + cd "$LASTDIR" +} + +git_svn_init_dir_repo () +# assumes is ran from the parent dir of the repo +# $1 EXT_DIR +# $2 EXT_SRC +# $3 REV +{ + local LASTDIR="$(pwd)" + + mkdir -p "$1" + cd "$1" + git svn init "$2" + git svn fetch + + cd "$LASTDIR" +} + +git_svn_externals_refresh_external () +#$1 directory where the external is locally +#$2 remote url +#$3 revision at which the external is pinned at +{ + local LASTDIR="$GIT_SVN_TOP_DIR" + + local EXT_SRC="$2" + local EXT_DIR="$1" + + if cd "$EXT_DIR" 2>/dev/null; then + local OLDDIREXISTS=yes + local OLD_EXT_SRC=$(git config --get svn-remote.svn.url) + local OLD_EXT_REV=$(git config --get svn-remote.svn.revision || svn_revision_to_numrevision $OLD_EXT_SRC HEAD) + cd - + else + local OLDDIREXISTS=no + local OLD_EXT_SRC="${EXT_SRC}" + local OLD_EXT_REV=$(svn_revision_to_numrevision $EXT_SRC HEAD) + fi + + if [ "$OLD_EXT_SRC" != "$EXT_SRC" ] ; then + echo "External URI definition changed. Moving away the old repo and pulling a new one." + cd "$LASTDIR" + local SUBDIR="$(basename "$EXT_DIR")" + local DIRNAME="$(dirname "$EXT_DIR")" + NEWDIR="$(mktemp -p "$DIRNAME" "$SUBDIR.obsolete.XXXXXX")" && rm -f "$NEWDIR" + mv "$EXT_DIR" "$NEWDIR" + echo " Old copy moved to '$NEWDIR'." + git_svn_init_dir_repo "$EXT_DIR" "$EXT_SRC" "$REV" + elif [ "$OLDDIREXISTS" = "no" ] ; then + git_svn_init_dir_repo "$EXT_DIR" "$EXT_SRC" "$REV" + else + cd "$EXT_DIR" + git svn rebase + fi + + cd "$LASTDIR" + return 0 +} + +git_svn_externals_refresh () +{ + git svn show-externals | grep -vE '^(#.*|)$' | while read EXT_DIR REV EXT_SRC ; do + if [ -z "$REV" ] ; then + echo "Skipping illegal external '$EXT_DIR' which has no value" >&2 + continue + fi + EXT_DIR="$(prune_inital_slashes "$EXT_DIR")" + + if [ -z "$EXT_SRC" ] ; then + EXT_SRC="$REV" + REV="-rHEAD" + fi + REV=${REV#-r} + + echo "Refreshing local copy for external '$EXT_DIR' ( $EXT_SRC@$REV )" + cd "$GIT_SVN_TOP_DIR" + git_svn_externals_refresh_external "$EXT_DIR" "$EXT_SRC" "$REV" + done + + cd "$GIT_SVN_TOP_DIR" +} + + +case $1 in + --remove) + git_svn_externals_remove + ;; + -r|--refresh|*) + git_svn_externals_refresh + ;; +esac + -- 1.5.6.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html