submodule: teach set-branch subcommand

This teaches git-submodule the set-branch subcommand which allows the branch of a submodule to be set through a porcelain command without having to manually manipulate the .gitmodules file. Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Denton Liu committed Feb 8, 2019 at 03:21 UTC b57e8119e6e08f731308923ef2b033eb45152bc6
4 files changed +175 -5
Documentation/git-submodule.txt
+7
@@ -14,6 +14,7 @@ SYNOPSIS
14 'git submodule' [--quiet] init [--] [<path>...]
15 'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)
16 'git submodule' [--quiet] update [<options>] [--] [<path>...]
17 +'git submodule' [--quiet] set-branch [<options>] [--] <path>
18 'git submodule' [--quiet] summary [<options>] [--] [<path>...]
19 'git submodule' [--quiet] foreach [--recursive] <command>
20 'git submodule' [--quiet] sync [--recursive] [--] [<path>...]
@@ -168,6 +169,12 @@ submodule with the `--init` option.
169 If `--recursive` is specified, this command will recurse into the
170 registered submodules, and update any nested submodules within.
171 --
172 +set-branch ((-d|--default)|(-b|--branch <branch>)) [--] <path>::
173 + Sets the default remote tracking branch for the submodule. The
174 + `--branch` option allows the remote branch to be specified. The
175 + `--default` option removes the submodule.<name>.branch configuration
176 + key, which causes the tracking branch to default to 'master'.
177 +
178 summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::
179 Show commit summary between the given commit (defaults to HEAD) and
180 working tree/index. For a submodule in question, a series of commits
contrib/completion/git-completion.bash
+4 -1
@@ -2573,7 +2573,7 @@ _git_submodule ()
2573 {
2574 __git_has_doubledash && return
2575
2576 - local subcommands="add status init deinit update summary foreach sync"
2576 + local subcommands="add status init deinit update set-branch summary foreach sync"
2577 local subcommand="$(__git_find_on_cmdline "$subcommands")"
2578 if [ -z "$subcommand" ]; then
2579 case "$cur" in
@@ -2604,6 +2604,9 @@ _git_submodule ()
2604 --force --rebase --merge --reference --depth --recursive --jobs
2605 "
2606 ;;
2607 + set-branch,--*)
2608 + __gitcomp "--default --branch"
2609 + ;;
2610 summary,--*)
2611 __gitcomp "--cached --files --summary-limit"
2612 ;;
git-submodule.sh
+71 -4
@@ -10,6 +10,7 @@ USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <re
10 or: $dashless [--quiet] init [--] [<path>...]
11 or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)
12 or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]
13 + or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>
14 or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
15 or: $dashless [--quiet] foreach [--recursive] <command>
16 or: $dashless [--quiet] sync [--recursive] [--] [<path>...]
@@ -684,6 +685,72 @@ cmd_update()
685 }
686 }
687
688 +#
689 +# Configures a submodule's default branch
690 +#
691 +# $@ = requested path
692 +#
693 +cmd_set_branch() {
694 + unset_branch=false
695 + branch=
696 +
697 + while test $# -ne 0
698 + do
699 + case "$1" in
700 + -q|--quiet)
701 + # we don't do anything with this but we need to accept it
702 + ;;
703 + -d|--default)
704 + unset_branch=true
705 + ;;
706 + -b|--branch)
707 + case "$2" in '') usage ;; esac
708 + branch=$2
709 + shift
710 + ;;
711 + --)
712 + shift
713 + break
714 + ;;
715 + -*)
716 + usage
717 + ;;
718 + *)
719 + break
720 + ;;
721 + esac
722 + shift
723 + done
724 +
725 + if test $# -ne 1
726 + then
727 + usage
728 + fi
729 +
730 + # we can't use `git submodule--helper name` here because internally, it
731 + # hashes the path so a trailing slash could lead to an unintentional no match
732 + name="$(git submodule--helper list "$1" | cut -f2)"
733 + if test -z "$name"
734 + then
735 + exit 1
736 + fi
737 +
738 + test -n "$branch"; has_branch=$?
739 + test "$unset_branch" = true; has_unset_branch=$?
740 +
741 + if test $((!$has_branch != !$has_unset_branch)) -eq 0
742 + then
743 + usage
744 + fi
745 +
746 + if test $has_branch -eq 0
747 + then
748 + git submodule--helper config submodule."$name".branch "$branch"
749 + else
750 + git submodule--helper config --unset submodule."$name".branch
751 + fi
752 +}
753 +
754 #
755 # Show commit summary for submodules in index or working tree
756 #
@@ -983,7 +1050,7 @@ cmd_absorbgitdirs()
1050 while test $# != 0 && test -z "$command"
1051 do
1052 case "$1" in
986 - add | foreach | init | deinit | update | status | summary | sync | absorbgitdirs)
1053 + add | foreach | init | deinit | update | set-branch | status | summary | sync | absorbgitdirs)
1054 command=$1
1055 ;;
1056 -q|--quiet)
@@ -1024,8 +1091,8 @@ then
1091 fi
1092 fi
1093
1027 -# "-b branch" is accepted only by "add"
1028 -if test -n "$branch" && test "$command" != add
1094 +# "-b branch" is accepted only by "add" and "set-branch"
1095 +if test -n "$branch" && (test "$command" != add || test "$command" != set-branch)
1096 then
1097 usage
1098 fi
@@ -1036,4 +1103,4 @@ then
1103 usage
1104 fi
1105
1039 -"cmd_$command" "$@"
1106 +"cmd_$(echo $command | sed -e s/-/_/g)" "$@"
t/t7419-submodule-set-branch.sh new
+93
@@ -0,0 +1,93 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2019 Denton Liu
4 +#
5 +
6 +test_description='Test submodules set-branch subcommand
7 +
8 +This test verifies that the set-branch subcommand of git-submodule is working
9 +as expected.
10 +'
11 +
12 +TEST_NO_CREATE_REPO=1
13 +. ./test-lib.sh
14 +
15 +test_expect_success 'submodule config cache setup' '
16 + mkdir submodule &&
17 + (cd submodule &&
18 + git init &&
19 + echo a >a &&
20 + git add . &&
21 + git commit -ma &&
22 + git checkout -b topic &&
23 + echo b >a &&
24 + git add . &&
25 + git commit -mb
26 + ) &&
27 + mkdir super &&
28 + (cd super &&
29 + git init &&
30 + git submodule add ../submodule &&
31 + git commit -m "add submodule"
32 + )
33 +'
34 +
35 +test_expect_success 'ensure submodule branch is unset' '
36 + (cd super &&
37 + test_must_fail grep branch .gitmodules
38 + )
39 +'
40 +
41 +test_expect_success 'test submodule set-branch --branch' '
42 + (cd super &&
43 + git submodule set-branch --branch topic submodule &&
44 + grep "branch = topic" .gitmodules &&
45 + git submodule update --remote &&
46 + cat <<-\EOF >expect &&
47 + b
48 + EOF
49 + git -C submodule show -s --pretty=%s >actual &&
50 + test_cmp expect actual
51 + )
52 +'
53 +
54 +test_expect_success 'test submodule set-branch --default' '
55 + (cd super &&
56 + git submodule set-branch --default submodule &&
57 + test_must_fail grep branch .gitmodules &&
58 + git submodule update --remote &&
59 + cat <<-\EOF >expect &&
60 + a
61 + EOF
62 + git -C submodule show -s --pretty=%s >actual &&
63 + test_cmp expect actual
64 + )
65 +'
66 +
67 +test_expect_success 'test submodule set-branch -b' '
68 + (cd super &&
69 + git submodule set-branch -b topic submodule &&
70 + grep "branch = topic" .gitmodules &&
71 + git submodule update --remote &&
72 + cat <<-\EOF >expect &&
73 + b
74 + EOF
75 + git -C submodule show -s --pretty=%s >actual &&
76 + test_cmp expect actual
77 + )
78 +'
79 +
80 +test_expect_success 'test submodule set-branch -d' '
81 + (cd super &&
82 + git submodule set-branch -d submodule &&
83 + test_must_fail grep branch .gitmodules &&
84 + git submodule update --remote &&
85 + cat <<-\EOF >expect &&
86 + a
87 + EOF
88 + git -C submodule show -s --pretty=%s >actual &&
89 + test_cmp expect actual
90 + )
91 +'
92 +
93 +test_done