summaryrefslogtreecommitdiff
path: root/git-submodule.sh
diff options
context:
space:
mode:
Diffstat (limited to 'git-submodule.sh')
-rwxr-xr-xgit-submodule.sh152
1 files changed, 130 insertions, 22 deletions
diff --git a/git-submodule.sh b/git-submodule.sh
index b40f876..0a27232 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -5,16 +5,18 @@
# Copyright (c) 2007 Lars Hjemli
USAGE="[--quiet] [--cached] \
-[add <repo> [-b branch] <path>]|[status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \
-[--] [<path>...]"
+[add <repo> [-b branch] <path>]|[status|init|update [-i|--init] [-N|--no-fetch]|summary [-n|--summary-limit <n>] [<commit>]] \
+[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]"
OPTIONS_SPEC=
. git-sh-setup
+. git-parse-remote
require_work_tree
command=
branch=
quiet=
cached=
+nofetch=
#
# print stuff on stdout unless -q was specified
@@ -30,12 +32,11 @@ say()
# Resolve relative url by appending to parent's url
resolve_relative_url ()
{
- branch="$(git symbolic-ref HEAD 2>/dev/null)"
- remote="$(git config branch.${branch#refs/heads/}.remote)"
- remote="${remote:-origin}"
+ remote=$(get_default_remote)
remoteurl=$(git config "remote.$remote.url") ||
die "remote ($remote) does not have a url defined in .git/config"
url="$1"
+ remoteurl=${remoteurl%/}
while test -n "$url"
do
case "$url" in
@@ -50,7 +51,16 @@ resolve_relative_url ()
break;;
esac
done
- echo "$remoteurl/$url"
+ echo "$remoteurl/${url%/}"
+}
+
+#
+# Get submodule info for registered submodules
+# $@ = path to limit submodule list
+#
+module_list()
+{
+ git ls-files --error-unmatch --stage -- "$@" | grep '^160000 '
}
#
@@ -157,9 +167,18 @@ cmd_add()
;;
esac
- # strip trailing slashes from path
- path=$(echo "$path" | sed -e 's|/*$||')
-
+ # normalize path:
+ # multiple //; leading ./; /./; /../; trailing /
+ path=$(printf '%s/\n' "$path" |
+ sed -e '
+ s|//*|/|g
+ s|^\(\./\)*||
+ s|/\./|/|g
+ :start
+ s|\([^/]*\)/\.\./||
+ tstart
+ s|/*$||
+ ')
git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
die "'$path' already exists in the index"
@@ -185,7 +204,7 @@ cmd_add()
else
module_clone "$path" "$realrepo" || exit
- (unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
+ (unset GIT_DIR; cd "$path" && git checkout -f -q ${branch:+-b "$branch" "origin/$branch"}) ||
die "Unable to checkout submodule '$path'"
fi
@@ -199,6 +218,26 @@ cmd_add()
}
#
+# Execute an arbitrary command sequence in each checked out
+# submodule
+#
+# $@ = command to execute
+#
+cmd_foreach()
+{
+ module_list |
+ while read mode sha1 stage path
+ do
+ if test -e "$path"/.git
+ then
+ say "Entering '$path'"
+ (cd "$path" && eval "$@") ||
+ die "Stopping at '$path'; script returned non-zero status."
+ fi
+ done
+}
+
+#
# Register submodules in .git/config
#
# $@ = requested paths (default to all)
@@ -226,7 +265,7 @@ cmd_init()
shift
done
- git ls-files --stage -- "$@" | grep '^160000 ' |
+ module_list "$@" |
while read mode sha1 stage path
do
# Skip already registered paths
@@ -271,6 +310,10 @@ cmd_update()
shift
cmd_init "$@" || return
;;
+ -N|--no-fetch)
+ shift
+ nofetch=1
+ ;;
--)
shift
break
@@ -284,7 +327,7 @@ cmd_update()
esac
done
- git ls-files --stage -- "$@" | grep '^160000 ' |
+ module_list "$@" |
while read mode sha1 stage path
do
name=$(module_name "$path") || exit
@@ -294,7 +337,7 @@ cmd_update()
# Only mention uninitialized submodules when its
# path have been specified
test "$#" != "0" &&
- say "Submodule path '$path' not initialized"
+ say "Submodule path '$path' not initialized" &&
say "Maybe you want to use 'update --init'?"
continue
fi
@@ -311,8 +354,21 @@ cmd_update()
if test "$subsha1" != "$sha1"
then
- (unset GIT_DIR; cd "$path" && git-fetch &&
- git-checkout -q "$sha1") ||
+ force=
+ if test -z "$subsha1"
+ then
+ force="-f"
+ fi
+
+ if test -z "$nofetch"
+ then
+ (unset GIT_DIR; cd "$path" &&
+ git-fetch) ||
+ die "Unable to fetch in submodule path '$path'"
+ fi
+
+ (unset GIT_DIR; cd "$path" &&
+ git-checkout $force -q "$sha1") ||
die "Unable to checkout '$sha1' in submodule path '$path'"
say "Submodule path '$path': checked out '$sha1'"
@@ -379,7 +435,7 @@ cmd_summary() {
test $summary_limit = 0 && return
- if rev=$(git rev-parse --verify "$1^0" 2>/dev/null)
+ if rev=$(git rev-parse -q --verify "$1^0")
then
head=$rev
shift
@@ -390,7 +446,7 @@ cmd_summary() {
cd_to_toplevel
# Get modified modules cared by user
modules=$(git diff-index $cached --raw $head -- "$@" |
- grep -e '^:160000' -e '^:[0-7]* 160000' |
+ egrep '^:([0-7]* )?160000' |
while read mod_src mod_dst sha1_src sha1_dst status name
do
# Always show modules deleted or type-changed (blob<->module)
@@ -404,7 +460,7 @@ cmd_summary() {
test -z "$modules" && return
git diff-index $cached --raw $head -- $modules |
- grep -e '^:160000' -e '^:[0-7]* 160000' |
+ egrep '^:([0-7]* )?160000' |
cut -c2- |
while read mod_src mod_dst sha1_src sha1_dst status name
do
@@ -430,11 +486,11 @@ cmd_summary() {
missing_dst=
test $mod_src = 160000 &&
- ! GIT_DIR="$name/.git" git-rev-parse --verify $sha1_src^0 >/dev/null 2>&1 &&
+ ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
missing_src=t
test $mod_dst = 160000 &&
- ! GIT_DIR="$name/.git" git-rev-parse --verify $sha1_dst^0 >/dev/null 2>&1 &&
+ ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
missing_dst=t
total_commits=
@@ -549,7 +605,7 @@ cmd_status()
shift
done
- git ls-files --stage -- "$@" | grep '^160000 ' |
+ module_list "$@" |
while read mode sha1 stage path
do
name=$(module_name "$path") || exit
@@ -573,6 +629,58 @@ cmd_status()
fi
done
}
+#
+# Sync remote urls for submodules
+# This makes the value for remote.$remote.url match the value
+# specified in .gitmodules.
+#
+cmd_sync()
+{
+ while test $# -ne 0
+ do
+ case "$1" in
+ -q|--quiet)
+ quiet=1
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+ cd_to_toplevel
+ module_list "$@" |
+ while read mode sha1 stage path
+ do
+ name=$(module_name "$path")
+ url=$(git config -f .gitmodules --get submodule."$name".url)
+
+ # Possibly a url relative to parent
+ case "$url" in
+ ./*|../*)
+ url=$(resolve_relative_url "$url") || exit
+ ;;
+ esac
+
+ if test -e "$path"/.git
+ then
+ (
+ unset GIT_DIR
+ cd "$path"
+ remote=$(get_default_remote)
+ say "Synchronizing submodule url for '$name'"
+ git config remote."$remote".url "$url"
+ )
+ fi
+ done
+}
# This loop parses the command line arguments to find the
# subcommand name to dispatch. Parsing of the subcommand specific
@@ -583,7 +691,7 @@ cmd_status()
while test $# != 0 && test -z "$command"
do
case "$1" in
- add | init | update | status | summary)
+ add | foreach | init | update | status | summary | sync)
command=$1
;;
-q|--quiet)