Merge branches 'lh/submodules' and 'pb/am'
authorJunio C Hamano <junkio@cox.net>
Sun, 3 Jun 2007 02:04:54 +0000 (19:04 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 3 Jun 2007 02:04:54 +0000 (19:04 -0700)
* lh/submodules:
  Add basic test-script for git-submodule
  Add git-submodule command

* pb/am:
  Remove git-applypatch
  git-applymbox: Remove command

14 files changed:
.gitignore
Documentation/SubmittingPatches
Documentation/cmd-list.perl
Documentation/git-am.txt
Documentation/git-applymbox.txt [deleted file]
Documentation/git-applypatch.txt [deleted file]
Documentation/git-mailinfo.txt
Documentation/git-submodule.txt [new file with mode: 0644]
Documentation/hooks.txt
Makefile
git-applymbox.sh [deleted file]
git-applypatch.sh [deleted file]
git-submodule.sh [new file with mode: 0755]
t/t7400-submodule-basic.sh [new file with mode: 0755]

index 4dc0c39..15aed70 100644 (file)
@@ -7,8 +7,6 @@ git-add--interactive
 git-am
 git-annotate
 git-apply
-git-applymbox
-git-applypatch
 git-archimport
 git-archive
 git-bisect
@@ -126,6 +124,7 @@ git-ssh-push
 git-ssh-upload
 git-status
 git-stripspace
+git-submodule
 git-svn
 git-svnimport
 git-symbolic-ref
index b94d9a8..b5f2ecd 100644 (file)
@@ -239,7 +239,7 @@ One test you could do yourself if your MUA is set up correctly is:
     $ git fetch http://kernel.org/pub/scm/git/git.git master:test-apply
     $ git checkout test-apply
     $ git reset --hard
-    $ git applymbox a.patch
+    $ git am a.patch
 
 If it does not apply correctly, there can be various reasons.
 
@@ -247,7 +247,7 @@ If it does not apply correctly, there can be various reasons.
   does not have much to do with your MUA.  Please rebase the
   patch appropriately.
 
-* Your MUA corrupted your patch; applymbox would complain that
+* Your MUA corrupted your patch; "am" would complain that
   the patch does not apply.  Look at .dotest/ subdirectory and
   see what 'patch' file contains and check for the common
   corruption patterns mentioned above.
index 443802a..a181f75 100755 (executable)
@@ -72,8 +72,6 @@ __DATA__
 git-add                                 mainporcelain
 git-am                                  mainporcelain
 git-annotate                            ancillaryinterrogators
-git-applymbox                           ancillaryinterrogators
-git-applypatch                          purehelpers
 git-apply                               plumbingmanipulators
 git-archimport                          foreignscminterface
 git-archive                             mainporcelain
@@ -180,6 +178,7 @@ git-ssh-fetch                           synchingrepositories
 git-ssh-upload                          synchingrepositories
 git-status                              mainporcelain
 git-stripspace                          purehelpers
+git-submodule                           mainporcelain
 git-svn                                 foreignscminterface
 git-svnimport                           foreignscminterface
 git-symbolic-ref                        plumbingmanipulators
index f78e5dc..f3387f5 100644 (file)
@@ -127,8 +127,7 @@ is terminated before the first occurrence of such a line.
 
 When initially invoking it, you give it names of the mailboxes
 to crunch.  Upon seeing the first patch that does not apply, it
-aborts in the middle, just like 'git-applymbox' does.  You can
-recover from this in one of two ways:
+aborts in the middle,.  You can recover from this in one of two ways:
 
 . skip the current patch by re-running the command with '--skip'
   option.
@@ -145,7 +144,7 @@ names.
 
 SEE ALSO
 --------
-gitlink:git-applymbox[1], gitlink:git-applypatch[1], gitlink:git-apply[1].
+gitlink:git-apply[1].
 
 
 Author
diff --git a/Documentation/git-applymbox.txt b/Documentation/git-applymbox.txt
deleted file mode 100644 (file)
index ea919ba..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-git-applymbox(1)
-================
-
-NAME
-----
-git-applymbox - Apply a series of patches in a mailbox
-
-
-SYNOPSIS
---------
-'git-applymbox' [-u] [-k] [-q] [-m] ( -c .dotest/<num> | <mbox> ) [ <signoff> ]
-
-DESCRIPTION
------------
-Splits mail messages in a mailbox into commit log message,
-authorship information and patches, and applies them to the
-current branch.
-
-
-OPTIONS
--------
--q::
-       Apply patches interactively.  The user will be given
-       opportunity to edit the log message and the patch before
-       attempting to apply it.
-
--k::
-       Usually the program 'cleans up' the Subject: header line
-       to extract the title line for the commit log message,
-       among which (1) remove 'Re:' or 're:', (2) leading
-       whitespaces, (3) '[' up to ']', typically '[PATCH]', and
-       then prepends "[PATCH] ".  This flag forbids this
-       munging, and is most useful when used to read back 'git
-       format-patch -k' output.
-
--m::
-       Patches are applied with `git-apply` command, and unless
-       it cleanly applies without fuzz, the processing fails.
-       With this flag, if a tree that the patch applies cleanly
-       is found in a repository, the patch is applied to the
-       tree and then a 3-way merge between the resulting tree
-       and the current tree.
-
--u::
-       Pass `-u` flag to `git-mailinfo` (see gitlink:git-mailinfo[1]).
-       The proposed commit log message taken from the e-mail
-       are re-coded into UTF-8 encoding (configuration variable
-       `i18n.commitencoding` can be used to specify project's
-       preferred encoding if it is not UTF-8).  This used to be
-       optional but now it is the default.
-+
-Note that the patch is always used as-is without charset
-conversion, even with this flag.
-
--n::
-       Pass `-n` flag to `git-mailinfo` (see
-       gitlink:git-mailinfo[1]).
-
--c .dotest/<num>::
-       When the patch contained in an e-mail does not cleanly
-       apply, the command exits with an error message. The
-       patch and extracted message are found in .dotest/, and
-       you could re-run 'git applymbox' with '-c .dotest/<num>'
-       flag to restart the process after inspecting and fixing
-       them.
-
-<mbox>::
-       The name of the file that contains the e-mail messages
-       with patches.  This file should be in the UNIX mailbox
-       format.  See 'SubmittingPatches' document to learn about
-       the formatting convention for e-mail submission.
-
-<signoff>::
-       The name of the file that contains your "Signed-off-by"
-       line.  See 'SubmittingPatches' document to learn what
-       "Signed-off-by" line means.  You can also just say
-       'yes', 'true', 'me', or 'please' to use an automatically
-       generated "Signed-off-by" line based on your committer
-       identity.
-
-
-SEE ALSO
---------
-gitlink:git-am[1], gitlink:git-applypatch[1].
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-applypatch.txt b/Documentation/git-applypatch.txt
deleted file mode 100644 (file)
index 451434a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-git-applypatch(1)
-=================
-
-NAME
-----
-git-applypatch - Apply one patch extracted from an e-mail
-
-
-SYNOPSIS
---------
-'git-applypatch' <msg> <patch> <info> [<signoff>]
-
-DESCRIPTION
------------
-This is usually not what an end user wants to run directly.  See
-gitlink:git-am[1] instead.
-
-Takes three files <msg>, <patch>, and <info> prepared from an
-e-mail message by 'git-mailinfo', and creates a commit.  It is
-usually not necessary to use this command directly.
-
-This command can run `applypatch-msg`, `pre-applypatch`, and
-`post-applypatch` hooks.  See link:hooks.html[hooks] for more
-information.
-
-
-OPTIONS
--------
-<msg>::
-       Commit log message (sans the first line, which comes
-       from e-mail Subject stored in <info>).
-
-<patch>::
-       The patch to apply.
-
-<info>::
-       Author and subject information extracted from e-mail,
-       used on "author" line and as the first line of the
-       commit log message.
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
index 8eadceb..1695695 100644 (file)
@@ -16,7 +16,7 @@ DESCRIPTION
 Reading a single e-mail message from the standard input, and
 writes the commit log message in <msg> file, and the patches in
 <patch> file.  The author name, e-mail and e-mail subject are
-written out to the standard output to be used by git-applypatch
+written out to the standard output to be used by git-am
 to create a commit.  It is usually not necessary to use this
 command directly.  See gitlink:git-am[1] instead.
 
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
new file mode 100644 (file)
index 0000000..cb0424f
--- /dev/null
@@ -0,0 +1,65 @@
+git-submodule(1)
+================
+
+NAME
+----
+git-submodule - Initialize, update or inspect submodules
+
+
+SYNOPSIS
+--------
+'git-submodule' [--quiet] [--cached] [status|init|update] [--] [<path>...]
+
+
+COMMANDS
+--------
+status::
+       Show the status of the submodules. This will print the SHA-1 of the
+       currently checked out commit for each submodule, along with the
+       submodule path and the output of gitlink:git-describe[1] for the
+       SHA-1. Each SHA-1 will be prefixed with `-` if the submodule is not
+       initialized and `+` if the currently checked out submodule commit
+       does not match the SHA-1 found in the index of the containing
+       repository. This command is the default command for git-submodule.
+
+init::
+       Initialize the submodules, i.e. clone the git repositories specified
+       in the .gitmodules file and checkout the submodule commits specified
+       in the index of the containing repository. This will make the
+       submodules HEAD be detached.
+
+update::
+       Update the initialized submodules, i.e. checkout the submodule commits
+       specified in the index of the containing repository. This will make
+       the submodules HEAD be detached.
+
+
+OPTIONS
+-------
+-q, --quiet::
+       Only print error messages.
+
+--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.
+
+<path>::
+       Path to submodule(s). When specified this will restrict the command
+       to only operate on the submodules found at the specified paths.
+
+FILES
+-----
+When cloning submodules, a .gitmodules file in the top-level directory
+of the containing repository is used to find the url of each submodule.
+This file should be formatted in the same way as $GIR_DIR/config. The key
+to each submodule url is "module.$path.url".
+
+
+AUTHOR
+------
+Written by Lars Hjemli <hjemli@gmail.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
index aabb975..6836477 100644 (file)
@@ -12,11 +12,10 @@ This document describes the currently defined hooks.
 applypatch-msg
 --------------
 
-This hook is invoked by `git-applypatch` script, which is
-typically invoked by `git-applymbox`.  It takes a single
+This hook is invoked by `git-am` script.  It takes a single
 parameter, the name of the file that holds the proposed commit
 log message.  Exiting with non-zero status causes
-`git-applypatch` to abort before applying the patch.
+`git-am` to abort before applying the patch.
 
 The hook is allowed to edit the message file in place, and can
 be used to normalize the message into some project standard
@@ -29,8 +28,7 @@ The default 'applypatch-msg' hook, when enabled, runs the
 pre-applypatch
 --------------
 
-This hook is invoked by `git-applypatch` script, which is
-typically invoked by `git-applymbox`.  It takes no parameter,
+This hook is invoked by `git-am`.  It takes no parameter,
 and is invoked after the patch is applied, but before a commit
 is made.  Exiting with non-zero status causes the working tree
 after application of the patch not committed.
@@ -44,12 +42,11 @@ The default 'pre-applypatch' hook, when enabled, runs the
 post-applypatch
 ---------------
 
-This hook is invoked by `git-applypatch` script, which is
-typically invoked by `git-applymbox`.  It takes no parameter,
+This hook is invoked by `git-am`.  It takes no parameter,
 and is invoked after the patch is applied and a commit is made.
 
 This hook is meant primarily for notification, and cannot affect
-the outcome of `git-applypatch`.
+the outcome of `git-am`.
 
 pre-commit
 ----------
index cac0a4a..a11ff60 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -206,10 +206,10 @@ SCRIPT_SH = \
        git-repack.sh git-request-pull.sh git-reset.sh \
        git-sh-setup.sh \
        git-tag.sh git-verify-tag.sh \
-       git-applymbox.sh git-applypatch.sh git-am.sh \
+       git-am.sh \
        git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
        git-merge-resolve.sh git-merge-ours.sh \
-       git-lost-found.sh git-quiltimport.sh
+       git-lost-found.sh git-quiltimport.sh git-submodule.sh
 
 SCRIPT_PERL = \
        git-add--interactive.perl \
diff --git a/git-applymbox.sh b/git-applymbox.sh
deleted file mode 100755 (executable)
index c18e80f..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/sh
-##
-## "dotest" is my stupid name for my patch-application script, which
-## I never got around to renaming after I tested it. We're now on the
-## second generation of scripts, still called "dotest".
-##
-## Update: Ryan Anderson finally shamed me into naming this "applymbox".
-##
-## You give it a mbox-format collection of emails, and it will try to
-## apply them to the kernel using "applypatch"
-##
-## The patch application may fail in the middle.  In which case:
-## (1) look at .dotest/patch and fix it up to apply
-## (2) re-run applymbox with -c .dotest/msg-number for the current one.
-## Pay a special attention to the commit log message if you do this and
-## use a Signoff_file, because applypatch wants to append the sign-off
-## message to msg-clean every time it is run.
-##
-## git-am is supposed to be the newer and better tool for this job.
-
-USAGE='[-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]'
-. git-sh-setup
-
-git var GIT_COMMITTER_IDENT >/dev/null || exit
-
-keep_subject= query_apply= continue= utf8=-u resume=t
-while case "$#" in 0) break ;; esac
-do
-       case "$1" in
-       -u)     utf8=-u ;;
-       -n)     utf8=-n ;;
-       -k)     keep_subject=-k ;;
-       -q)     query_apply=t ;;
-       -c)     continue="$2"; resume=f; shift ;;
-       -m)     fall_back_3way=t ;;
-       -*)     usage ;;
-       *)      break ;;
-       esac
-       shift
-done
-
-case "$continue" in
-'')
-       rm -rf .dotest
-       mkdir .dotest
-       num_msgs=$(git-mailsplit "$1" .dotest) || exit 1
-       echo "$num_msgs patch(es) to process."
-       shift
-esac
-
-files=$(git-diff-index --cached --name-only HEAD) || exit
-if [ "$files" ]; then
-   echo "Dirty index: cannot apply patches (dirty: $files)" >&2
-   exit 1
-fi
-
-case "$query_apply" in
-t)     touch .dotest/.query_apply
-esac
-case "$fall_back_3way" in
-t)     : >.dotest/.3way
-esac
-case "$keep_subject" in
--k)    : >.dotest/.keep_subject
-esac
-
-signoff="$1"
-set x .dotest/0*
-shift
-while case "$#" in 0) break;; esac
-do
-    i="$1" 
-    case "$resume,$continue" in
-    f,$i)      resume=t;;
-    f,*)       shift
-               continue;;
-    *)
-           git-mailinfo $keep_subject $utf8 \
-               .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
-           test -s .dotest/patch || {
-               echo "Patch is empty.  Was it split wrong?"
-               exit 1
-           }
-           git-stripspace < .dotest/msg > .dotest/msg-clean
-           ;;
-    esac
-    while :; # for fixing up and retry
-    do
-       git-applypatch .dotest/msg-clean .dotest/patch .dotest/info "$signoff"
-       case "$?" in
-       0)
-               # Remove the cleanly applied one to reduce clutter.
-               rm -f .dotest/$i
-               ;;
-       2)
-               # 2 is a special exit code from applypatch to indicate that
-               # the patch wasn't applied, but continue anyway 
-               ;;
-       *)
-               ret=$?
-               if test -f .dotest/.query_apply
-               then
-                       echo >&2 "* Patch failed."
-                       echo >&2 "* You could fix it up in your editor and"
-                       echo >&2 "  retry.  If you want to do so, say yes here"
-                       echo >&2 "  AFTER fixing .dotest/patch up."
-                       echo >&2 -n "Retry [y/N]? "
-                       read yesno
-                       case "$yesno" in
-                       [Yy]*)
-                               continue ;;
-                       esac
-               fi
-               exit $ret
-       esac
-       break
-    done
-    shift
-done
-# return to pristine
-rm -fr .dotest
diff --git a/git-applypatch.sh b/git-applypatch.sh
deleted file mode 100755 (executable)
index 8df2aee..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/bin/sh
-##
-## applypatch takes four file arguments, and uses those to
-## apply the unpacked patch (surprise surprise) that they
-## represent to the current tree.
-##
-## The arguments are:
-##     $1 - file with commit message
-##     $2 - file with the actual patch
-##     $3 - "info" file with Author, email and subject
-##     $4 - optional file containing signoff to add
-##
-
-USAGE='<msg> <patch> <info> [<signoff>]'
-. git-sh-setup
-
-case "$#" in 3|4) ;; *) usage ;; esac
-
-final=.dotest/final-commit
-##
-## If this file exists, we ask before applying
-##
-query_apply=.dotest/.query_apply
-
-## We do not munge the first line of the commit message too much
-## if this file exists.
-keep_subject=.dotest/.keep_subject
-
-## We do not attempt the 3-way merge fallback unless this file exists.
-fall_back_3way=.dotest/.3way
-
-MSGFILE=$1
-PATCHFILE=$2
-INFO=$3
-SIGNOFF=$4
-EDIT=${VISUAL:-${EDITOR:-vi}}
-
-export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$INFO")"
-export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$INFO")"
-export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$INFO")"
-export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$INFO")"
-
-if test '' != "$SIGNOFF"
-then
-       if test -f "$SIGNOFF"
-       then
-               SIGNOFF=`cat "$SIGNOFF"` || exit
-       elif case "$SIGNOFF" in yes | true | me | please) : ;; *) false ;; esac
-       then
-               SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e '
-                               s/>.*/>/
-                               s/^/Signed-off-by: /'
-               `
-       else
-               SIGNOFF=
-       fi
-       if test '' != "$SIGNOFF"
-       then
-               LAST_SIGNED_OFF_BY=`
-                       sed -ne '/^Signed-off-by: /p' "$MSGFILE" |
-                       tail -n 1
-               `
-               test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
-                   test '' = "$LAST_SIGNED_OFF_BY" && echo
-                   echo "$SIGNOFF"
-               } >>"$MSGFILE"
-       fi
-fi
-
-patch_header=
-test -f "$keep_subject" || patch_header='[PATCH] '
-
-{
-       echo "$patch_header$SUBJECT"
-       if test -s "$MSGFILE"
-       then
-               echo
-               cat "$MSGFILE"
-       fi
-} >"$final"
-
-interactive=yes
-test -f "$query_apply" || interactive=no
-
-while [ "$interactive" = yes ]; do
-       echo "Commit Body is:"
-       echo "--------------------------"
-       cat "$final"
-       echo "--------------------------"
-       printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
-       read reply
-       case "$reply" in
-               y|Y) interactive=no;;
-               n|N) exit 2;;   # special value to tell dotest to keep going
-               e|E) "$EDIT" "$final";;
-               a|A) rm -f "$query_apply"
-                    interactive=no ;;
-       esac
-done
-
-if test -x "$GIT_DIR"/hooks/applypatch-msg
-then
-       "$GIT_DIR"/hooks/applypatch-msg "$final" || exit
-fi
-
-echo
-echo Applying "'$SUBJECT'"
-echo
-
-git-apply --index "$PATCHFILE" || {
-
-       # git-apply exits with status 1 when the patch does not apply,
-       # but it die()s with other failures, most notably upon corrupt
-       # patch.  In the latter case, there is no point to try applying
-       # it to another tree and do 3-way merge.
-       test $? = 1 || exit 1
-
-       test -f "$fall_back_3way" || exit 1
-
-       # Here if we know which revision the patch applies to,
-       # we create a temporary working tree and index, apply the
-       # patch, and attempt 3-way merge with the resulting tree.
-
-       O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
-       rm -fr .patch-merge-*
-
-       if git-apply -z --index-info "$PATCHFILE" \
-               >.patch-merge-index-info 2>/dev/null &&
-               GIT_INDEX_FILE=.patch-merge-tmp-index \
-               git-update-index -z --index-info <.patch-merge-index-info &&
-               GIT_INDEX_FILE=.patch-merge-tmp-index \
-               git-write-tree >.patch-merge-tmp-base &&
-               (
-                       mkdir .patch-merge-tmp-dir &&
-                       cd .patch-merge-tmp-dir &&
-                       GIT_INDEX_FILE="../.patch-merge-tmp-index" \
-                       GIT_OBJECT_DIRECTORY="$O_OBJECT" \
-                       git-apply $binary --index
-               ) <"$PATCHFILE"
-       then
-               echo Using index info to reconstruct a base tree...
-               mv .patch-merge-tmp-base .patch-merge-base
-               mv .patch-merge-tmp-index .patch-merge-index
-       else
-       (
-               N=10
-
-               # Otherwise, try nearby trees that can be used to apply the
-               # patch.
-               git-rev-list --max-count=$N HEAD
-
-               # or hoping the patch is against known tags...
-               git-ls-remote --tags .
-       ) |
-           while read base junk
-           do
-               # Try it if we have it as a tree.
-               git-cat-file tree "$base" >/dev/null 2>&1 || continue
-
-               rm -fr .patch-merge-tmp-* &&
-               mkdir .patch-merge-tmp-dir || break
-               (
-                       cd .patch-merge-tmp-dir &&
-                       GIT_INDEX_FILE=../.patch-merge-tmp-index &&
-                       GIT_OBJECT_DIRECTORY="$O_OBJECT" &&
-                       export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&
-                       git-read-tree "$base" &&
-                       git-apply --index &&
-                       mv ../.patch-merge-tmp-index ../.patch-merge-index &&
-                       echo "$base" >../.patch-merge-base
-               ) <"$PATCHFILE"  2>/dev/null && break
-           done
-       fi
-
-       test -f .patch-merge-index &&
-       his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
-       orig_tree=$(cat .patch-merge-base) &&
-       rm -fr .patch-merge-* || exit 1
-
-       echo Falling back to patching base and 3-way merge using $orig_tree...
-
-       # This is not so wrong.  Depending on which base we picked,
-       # orig_tree may be wildly different from ours, but his_tree
-       # has the same set of wildly different changes in parts the
-       # patch did not touch, so resolve ends up canceling them,
-       # saying that we reverted all those changes.
-
-       if git-merge-resolve $orig_tree -- HEAD $his_tree
-       then
-               echo Done.
-       else
-               echo Failed to merge in the changes.
-               exit 1
-       fi
-}
-
-if test -x "$GIT_DIR"/hooks/pre-applypatch
-then
-       "$GIT_DIR"/hooks/pre-applypatch || exit
-fi
-
-tree=$(git-write-tree) || exit 1
-echo Wrote tree $tree
-parent=$(git-rev-parse --verify HEAD) &&
-commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1
-echo Committed: $commit
-git-update-ref -m "applypatch: $SUBJECT" HEAD $commit $parent || exit
-
-if test -x "$GIT_DIR"/hooks/post-applypatch
-then
-       "$GIT_DIR"/hooks/post-applypatch
-fi
diff --git a/git-submodule.sh b/git-submodule.sh
new file mode 100755 (executable)
index 0000000..6ed5a6c
--- /dev/null
@@ -0,0 +1,194 @@
+#!/bin/sh
+#
+# git-submodules.sh: init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[--quiet] [--cached] [status|init|update] [--] [<path>...]'
+. git-sh-setup
+require_work_tree
+
+init=
+update=
+status=
+quiet=
+cached=
+
+#
+# print stuff on stdout unless -q was specified
+#
+say()
+{
+       if test -z "$quiet"
+       then
+               echo "$@"
+       fi
+}
+
+#
+# Run clone + checkout on missing submodules
+#
+# $@ = requested paths (default to all)
+#
+modules_init()
+{
+       git ls-files --stage -- "$@" | grep -e '^160000 ' |
+       while read mode sha1 stage path
+       do
+               # Skip submodule paths that already contain a .git directory.
+               # This will also trigger if $path is a symlink to a git
+               # repository
+               test -d "$path"/.git && continue
+
+               # If there already is a directory at the submodule path,
+               # expect it to be empty (since that is the default checkout
+               # action) and try to remove it.
+               # Note: if $path is a symlink to a directory the test will
+               # succeed but the rmdir will fail. We might want to fix this.
+               if test -d "$path"
+               then
+                       rmdir "$path" 2>/dev/null ||
+                       die "Directory '$path' exist, but is neither empty nor a git repository"
+               fi
+
+               test -e "$path" &&
+               die "A file already exist at path '$path'"
+
+               url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
+               test -z "$url" &&
+               die "No url found for submodule '$path' in .gitmodules"
+
+               # MAYBE FIXME: this would be the place to check GIT_CONFIG
+               # for a preferred url for this submodule, possibly like this:
+               #
+               # modname=$(GIT_CONFIG=.gitmodules git-config module."$path".name)
+               # alturl=$(git-config module."$modname".url)
+               #
+               # This would let the versioned .gitmodules file use the submodule
+               # path as key, while the unversioned GIT_CONFIG would use the
+               # logical modulename (if present) as key. But this would need
+               # another fallback mechanism if the module wasn't named.
+
+               git-clone -n "$url" "$path" ||
+               die "Clone of submodule '$path' failed"
+
+               (unset GIT_DIR && cd "$path" && git-checkout -q "$sha1") ||
+               die "Checkout of submodule '$path' failed"
+
+               say "Submodule '$path' initialized"
+       done
+}
+
+#
+# Checkout correct revision of each initialized submodule
+#
+# $@ = requested paths (default to all)
+#
+modules_update()
+{
+       git ls-files --stage -- "$@" | grep -e '^160000 ' |
+       while read mode sha1 stage path
+       do
+               if ! test -d "$path"/.git
+               then
+                       # Only mention uninitialized submodules when its
+                       # path have been specified
+                       test "$#" != "0" &&
+                       say "Submodule '$path' not initialized"
+                       continue;
+               fi
+               subsha1=$(unset GIT_DIR && cd "$path" &&
+                       git-rev-parse --verify HEAD) ||
+               die "Unable to find current revision of submodule '$path'"
+
+               if test "$subsha1" != "$sha1"
+               then
+                       (unset GIT_DIR && cd "$path" && git-fetch &&
+                               git-checkout -q "$sha1") ||
+                       die "Unable to checkout '$sha1' in submodule '$path'"
+
+                       say "Submodule '$path': checked out '$sha1'"
+               fi
+       done
+}
+
+#
+# List all registered submodules, prefixed with:
+#  - submodule not initialized
+#  + different revision checked out
+#
+# If --cached was specified the revision in the index will be printed
+# instead of the currently checked out revision.
+#
+# $@ = requested paths (default to all)
+#
+modules_list()
+{
+       git ls-files --stage -- "$@" | grep -e '^160000 ' |
+       while read mode sha1 stage path
+       do
+               if ! test -d "$path"/.git
+               then
+                       say "-$sha1 $path"
+                       continue;
+               fi
+               revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
+               if git diff-files --quiet -- "$path"
+               then
+                       say " $sha1 $path ($revname)"
+               else
+                       if test -z "$cached"
+                       then
+                               sha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD)
+                               revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
+                       fi
+                       say "+$sha1 $path ($revname)"
+               fi
+       done
+}
+
+while case "$#" in 0) break ;; esac
+do
+       case "$1" in
+       init)
+               init=1
+               ;;
+       update)
+               update=1
+               ;;
+       status)
+               status=1
+               ;;
+       -q|--quiet)
+               quiet=1
+               ;;
+       --cached)
+               cached=1
+               ;;
+       --)
+               break
+               ;;
+       -*)
+               usage
+               ;;
+       *)
+               break
+               ;;
+       esac
+       shift
+done
+
+case "$init,$update,$status,$cached" in
+1,,,)
+       modules_init "$@"
+       ;;
+,1,,)
+       modules_update "$@"
+       ;;
+,,*,*)
+       modules_list "$@"
+       ;;
+*)
+       usage
+       ;;
+esac
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
new file mode 100755 (executable)
index 0000000..6274729
--- /dev/null
@@ -0,0 +1,143 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Lars Hjemli
+#
+
+test_description='Basic porcelain support for submodules
+
+This test tries to verify basic sanity of the init, update and status
+subcommands of git-submodule.
+'
+
+. ./test-lib.sh
+
+#
+# Test setup:
+#  -create a repository in directory lib
+#  -add a couple of files
+#  -add directory lib to 'superproject', this creates a DIRLINK entry
+#  -add a couple of regular files to enable testing of submodule filtering
+#  -mv lib subrepo
+#  -add an entry to .gitmodules for path 'lib'
+#
+test_expect_success 'Prepare submodule testing' '
+       mkdir lib &&
+       cd lib &&
+       git-init &&
+       echo a >a &&
+       git-add a &&
+       git-commit -m "submodule commit 1" &&
+       git-tag -a -m "rev-1" rev-1 &&
+       rev1=$(git-rev-parse HEAD) &&
+       if test -z "$rev1"
+       then
+               echo "[OOPS] submodule git-rev-parse returned nothing"
+               false
+       fi &&
+       cd .. &&
+       echo a >a &&
+       echo z >z &&
+       git-add a lib z &&
+       git-commit -m "super commit 1" &&
+       mv lib .subrepo &&
+       GIT_CONFIG=.gitmodules git-config module.lib.url ./.subrepo
+'
+
+test_expect_success 'status should only print one line' '
+       lines=$(git-submodule status | wc -l) &&
+       test $lines = 1
+'
+
+test_expect_success 'status should initially be "missing"' '
+       git-submodule status | grep "^-$rev1"
+'
+
+test_expect_success 'init should fail when path is used by a file' '
+       echo "hello" >lib &&
+       if git-submodule init
+       then
+               echo "[OOPS] init should have failed"
+               false
+       elif test -f lib && test "$(cat lib)" != "hello"
+       then
+               echo "[OOPS] init failed but lib file was molested"
+               false
+       else
+               rm lib
+       fi
+'
+
+test_expect_success 'init should fail when path is used by a nonempty directory' '
+       mkdir lib &&
+       echo "hello" >lib/a &&
+       if git-submodule init
+       then
+               echo "[OOPS] init should have failed"
+               false
+       elif test "$(cat lib/a)" != "hello"
+       then
+               echo "[OOPS] init failed but lib/a was molested"
+               false
+       else
+               rm lib/a
+       fi
+'
+
+test_expect_success 'init should work when path is an empty dir' '
+       rm -rf lib &&
+       mkdir lib &&
+       git-submodule init &&
+       head=$(cd lib && git-rev-parse HEAD) &&
+       if test -z "$head"
+       then
+               echo "[OOPS] Failed to obtain submodule head"
+               false
+       elif test "$head" != "$rev1"
+       then
+               echo "[OOPS] Submodule head is $head but should have been $rev1"
+               false
+       fi
+'
+
+test_expect_success 'status should be "up-to-date" after init' '
+       git-submodule status | grep "^ $rev1"
+'
+
+test_expect_success 'status should be "modified" after submodule commit' '
+       cd lib &&
+       echo b >b &&
+       git-add b &&
+       git-commit -m "submodule commit 2" &&
+       rev2=$(git-rev-parse HEAD) &&
+       cd .. &&
+       if test -z "$rev2"
+       then
+               echo "[OOPS] submodule git-rev-parse returned nothing"
+               false
+       fi &&
+       git-submodule status | grep "^+$rev2"
+'
+
+test_expect_success 'the --cached sha1 should be rev1' '
+       git-submodule --cached status | grep "^+$rev1"
+'
+
+test_expect_success 'update should checkout rev1' '
+       git-submodule update &&
+       head=$(cd lib && git-rev-parse HEAD) &&
+       if test -z "$head"
+       then
+               echo "[OOPS] submodule git-rev-parse returned nothing"
+               false
+       elif test "$head" != "$rev1"
+       then
+               echo "[OOPS] init did not checkout correct head"
+               false
+       fi
+'
+
+test_expect_success 'status should be "up-to-date" after update' '
+       git-submodule status | grep "^ $rev1"
+'
+
+test_done