My situation: I have a large number of computers that I use for various tasks. I have a large number of libraries, each in its own git repo.
My desire: I want to be able to modify one of the libraries on any computer, do a git commit/push; then go to another computer, do a git pull
, and have all the libraries updated. Then I modify one of these libraries, commit/push, and everything works when I get tot he next computer.
My current attempt: I have a top-level git project that incorporates all the other library repos as submodules. This includes a .gitmodules file that specifies the working branch of each module by using
git config -f .gitmodules submodule.modulename.branch develop
I have update = merge
set for each module.
I have submodule.recurse
set to true, so git pull
at the top level does something to each module.
How it is broken: Heads become detached. I wrote a script that parses the .gitmodules
file and does a checkout
of the appropriate branch of each module. I then commit
and push
the top module. Whenever I modify things and try to do a pull, e.g. on another machine, heads become detached. If I don't notice that the head is detached before I start modifications, I have to carefully unscramble the wreckage before I can commit my changes.
There are literally 3.6k stack overflow questions about git detached heads over the past decade, and most seem to be from the submodule capability. I haven't gone through all of them, but what I have tried isn't working.
I forget why I rejected git-subtree
, but git-subrepo
hasn't been touched in over a year and has 153 issues and 25 pull requests pending, so I think it's dead.
Does anyone have a working solution to this?
I could probably streamline this a bit, but my readme for the top-level project now says:
git clone --recursive --jobs=8 *mysuperproject_clone_url*
cd *mysuperproject*
git config alias.pullall 'submodule foreach git pull'
git config alias.statusall 'submodule foreach git status'
git config alias.switchall \
"submodule foreach --recursive 'git switch \$(git config -f \${toplevel}/.gitmodules submodule.\${sm_path}.branch)'"
git switchall
git pullall
git switchall
Module named newmodule
working on path develop
in the following example.
cd /path/to/mysuperproject
git submodule add git@github.com:myaccount/newmodule
git config -f .gitmodules submodule.newmodule.branch develop
git config -f .gitmodules submodule.newmodule.update merge
If the submodule is on the default master
branch, you still have to config the branch.
If you switch a submodule to a different branch, then in the top level you must config again
git config -f .gitmodules submodule.newmodule.branch newbranch
And push both the submodule and the top level project.
On a different working directory (such as on a different machine), you must
cd /path/to/mysuperproject
git pull
git switchall
git pullall
I mentioned before that git submodule update --remote --merge
is supposed to not detached the HEAD of a submodule following a branch.
I understand you have set update = merge
, but just for testing, try the complete update command, to see if this works.
Since the HEAD is still detached, you need to add (to a git alias script for instance) the command
git submodule foreach --recursive git switch $(git config -f .gitmodules submodule.${sm_path}.branch)
I just tested it:
First, in the Git repository, I check the submodule is in a detached HEAD mode:
vonc@vclp MINGW64 ~/git/git (master)
$ git submodule update --init
Submodule 'sha1collisiondetection' (https://github.com/cr-marcstevens/sha1collisiondetection.git) registered for path 'sha1collisiondetection'
Cloning into 'C:/Users/vonc/git/git/sha1collisiondetection'...
Submodule path 'sha1collisiondetection': checked out '855827c583bc30645ba427885caa40c5b81764d2'
vonc@vclp MINGW64 ~/git/git/sha1collisiondetection (master)
$ git br
* (HEAD detached at 855827c)
master
Then I define my alias, with escaped $
: \$
.
No need for ../
when accessing the .gitmodules
file. That is what $toplevel
is for.
vonc@vclp MINGW64 ~/git/git (master)
$ git config alias.switchall \
"submodule foreach --recursive 'git switch \$(git config -f \${toplevel}/.gitmodules submodule.\${sm_path}.branch)'"
Final test:
vonc@vclp MINGW64 ~/git/git (master)
$ git switchall
Entering 'sha1collisiondetection'
Previous HEAD position was 855827c Detect endianess on HP-UX
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
vonc@vclp MINGW64 ~/git/git (tmp)
$ cd sha1collisiondetection/
vonc@vclp MINGW64 ~/git/git/sha1collisiondetection (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
vonc@vclp MINGW64 ~/git/git/sha1collisiondetection (master)
$ git branch
* master