Merge branch 'py/submodule'

* py/submodule:
  git-submodule summary: fix that some "wc" flavors produce leading spaces
  git-submodule summary: test
  git-submodule summary: documentation
  git-submodule summary: limit summary size
  git-submodule summary: show commit summary
  git-submodule summary: code framework
This commit is contained in:
Junio C Hamano 2008-03-15 01:10:44 -07:00
commit 37bd6c5a2a
3 changed files with 386 additions and 8 deletions

View File

@ -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

View File

@ -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

195
t/t7401-submodule-summary.sh Executable file
View File

@ -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