From: W. Trevor King Date: Thu, 09 Jan 2014 06:17:52 GMT Subject: [RFC v3 1/4] submodule: Add helpers for configurable local branches Message-ID: <684f061e58bd16e617f438be9d6ed7b8d913463b.1389247320.git.wking@tremily.us> In-Reply-To: From: "W. Trevor King" There are three branches that submodule folks usually care about: 1. The linked $sha1 in the superproject (set explicitly for every superproject commit, and thus for every superproject branch). 2. The remote-tracking submodule..branch that tracks a branch in upstream submodule..url repository. 3. The submodule's locally checked out branch, which we currently let the developer setup by hand, which is integrated with one of the other two branches by non-checkout update modes. Git is currently a bit weak on conveniently handling branch #3. "Just use what the developer has setup" works well for many basic workflows, but falls short for: * Cloning-updates, where we currently always setup a detached HEAD. This is easy to fix if you accept submodule..branch or the branch pointed to by the cloned repository's HEAD as a guess, but this conflates branch #2 and branch #3, which may confuse users. * Workflows where the preferred #3 branch depends on the superproject branch. For example, if the remote subproject has only a master branch, but the local superproject needs to develop several submodule feature branches simultaneously, you can have a situation like this: Superproject branch Submodule branch Subproject branch =================== ================ ================= master master master feature-1 feature-1 master feature-2 feature-2 master feature-3 feature-2 master In order to checkout the appropriate submodule branch for a given superproject branch, we need a way to specify the preferred submodule branch for a given superproject branch. This commit adds two helper functions: * get_current_branch, to determine which superproject branch you're on, and * get_local_branch, to determine the preferred submodule branch for that superproject branch. The lookup chain for the local-branch is: 1. superproject..local-branch in the submodule's config (superproject/.git/modules//config). This is where the developer can store local per-superproject-branch overrides (e.g. if they wanted to use submodule branch feature-1 with superproject branch feature-3). 2. submodule..local-branch in the superproject's config. This is where the developer can store local cross-superproject-branch overrides (e.g. if they wanted to use submodule branch master for any superproject branch that didn't have a per-superproject-branch override). 3. submodule..local-branch in the superproject's .gitmodules file. Because the gitmodules file is stored in the superproject's versioned tree, it is automatically superproject-branch-specific. For example: $ git cat-file -p feature-1:.gitmodules ... [submodule "submod"] ... local-branch = feature-1 $ git cat-file -p feature-3:.gitmodules ... [submodule "submod"] ... local-branch = feature-2 this is where the project-wide defaults are setup and shared between developers. 4. The default local-branch is 'master'. The new get_local_branch function handles the first step in this chain. The next two steps are already covered by the existing get_submodule_config. --- git-submodule.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/git-submodule.sh b/git-submodule.sh index 2677f2e..56fc3f1 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -220,6 +220,39 @@ get_submodule_config () { printf '%s' "${value:-$default}" } +# +# Print a submodule's configured local branch name +# +# $1 = superproject branch +# $2 = default (from the superproject's .gitmodules) +# +# To be called from the submodule root directory. +# +get_local_branch () +{ + superproject_branch="$1" + default="${2:-master}" + if test -z "${superproject_branch}" + then + value="" + else + value=$(git config superproject."$superproject_branch".local-branch) + fi + printf '%s' "${value:-$default}" +} + +# +# Print the currently checked out branch of the current repository +# +# $1 = default +# +get_current_branch () +{ + default="$1" + branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || + branch="" + printf '%s' "${branch:-$default}" +} # # Map submodule path to submodule name -- 1.8.5.2.237.g01c62c6