summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-submodule.txt19
-rwxr-xr-xgit-submodule.sh180
-rwxr-xr-xt/t7401-submodule-summary.sh195
3 files changed, 386 insertions, 8 deletions
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index b4d01605a5..41f9f63566 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -12,6 +12,7 @@ SYNOPSIS
'git-submodule' [--quiet] add [-b branch] [--] <repository> [<path>]
'git-submodule' [--quiet] status [--cached] [--] [<path>...]
'git-submodule' [--quiet] [init|update] [--] [<path>...]
+'git-submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
COMMANDS
@@ -47,6 +48,11 @@ update::
checkout the commit specified in the index of the containing repository.
This will make the submodules HEAD be detached.
+summary::
+ Show commit summary between the given commit (defaults to HEAD) and
+ working tree/index. For a submodule in question, a series of commits
+ in the submodule between the given super project commit and the
+ index or working tree (switched by --cached) are shown.
OPTIONS
-------
@@ -57,9 +63,16 @@ OPTIONS
Branch of repository to add as submodule.
--cached::
- Display the SHA-1 stored in the index, not the SHA-1 of the currently
- checked out submodule commit. This option is only valid for the
- status command.
+ This option is only valid for status and summary commands. These
+ commands typically use the commit found in the submodule HEAD, but
+ with this option, the commit stored in the index is used instead.
+
+-n, --summary-limit::
+ This option is only valid for the summary command.
+ Limit the summary size (number of commits shown in total).
+ Giving 0 will disable the summary; a negative number means unlimted
+ (the default). This limit only applies to modified submodules. The
+ size is always limited to 1 for added/deleted/typechanged submodules.
<path>::
Path to submodule(s). When specified this will restrict the command
diff --git a/git-submodule.sh b/git-submodule.sh
index 7171cb60ab..5f1d5ef06e 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -4,7 +4,9 @@
#
# Copyright (c) 2007 Lars Hjemli
-USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
+USAGE="[--quiet] [--cached] \
+[add <repo> [-b branch]|status|init|update|summary [-n|--summary-limit <n>] [<commit>]] \
+[--] [<path>...]"
OPTIONS_SPEC=
. git-sh-setup
require_work_tree
@@ -330,7 +332,175 @@ set_name_rev () {
) )
test -z "$revname" || revname=" ($revname)"
}
+#
+# Show commit summary for submodules in index or working tree
+#
+# If '--cached' is given, show summary between index and given commit,
+# or between working tree and given commit
+#
+# $@ = [commit (default 'HEAD'),] requested paths (default all)
+#
+cmd_summary() {
+ summary_limit=-1
+
+ # parse $args after "submodule ... summary".
+ while test $# -ne 0
+ do
+ case "$1" in
+ --cached)
+ cached="$1"
+ ;;
+ -n|--summary-limit)
+ if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
+ then
+ :
+ else
+ usage
+ fi
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
+ test $summary_limit = 0 && return
+
+ if rev=$(git rev-parse --verify "$1^0" 2>/dev/null)
+ then
+ head=$rev
+ shift
+ else
+ head=HEAD
+ fi
+
+ cd_to_toplevel
+ # Get modified modules cared by user
+ modules=$(git diff-index $cached --raw $head -- "$@" |
+ grep -e '^:160000' -e '^:[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)
+ test $status = D -o $status = T && echo "$name" && continue
+ # Also show added or modified modules which are checked out
+ GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
+ echo "$name"
+ done
+ )
+
+ test -n "$modules" &&
+ git diff-index $cached --raw $head -- $modules |
+ grep -e '^:160000' -e '^:[0-7]* 160000' |
+ cut -c2- |
+ while read mod_src mod_dst sha1_src sha1_dst status name
+ do
+ if test -z "$cached" &&
+ test $sha1_dst = 0000000000000000000000000000000000000000
+ then
+ case "$mod_dst" in
+ 160000)
+ sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
+ ;;
+ 100644 | 100755 | 120000)
+ sha1_dst=$(git hash-object $name)
+ ;;
+ 000000)
+ ;; # removed
+ *)
+ # unexpected type
+ echo >&2 "unexpected mode $mod_dst"
+ continue ;;
+ esac
+ fi
+ missing_src=
+ missing_dst=
+
+ test $mod_src = 160000 &&
+ ! GIT_DIR="$name/.git" git-rev-parse --verify $sha1_src^0 >/dev/null 2>&1 &&
+ missing_src=t
+
+ test $mod_dst = 160000 &&
+ ! GIT_DIR="$name/.git" git-rev-parse --verify $sha1_dst^0 >/dev/null 2>&1 &&
+ missing_dst=t
+ total_commits=
+ case "$missing_src,$missing_dst" in
+ t,)
+ errmsg=" Warn: $name doesn't contain commit $sha1_src"
+ ;;
+ ,t)
+ errmsg=" Warn: $name doesn't contain commit $sha1_dst"
+ ;;
+ t,t)
+ errmsg=" Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+ ;;
+ *)
+ errmsg=
+ total_commits=$(
+ if test $mod_src = 160000 -a $mod_dst = 160000
+ then
+ range="$sha1_src...$sha1_dst"
+ elif test $mod_src = 160000
+ then
+ range=$sha1_src
+ else
+ range=$sha1_dst
+ fi
+ GIT_DIR="$name/.git" \
+ git log --pretty=oneline --first-parent $range | wc -l
+ )
+ total_commits=" ($(($total_commits + 0)))"
+ ;;
+ esac
+
+ sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
+ sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
+ if test $status = T
+ then
+ if test $mod_dst = 160000
+ then
+ echo "* $name $sha1_abbr_src(blob)->$sha1_abbr_dst(submodule)$total_commits:"
+ else
+ echo "* $name $sha1_abbr_src(submodule)->$sha1_abbr_dst(blob)$total_commits:"
+ fi
+ else
+ echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
+ fi
+ if test -n "$errmsg"
+ then
+ # Don't give error msg for modification whose dst is not submodule
+ # i.e. deleted or changed to blob
+ test $mod_dst = 160000 && echo "$errmsg"
+ else
+ if test $mod_src = 160000 -a $mod_dst = 160000
+ then
+ limit=
+ test $summary_limit -gt 0 && limit="-$summary_limit"
+ GIT_DIR="$name/.git" \
+ git log $limit --pretty='format: %m %s' \
+ --first-parent $sha1_src...$sha1_dst
+ elif test $mod_dst = 160000
+ then
+ GIT_DIR="$name/.git" \
+ git log --pretty='format: > %s' -1 $sha1_dst
+ else
+ GIT_DIR="$name/.git" \
+ git log --pretty='format: < %s' -1 $sha1_src
+ fi
+ echo
+ fi
+ echo
+ done
+}
#
# List all submodules, prefixed with:
# - submodule not initialized
@@ -401,7 +571,7 @@ cmd_status()
while test $# != 0 && test -z "$command"
do
case "$1" in
- add | init | update | status)
+ add | init | update | status | summary)
command=$1
;;
-q|--quiet)
@@ -416,7 +586,7 @@ do
branch="$2"; shift
;;
--cached)
- cached=1
+ cached="$1"
;;
--)
break
@@ -440,8 +610,8 @@ then
usage
fi
-# "--cached" is accepted only by "status"
-if test -n "$cached" && test "$command" != status
+# "--cached" is accepted only by "status" and "summary"
+if test -n "$cached" && test "$command" != status -a "$command" != summary
then
usage
fi
diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
new file mode 100755
index 0000000000..0f3c42ab35
--- /dev/null
+++ b/t/t7401-submodule-summary.sh
@@ -0,0 +1,195 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Ping Yin
+#
+
+test_description='Summary support for submodules
+
+This test tries to verify the sanity of summary subcommand of git-submodule.
+'
+
+. ./test-lib.sh
+
+add_file () {
+ sm=$1
+ shift
+ owd=$(pwd)
+ cd "$sm"
+ for name; do
+ echo "$name" > "$name" &&
+ git add "$name" &&
+ test_tick &&
+ git commit -m "Add $name"
+ done >/dev/null
+ git rev-parse --verify HEAD | cut -c1-7
+ cd "$owd"
+}
+commit_file () {
+ test_tick &&
+ git commit "$@" -m "Commit $*" >/dev/null
+}
+
+test_create_repo sm1 &&
+add_file . foo
+
+head1=$(add_file sm1 foo1 foo2)
+
+test_expect_success 'added submodule' "
+ git add sm1 &&
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 0000000...$head1 (2):
+ > Add foo2
+
+EOF
+"
+
+commit_file sm1 &&
+head2=$(add_file sm1 foo3)
+
+test_expect_success 'modified submodule(forward)' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head1...$head2 (1):
+ > Add foo3
+
+EOF
+"
+
+commit_file sm1 &&
+cd sm1 &&
+git reset --hard HEAD~2 >/dev/null &&
+head3=$(git rev-parse --verify HEAD | cut -c1-7) &&
+cd ..
+
+test_expect_success 'modified submodule(backward)' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head2...$head3 (2):
+ < Add foo3
+ < Add foo2
+
+EOF
+"
+
+head4=$(add_file sm1 foo4 foo5) &&
+head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
+test_expect_success 'modified submodule(backward and forward)' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head2...$head4 (4):
+ > Add foo5
+ > Add foo4
+ < Add foo3
+ < Add foo2
+
+EOF
+"
+
+test_expect_success '--summary-limit' "
+ git submodule summary -n 3 >actual &&
+ diff actual - <<-EOF
+* sm1 $head2...$head4 (4):
+ > Add foo5
+ > Add foo4
+ < Add foo3
+
+EOF
+"
+
+commit_file sm1 &&
+mv sm1 sm1-bak &&
+echo sm1 >sm1 &&
+head5=$(git hash-object sm1 | cut -c1-7) &&
+git add sm1 &&
+rm -f sm1 &&
+mv sm1-bak sm1
+
+test_expect_success 'typechanged submodule(submodule->blob), --cached' "
+ git submodule summary --cached >actual &&
+ diff actual - <<-EOF
+* sm1 $head4(submodule)->$head5(blob) (3):
+ < Add foo5
+
+EOF
+"
+
+rm -rf sm1 &&
+git checkout-index sm1
+test_expect_success 'typechanged submodule(submodule->blob)' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head4(submodule)->$head5(blob):
+
+EOF
+"
+
+rm -f sm1 &&
+test_create_repo sm1 &&
+head6=$(add_file sm1 foo6 foo7)
+test_expect_success 'nonexistent commit' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head4...$head6:
+ Warn: sm1 doesn't contain commit $head4_full
+
+EOF
+"
+
+commit_file
+test_expect_success 'typechanged submodule(blob->submodule)' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head5(blob)->$head6(submodule) (2):
+ > Add foo7
+
+EOF
+"
+
+commit_file sm1 &&
+rm -rf sm1
+test_expect_success 'deleted submodule' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head6...0000000:
+
+EOF
+"
+
+test_create_repo sm2 &&
+head7=$(add_file sm2 foo8 foo9) &&
+git add sm2
+
+test_expect_success 'multiple submodules' "
+ git submodule summary >actual &&
+ diff actual - <<-EOF
+* sm1 $head6...0000000:
+
+* sm2 0000000...$head7 (2):
+ > Add foo9
+
+EOF
+"
+
+test_expect_success 'path filter' "
+ git submodule summary sm2 >actual &&
+ diff actual - <<-EOF
+* sm2 0000000...$head7 (2):
+ > Add foo9
+
+EOF
+"
+
+commit_file sm2
+test_expect_success 'given commit' "
+ git submodule summary HEAD^ >actual &&
+ diff actual - <<-EOF
+* sm1 $head6...0000000:
+
+* sm2 0000000...$head7 (2):
+ > Add foo9
+
+EOF
+"
+
+test_done