Merge branch 'wk/submodule-on-branch'
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Feb 2014 22:01:31 +0000 (14:01 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Feb 2014 22:01:33 +0000 (14:01 -0800)
Make sure 'submodule update' modes that do not detach HEADs can
be used more pleasantly by checking out a concrete branch when
cloning them to prime the well.

* wk/submodule-on-branch:
Documentation: describe 'submodule update --remote' use case
submodule: explicit local branch creation in module_clone
submodule: document module_clone arguments in comments
submodule: make 'checkout' update_module mode more explicit

1  2 
Documentation/gitmodules.txt
git-submodule.sh
t/t7406-submodule-update.sh
index 347a9f76ee809c3691dc6580b0fba3ebde0b0e3c,385f35da59c6a1e0ce31b869e2b0bd199bb3074d..f539e3f66a8b4c9b2603b0e2f63a89dd2adf1bfe
@@@ -35,8 -35,6 +35,8 @@@ submodule.<name>.url:
        linkgit:git-clone[1] or (if it begins with ./ or ../) a location
        relative to the superproject's origin repository.
  
 +In addition, there are a number of optional keys:
 +
  submodule.<name>.update::
        Defines what to do when the submodule is updated by the superproject.
        If 'checkout' (the default), the new commit specified in the
@@@ -55,6 -53,10 +55,10 @@@ submodule.<name>.branch:
        A remote branch name for tracking updates in the upstream submodule.
        If the option is not specified, it defaults to 'master'.  See the
        `--remote` documentation in linkgit:git-submodule[1] for details.
+ +
+ This branch name is also used for the local branch created by
+ non-checkout cloning updates.  See the `update` documentation in
+ linkgit:git-submodule[1] for details.
  
  submodule.<name>.fetchRecurseSubmodules::
        This option can be used to control recursive fetching of this
diff --combined git-submodule.sh
index 4a30087768a16d77bfcec41889f58b64fdf5f89c,626a746f7c89e915115bd70a9975576f5184d9b6..a33f68d27c0e1d482562373e6fd299da5dd9361a
@@@ -156,7 -156,7 +156,7 @@@ module_list(
                git ls-files -z --error-unmatch --stage -- "$@" ||
                echo "unmatched pathspec exists"
        ) |
 -      perl -e '
 +      @@PERL@@ -e '
        my %unmerged = ();
        my ($null_sha1) = ("0" x 40);
        my @out = ();
@@@ -241,6 -241,15 +241,15 @@@ module_name(
  #
  # Clone a submodule
  #
+ # $1 = submodule path
+ # $2 = submodule name
+ # $3 = URL to clone
+ # $4 = reference repository to reuse (empty for independent)
+ # $5 = depth argument for shallow clones (empty for deep)
+ # $6 = (remote-tracking) starting point for the local branch (empty for HEAD)
+ # $7 = local branch to create (empty for a detached HEAD, unless $6 is
+ #      also empty, in which case the local branch is left unchanged)
+ #
  # Prior to calling, cmd_update checks that a possibly existing
  # path is not a git repository.
  # Likewise, cmd_add checks that path does not exist at all,
@@@ -253,6 -262,8 +262,8 @@@ module_clone(
        url=$3
        reference="$4"
        depth="$5"
+       start_point="$6"
+       local_branch="$7"
        quiet=
        if test -n "$GIT_QUIET"
        then
        echo "gitdir: $rel/$a" >"$sm_path/.git"
  
        rel=$(echo $a | sed -e 's|[^/][^/]*|..|g')
-       (clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
+       (
+               clear_local_git_env
+               cd "$sm_path" &&
+               GIT_WORK_TREE=. git config core.worktree "$rel/$b" &&
+               # ash fails to wordsplit ${local_branch:+-B "$local_branch"...}
+               case "$local_branch" in
+               '') git checkout -f -q ${start_point:+"$start_point"} ;;
+               ?*) git checkout -f -q -B "$local_branch" ${start_point:+"$start_point"} ;;
+               esac
+       ) || die "$(eval_gettext "Unable to setup cloned submodule '\$sm_path'")"
  }
  
  isnumber()
@@@ -469,16 -489,15 +489,15 @@@ Use -f if you really want to add it." >
                                echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
                        fi
                fi
-               module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" || exit
-               (
-                       clear_local_git_env
-                       cd "$sm_path" &&
-                       # ash fails to wordsplit ${branch:+-b "$branch"...}
-                       case "$branch" in
-                       '') git checkout -f -q ;;
-                       ?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
-                       esac
-               ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
+               if test -n "$branch"
+               then
+                       start_point="origin/$branch"
+                       local_branch="$branch"
+               else
+                       start_point=""
+                       local_branch=""
+               fi
+               module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" "$depth" "$start_point" "$local_branch" || exit
        fi
        git config submodule."$sm_name".url "$realrepo"
  
@@@ -545,12 -564,7 +564,12 @@@ cmd_foreach(
                                sm_path=$(relative_path "$sm_path") &&
                                # we make $path available to scripts ...
                                path=$sm_path &&
 -                              eval "$@" &&
 +                              if test $# -eq 1
 +                              then
 +                                      eval "$1"
 +                              else
 +                                      "$@"
 +                              fi &&
                                if test -n "$recursive"
                                then
                                        cmd_foreach "--recursive" "$@"
@@@ -721,6 -735,7 +740,6 @@@ cmd_deinit(
  cmd_update()
  {
        # parse $args after "submodule ... update".
 -      orig_flags=
        while test $# -ne 0
        do
                case "$1" in
                --reference)
                        case "$2" in '') usage ;; esac
                        reference="--reference=$2"
 -                      orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
                        shift
                        ;;
                --reference=*)
                        break
                        ;;
                esac
 -              orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
                shift
        done
  
                fi
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
-               branch=$(get_submodule_config "$name" branch master)
+               config_branch=$(get_submodule_config "$name" branch)
+               branch="${config_branch:-master}"
+               local_branch="$branch"
                if ! test -z "$update"
                then
                        update_module=$update
                else
                        update_module=$(git config submodule."$name".update)
-                       case "$update_module" in
-                       '')
-                               ;; # Unset update mode
-                       checkout | rebase | merge | none)
-                               ;; # Known update modes
-                       !*)
-                               ;; # Custom update command
-                       *)
-                               die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
-                               ;;
-                       esac
+                       if test -z "$update_module"
+                       then
+                               update_module="checkout"
+                       fi
                fi
  
                displaypath=$(relative_path "$prefix$sm_path")
  
