From: "W. Trevor King" <wk...@tremily.us>

This allows users to checkout the current
superproject-recorded-submodule-sha as a branch, avoiding the detached
head state that the standard submodule update creates.  This may be
useful for the existing --rebase/--merge workflows which already avoid
detached heads.

It is also useful if you want easy tracking of upstream branches.  The
particular upstream branch to be tracked is configured locally with
.git/modules/<name>/config.  With the new option Ævar's suggested

  $ git submodule foreach 'git checkout $(git config --file $toplevel/.gitm
odules submodule.$name.branch) && git pull'

reduces to a

  $ git submodule update --branch

after each supermodule .gitmodules edit, and a

  $ git submodule foreach 'git pull'

whenever you feel like updating the submodules.  Your still on you're
own to commit (or not) the updated submodule hashes in the
superproject's .gitmodules.

Signed-off-by: W. Trevor King <wk...@tremily.us>
---
 Documentation/git-submodule.txt | 20 +++++++++++------
 git-submodule.sh                | 48 +++++++++++++++++++++++++++++----------
 t/t7406-submodule-update.sh     | 50 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 98 insertions(+), 20 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index d0b4436..34392a1 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -13,7 +13,7 @@ SYNOPSIS
              [-f|--force] [--reference <repository>] [--] <repository> [<path>]
 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
-'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
+'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--branch] [--rebase]
              [--reference <repository>] [--merge] [--recursive] [--] 
[<path>...]
 'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
              [commit] [--] [<path>...]
@@ -136,11 +136,11 @@ init::
 
 update::
        Update the registered submodules, i.e. clone missing submodules and
-       checkout the commit specified in the index of the containing repository.
-       This will make the submodules HEAD be detached unless `--rebase` or
-       `--merge` is specified or the key `submodule.$name.update` is set to
-       `rebase`, `merge` or `none`. `none` can be overridden by specifying
-       `--checkout`.
+       checkout the commit specified in the index of the containing
+       repository.  This will make the submodules HEAD be detached unless
+       `--branch`, `--rebase`, `--merge` is specified or the key
+       `submodule.$name.update` is set to `branch`, `rebase`, `merge` or
+       `none`. `none` can be overridden by specifying `--checkout`.
 +
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
@@ -207,7 +207,13 @@ OPTIONS
 
 -b::
 --branch::
-       Branch of repository to add as submodule.
+       When used with the add command, gives the branch of repository to
+       add as submodule.
++
+When used with the update command, checks out a branch named
+`submodule.<name>.branch` (as set by `--local-branch`) pointing at the
+current HEAD SHA-1.  This is useful for commands like `update
+--rebase` that do not work on detached heads.
 
 --local-branch::
        Record a branch name used as `submodule.<path>.branch` in
diff --git a/git-submodule.sh b/git-submodule.sh
index c51b6ae..28eb4b1 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
 USAGE="[--quiet] add [-b branch] [--local-branch[=<branch>]] [-f|--force] 
[--reference <repository>] [--] <repository> [<path>]
    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] init [--] [<path>...]
-   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] 
[--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] 
[--branch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] 
[<path>...]
    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] 
[commit] [--] [<path>...]
    or: $dashless [--quiet] foreach [--recursive] <command>
    or: $dashless [--quiet] sync [--] [<path>...]"
@@ -539,6 +539,9 @@ cmd_update()
                -f|--force)
                        force=$1
                        ;;
+               -b|--branch)
+                       update="branch"
+                       ;;
                -r|--rebase)
                        update="rebase"
                        ;;
@@ -593,6 +596,7 @@ cmd_update()
                fi
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
+               branch=$(git config submodule."$name".branch)
                if ! test -z "$update"
                then
                        update_module=$update
@@ -627,7 +631,7 @@ Maybe you want to use 'update --init'?")"
                        die "$(eval_gettext "Unable to find current revision in 
submodule path '\$sm_path'")"
                fi
 
-               if test "$subsha1" != "$sha1" -o -n "$force"
+               if test "$subsha1" != "$sha1" -o -n "$force" -o 
"$update_module" = "branch"
                then
                        subforce=$force
                        # If we don't already have a -f flag and the submodule 
