> Rework of the first patch. The prompt now will look like this: > (+name:master). I tried to considere all suggestions. > Tests still missing. > > Signed-off-by: Benjamin Fuchs <email@xxxxxxxxxxxxxxxx> > --- > contrib/completion/git-prompt.sh | 49 ++++++++++++++++++++-------------------- > 1 file changed, 24 insertions(+), 25 deletions(-) > > diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh > index 4c82e7f..c44b9a2 100644 > --- a/contrib/completion/git-prompt.sh > +++ b/contrib/completion/git-prompt.sh > @@ -95,8 +95,10 @@ > # repository level by setting bash.hideIfPwdIgnored to "false". > # > # If you would like __git_ps1 to indicate that you are in a submodule, > -# set GIT_PS1_SHOWSUBMODULE. In this case a "sub:" will be added before > -# the branch name. > +# set GIT_PS1_SHOWSUBMODULE to a nonempty value. In this case the name > +# of the submodule will be prepended to the branch name (e.g. module:master). > +# The name will be prepended by "+" if the currently checked out submodule > +# commit does not match the SHA-1 found in the index of the containing repository. > > # check whether printf supports -v > __git_printf_supports_v= > @@ -288,30 +290,27 @@ __git_eread () > test -r "$f" && read "$@" <"$f" > } > > -# __git_is_submodule > -# Based on: > -# http://stackoverflow.com/questions/7359204/git-command-line-know-if-in-submodule > -__git_is_submodule () > -{ > - local git_dir parent_git module_name path > - # Find the root of this git repo, then check if its parent dir is also a repo > - git_dir="$(git rev-parse --show-toplevel)" > - module_name="$(basename "$git_dir")" > - parent_git="$(cd "$git_dir/.." && git rev-parse --show-toplevel 2> /dev/null)" > - if [[ -n $parent_git ]]; then > - # List all the submodule paths for the parent repo > - while read path > - do > - if [[ "$path" != "$module_name" ]]; then continue; fi > - if [[ -d "$git_dir/../$path" ]]; then return 0; fi > - done < <(cd $parent_git && git submodule --quiet foreach 'echo $path' 2> /dev/null) > - fi > - return 1 > -} > - > +# __git_ps1_submodule > +# > +# $1 - git_dir path > +# > +# Returns the name of the submodule if we are currently inside one. The name > +# will be prepended by "+" if the currently checked out submodule commit does > +# not match the SHA-1 found in the index of the containing repository. > +# NOTE: git_dir looks like in a ... > +# - submodule: "GIT_PARENT/.git/modules/PATH_TO_SUBMODULE" > +# - parent: "GIT_PARENT/.git" (exception "." in .git) > __git_ps1_submodule () > { > - __git_is_submodule && printf "sub:" > + local git_dir="$1" > + local submodule_name="$(basename "$git_dir")" > + if [ "$submodule_name" != ".git" ] && [ "$submodule_name" != "." ]; then > + local parent_top="${git_dir%.git*}" > + local submodule_top="${git_dir#*modules}" > + local status="" > + git diff -C "$parent_top" --no-ext-diff --ignore-submodules=dirty --quiet -- "$submodule_top" 2>/dev/null || status="+" This 'git diff' has to read the index of the parent repository, right? That can be potentially very expensive, if the parent repository, and thus its index, is big. You might want to provide finer granularity controls and separate the "$PWD is in a submodule" indicator from the "submodule commit doesn't match" indicator. Even if someone is in general interested in the former, he might have some huge repositories where he would prefer to disable the latter, because executing 'git diff' would make the prompt lag. I'm not sure we need brand new control knobs, though. Perhaps we can get away by checking the env and config variables used for the dirty index and worktree status indicator, after all they, too, are about whether to run 'git diff' for the prompt in a repository or not. > + printf "$status$submodule_name:" > + fi > } > > # __git_ps1 accepts 0 or 1 arguments (i.e., format string) > @@ -545,7 +544,7 @@ __git_ps1 () > > local sub="" > if [ -n "${GIT_PS1_SHOWSUBMODULE}" ]; then > - sub="$(__git_ps1_submodule)" > + sub="$(__git_ps1_submodule $g)" In Bash, and in shells in general, the visibility of variables works differently than in "regular" programming languages: - Any variable existing in a caller, even the ones declared as 'local' in the caller, are visible in all callees. This means you don't have to pass $g as parameter to __git_ps1_submodule(), because you can access it inside that function directly. This has the benefit that there is one less place where you can forget to quote a path variable :) - If the callee modifies any variable that isn't declared as local in the callee, then the caller will see the modified value of that variable, unless the callee was invoked in a subshell. Here your sole purpose is to set $sub to something like "+sub:", which is determined in __git_ps1_submodule(). You don't need the command substitution for that, you can set $sub directly in __git_ps1_submodule(), sparing the overhead of fork()ing a subshell. That's important for the sake of git users on Windows. > fi > > local f="$w$i$s$u" -- 2.7.4