Search code examples
gitrepositorygit-submodulescheckout

Why is `git submodules add` storing the GIT information in the parent .git?


Doing git submodule add is just creating a ".git" file that points to a parent GIT folder containing the data. Example:

enter image description here

Why are submodules store in the parent and how can I prevent GIT from doing this? I want to keep a consistent structure like other modules I have, in which each project has their own ".git" folder sitting next to the where the project data is stored.


Solution

  • At the beginning submodules worked the way you described. But later Git developers decided to change to the current way of using .git file (named gitlink) and push .git/ directory under superproject's .git/modules/. To fix existing repositories they created git submodule absorbgitdirs. So you can see they do all their best to do things the current way and there is no way to return to the original way of storing .git/ directory in the submodules. You can move it back manually and fix .git/config. This is how I managed to do this for one submodule:

    #! /bin/sh
    set -e
    
    # To the top-level directory of the current submodule
    cd "`git rev-parse --show-toplevel`"
    
    unset GIT_DIR
    
    # If .git/ subdirectory is already here
    test -d .git && exit 0
    
    if ! test -f .git; then
        echo "Error: Cannot find gitlink, aborting" >&2
        exit 1
    fi
    
    # Fix core.worktree now
    git config --unset core.worktree
    
    read _gitdir gitpath < .git
    unset _gitdir
    rm .git
    exec mv "$gitpath" .git
    

    I failed to run it from git submodule foreach --recursive because the command runs from top to bottom while my scripts can only be run from bottom to top (it doesn't fix children's .git links).

    Upd. This is recursive variant:

    #! /bin/sh
    # The script cannot be run with `git submodule foreach --recursive`
    # because the command runs recursively from top to bottom
    # while the command is required to be run from bottom to top
    # because it doesn't fix childrens' gitlinks.
    # So the script runs recursion itself;
    # it can be run with `git submodule foreach` without `--recursive`.
    set -e
    
    START_DIR="`pwd`"
    cd "`dirname \"$0\"`"
    PROG_DIR="`pwd`"
    cd "$START_DIR"
    
    # To the top-level directory of the current submodule or the superproject
    cd "`git rev-parse --show-toplevel`"
    
    unset GIT_DIR
    
    # If .git/ subdirectory is already here
    test -d .git && exit 0
    
    if ! test -f .git; then
        echo "Error: Cannot find gitlink, aborting" >&2
        exit 1
    fi
    
    if test -f .gitmodules; then
        git submodule foreach "$PROG_DIR"/"`basename \"$0\"`"
    fi
    
    # Fix core.worktree now
    git config --unset core.worktree
    
    read _gitdir gitpath < .git
    unset _gitdir
    rm .git
    exec mv "$gitpath" .git
    

    Or may be you can install VERY old Git, clone with submodules in the old way, then use newer Git to work as usual.