has never been checked out
@@ -650,16 +654,21 @@ Maybe you want to use 'update --init'?")"
                        case ";$cloned_modules;" in
                        *";$name;"*)
                                # then there is no local change to integrate
-                               update_module= ;;
+                               case "$update_module" in
+                                       rebase|merge)
+                                               update_module=
+                                               ;;
+                               esac
+                               ;;
                        esac
 
                        must_die_on_failure=
                        case "$update_module" in
                        rebase)
                                command="git rebase"
-                               die_msg="$(eval_gettext "Unable to rebase 
'\$sha1' in submodule path '\$sm_path'")"
+                               die_msg="$(eval_gettext "Unable to rebase 
'\$sha1' in submodule path '\$sm_path'")"     
                                say_msg="$(eval_gettext "Submodule path 
'\$sm_path': rebased into '\$sha1'")"
-                               must_die_on_failure=yes
+                       must_die_on_failure=yes
                                ;;
                        merge)
                                command="git merge"
@@ -674,15 +683,30 @@ Maybe you want to use 'update --init'?")"
                                ;;
                        esac
 
-                       if (clear_local_git_env; cd "$sm_path" && $command 
"$sha1")
+                       if test "$subsha1" != "$sha1" -o -n "$force"
                        then
-                               say "$say_msg"
-                       elif test -n "$must_die_on_failure"
+                               if (clear_local_git_env; cd "$sm_path" && 
$command "$sha1")
+                               then
+                                       say "$say_msg"
+                               elif test -n "$must_die_on_failure"
+                               then
+                                       die_with_status 2 "$die_msg"
+                               else
+                                       err="${err};$die_msg"
+                                       continue
+                               fi
+                       fi
+
+                       if test "$update_module" = "branch" -a -n "$branch"
                        then
-                               die_with_status 2 "$die_msg"
-                       else
-                               err="${err};$die_msg"
-                               continue
+                               if (clear_local_git_env; cd "$sm_path" &&
+                                       git branch -f "$branch" "$sha1" &&
+                                       git checkout "$branch")
+                               then
+                                       say "$(eval_gettext "Submodule path 
'\$sm_path': checked out branch '\$branch'")"
+                               else
+                                       err="${err};$(eval_gettext "Unable to 
checkout branch '\$branch' in submodule path '\$sm_path'")"
+                               fi
                        fi
                fi
 
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 1542653..c876a8b 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -6,7 +6,8 @@
 test_description='Test updating submodules
 
 This test verifies that "git submodule update" detaches the HEAD of the
-submodule and "git submodule update --rebase/--merge" does not detach the HEAD.
+submodule and "git submodule update --branch/--rebase/--merge" does not
+detach the HEAD.
 '
 
 . ./test-lib.sh
@@ -135,6 +136,53 @@ test_expect_success 'submodule update --force forcibly 
checks out submodules' '
        )
 '
 
+test_expect_success 'submodule update --branch detaches without 
submodule.<name>.branch' '
+       (cd super/submodule &&
+         git checkout master
+       ) &&
+       (cd super &&
+        (cd submodule &&
+         compare_head
+        ) &&
+        git submodule update --branch submodule &&
+        (cd submodule &&
+         test "$(git status -s file)" = ""
+        )
+       )
+'
+
+test_expect_success 'submodule update --branch staying on master' '
+       (cd super/submodule &&
+         git checkout master
+       ) &&
+       (cd super &&
+        (cd submodule &&
+         compare_head
+        ) &&
+        git config submodule.submodule.branch master
+        git submodule update --branch submodule &&
+        cd submodule &&
+        test "refs/heads/master" = "$(git symbolic-ref -q HEAD)" &&
+        compare_head
+       )
+'
+
+test_expect_success 'submodule update --branch creating a new branch' '
+       (cd super/submodule &&
+         git checkout master
+       ) &&
+       (cd super &&
+        (cd submodule &&
+         compare_head
+        ) &&
+        git config submodule.submodule.branch new-branch
+        git submodule update --branch submodule &&
+        cd submodule &&
+        test "refs/heads/new-branch" = "$(git symbolic-ref -q HEAD)" &&
+        compare_head
+       )
+'
+
 test_expect_success 'submodule update --rebase staying on master' '
        (cd super/submodule &&
          git checkout master
-- 
1.8.0.3.g95edff1.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to