Home > OS >  git submodule replacement that doesn't detach heads
git submodule replacement that doesn't detach heads

Time:01-10

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?


Answers to

git is newish: version 2.32;

Trial 1:

Machine a) add file to submodule, commit/push submodule.
Machine b) git submodule update --remote --merge

The added file is successfully propagated. However, the top level modules are now dirty and have to be pulled and pushed and pulled and pushed and pulled and pushed on the different machines to get everything in sync.

But if I make a change (submodule machine a; then pushed) and then git pull at the machine b top level (with submodule.recurse set so it pulls submodules) then the change is propagated, BUT the head is detached in the machine b submodule.


Getting closer: I have removed the submodule.recurse=True so that git pull at the top doesn't pull-and-detach each submodule. I have added aliases for pulling and status:

git config alias.pullall 'submodule foreach git pull'
git config alias.statusall 'submodule foreach git status'

and will add a fixheads alias when I figure out how to use the ${sm_path} variable with the right level of indirection.

CodePudding user response:

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
  •  Tags:  
  • Related