git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] First crude implementation of git-svn-externals

From
Eddy Petrișor <eddy.petrisor@gmail.com>
Date
Aug 29, 2008, 00:02 UTC
Message-ID
<1219968179-14156-2-git-send-email-eddy.petrisor@gmail.com>
In-Reply-To
<1219968179-14156-1-git-send-email-eddy.petrisor@gmail.com>
From: Eddy Petrisor <eddy@epetrisor.dsd.ro>
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
Previous: Eddy PetrișorNext: Eddy Petrișor
Message 3 of 9 in “git-svn-externals PoC (in a sh script)”
  1. 0/3 git-svn-externals PoC (in a sh script)Eddy Petrișor, Aug 29, 2008
  2. git svn: should not display zombie externalsEddy Petrișor, Aug 29, 2008
  3. First crude implementation of git-svn-externalsEddy Petrișor, Aug 29, 2008
  4. added a test frame for git-svn-externals.shEddy Petrișor, Aug 29, 2008
  5. Eddy PetrișorAug 29, 2008
  6. Eric WongAug 29, 2008
  7. RFH: git-svn and submodulesEric Wong, Sep 1, 2008
  8. Eddy PetrișorSep 10, 2008
  9. Eddy PetrișorSep 10, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.