-               if test "$update_module" = "none"
-               then
+               case "$update_module" in
+               none)
                        echo "Skipping submodule '$displaypath'"
                        continue
-               fi
+                       ;;
+               checkout)
+                       local_branch=""
+                       ;;
+               rebase | merge | !*)
+                       ;;
+               *)
+                       die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
+               esac
  
                if test -z "$url"
                then
@@@ -838,7 -858,8 +860,8 @@@ Maybe you want to use 'update --init'?"
  
                if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
                then
-                       module_clone "$sm_path" "$name" "$url" "$reference" "$depth" || exit
+                       start_point="origin/${branch}"
+                       module_clone "$sm_path" "$name" "$url" "$reference" "$depth" "$start_point" "$local_branch" || exit
                        cloned_modules="$cloned_modules;$name"
                        subsha1=
                else
                        case ";$cloned_modules;" in
                        *";$name;"*)
                                # then there is no local change to integrate
-                               update_module= ;;
+                               update_module='!git reset --hard -q'
                        esac
  
                        must_die_on_failure=
                        case "$update_module" in
+                       checkout)
+                               command="git checkout $subforce -q"
+                               die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
+                               say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
+                               ;;
                        rebase)
                                command="git rebase"
                                die_msg="$(eval_gettext "Unable to rebase '\$sha1' in submodule path '\$displaypath'")"
                                must_die_on_failure=yes
                                ;;
                        *)
-                               command="git checkout $subforce -q"
-                               die_msg="$(eval_gettext "Unable to checkout '\$sha1' in submodule path '\$displaypath'")"
-                               say_msg="$(eval_gettext "Submodule path '\$displaypath': checked out '\$sha1'")"
-                               ;;
+                               die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
                        esac
  
                        if (clear_local_git_env; cd "$sm_path" && $command "$sha1")
                                prefix="$prefix$sm_path/"
                                clear_local_git_env
                                cd "$sm_path" &&
 -                              eval cmd_update "$orig_flags"
 +                              eval cmd_update
                        )
                        res=$?
                        if test $res -gt 0
index 0246e80b1af98fe213b06beb8de0a9fec464b9f2,f056c01ba0874883014d36ed7d8f81c01b672106..28ca76384f6472b5d74564450ed122da9d49fe70
@@@ -63,6 -63,9 +63,9 @@@ test_expect_success 'setup a submodule 
         git submodule add ../none none &&
         test_tick &&
         git commit -m "none"
+       ) &&
+       (cd super &&
+        git tag initial-setup
        )
  '
  
@@@ -703,7 -706,7 +706,7 @@@ test_expect_success 'submodule update p
        git clone super_update_r super_update_r2 &&
        (cd super_update_r2 &&
         git submodule update --init --recursive >actual &&
-        test_i18ngrep "Submodule path .submodule/subsubmodule.: checked out" actual &&
+        test_i18ngrep "Submodule path .submodule/subsubmodule.: .git reset --hard -q" actual &&
         (cd submodule/subsubmodule &&
          git log > ../../expected
         ) &&
@@@ -762,17 -765,40 +765,50 @@@ test_expect_success 'submodule update c
         (cd submodule &&
          test 1 = $(git log --oneline | wc -l)
         )
 +)
 +'
 +
 +test_expect_success 'submodule update --recursive drops module name before recursing' '
 +      (cd super2 &&
 +       (cd deeper/submodule/subsubmodule &&
 +        git checkout HEAD^
 +       ) &&
 +       git submodule update --recursive deeper/submodule >actual &&
 +       test_i18ngrep "Submodule path .deeper/submodule/subsubmodule.: checked out" actual
        )
  '
  
+ test_expect_success 'submodule update --checkout clones detached HEAD' '
+       git clone super super4 &&
+       echo "detached HEAD" >expected &&
+       (cd super4 &&
+        git reset --hard initial-setup &&
+        git submodule init submodule &&
+        git submodule update >> /tmp/log 2>&1 &&
+        (cd submodule &&
+         git symbolic-ref HEAD > ../../actual ||
+         echo "detached HEAD" > ../../actual
+        )
+       ) &&
+       test_cmp actual expected &&
+       rm -rf super4
+ '
+ test_expect_success 'submodule update --merge clones attached HEAD' '
+       git clone super super4 &&
+       echo "refs/heads/master" >expected &&
+       (cd super4 &&
+        git reset --hard initial-setup &&
+        git submodule init submodule &&
+        git config submodule.submodule.update merge &&
+        git submodule update --merge &&
+        (cd submodule &&
+         git symbolic-ref HEAD > ../../actual ||
+         echo "detached HEAD" > ../../actual
+        )
+       ) &&
+       test_cmp actual expected &&
+       rm -rf super4
+ '
  test_done