Search code examples
gitbashcommand-promptgit-submodules

Git command line - know if in submodule?


Is there any way in git to know if you're in a submodule? You can do thinks like git submodule foreach in the parent directory but I can't seem to come up with a generic way to show that you're in a submodule if you're in one, or in any of the child directories inside the submodule.

I guess you could find the repo root with git rev-parse --show-toplevel, and then cd-ing up a level, and finding the root of that repo again and then comparing the list of submodules to the current directory, but that seems so sticky...


Solution

  • Here is a shell function that you can use to detect this:

    function is_submodule() 
    {       
         (cd "$(git rev-parse --show-toplevel)/.." && 
          git rev-parse --is-inside-work-tree) | grep -q true
    }
    

    Edit In response to your proposed script:

    Looking good.

    • There is a bug in

      for line in $submodules; do cd "$parent_git/$line"; \
          if [[ `pwd` = $_git_dir ]]; then return 0; fi; \
      done
      

    because it won't cd back (so it would only work if the first submodule is a match). My version checks without changing directories; That could be done done by cd-ing in a subshell, but returning the exitcode is getting complicated that way

    • I don't know where you get $_git_dir from - I used basename(1) to get that information (see below).

    • There was also a problem with submodules containing a space in the name. In my version, there is still a problem with newlines in submodule names left, but I don't care enough to fix that. (Note the 'idiomatic' way to avoid having the while read in a subshell without needing new bash-isms like readarray)

    • finally declaring all the vars local fixes potential problems when using this inside other scripts (e.g. when the outer script uses the $path variable...)

    • I renamed _git_dir to top_level (which is less confusing, because GIT_DIR means something else)

    Remaining issues:

    • I don't know whether git supports it (I don't think so) but this script could fail if the submodule directory is a symlink (because "$top_level/.." might resolve outside the containing repository)

    • submodule names with newlines will not be recognized properly

    • I also suggest you trap errors (either with 'set -e', 'trap "return 1" ERR' or similar) -- not in my script/exercise for reader

    #!/bin/bash
    
    function is_submodule() {
        local top_level parent_git module_name path
        # Find the root of this git repo, then check if its parent dir is also a repo
        top_level="$(git rev-parse --show-toplevel)"
        module_name="$(basename "$top_level")"
        parent_git="$(cd "$top_level/.." && 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 "$top_level/../$path" ]];    then return 0; fi
            done < <(cd $parent_git && git submodule --quiet foreach 'echo $path' 2> /dev/null)
            #return 1
        fi
        return 1
    }
    

    Usage

    if is_submodule; then
        echo "In a submodule!"
    else
        echo "Not in a submodule"
    fi