4

Which functions can I use to sync/init/update all submodules (local repo) to the version in a remote branch?

The "Sync" (let's call it that, I don't mean git sync!) must also work when:

  • A submodule has been added only to the remote branch
  • Files within a submodule have been added/removed/modified locally. Tracked or untracked.
  • Submodules are removed (optional)

Essentially, I want the local repo to always be at exactly the same version as the remote branch. Without much fiddling whenever I change somthing in the submodules. So no manual ssh'ing to the server to init a new submodule, only for the deploy script to work...

Can this be achieved without cloning (aka. transferring) the entire repository? I chose git to have a secure, fast way to deploy my sources. But the only option I can think of, is to do a complete git clone --recursive and check out submodules at their respective tags next. In which case, rsync would probably do a better job of syncing files.

NoMad
  • 702
  • 2
  • 11
  • 27
  • Each submodule is its own repository too, so given top level repository R with three submodules S0, S1, S2, you have *four* repositories to worry about. But repositories are cheap—not as cheap as branches, but still reasonably cheap—if you use *reference clones*. The submodules are still a pain in the patootie, though. :-) – torek Mar 13 '17 at 10:17

2 Answers2

16

What about git submodule update --init --recursive? It will update the submodule to the right commit, initialize it if needed, and do this for all submodules, even when they are inside other submodules. If that doesn't discard changes, try git submodule foreach --recursive git reset --hard first.

oyvind
  • 1,429
  • 3
  • 14
  • 24
  • I checked out a submodule @v1 in the deploy branch and pushed that. git submodule update --init --recursive works, but when I run it again after pushing to the submodule repo, after tag v1, that change is pulled too by the submodule update – NoMad Mar 13 '17 at 10:50
  • Can you elaborate on what you want to happen and what actually happens? What do you commit where and what happens to the submodule? – oyvind Mar 13 '17 at 11:17
  • Huh, my comment didn't post... I've now solved the problem, which was `HEAD` of the submodule was @ `v2` after the `git submodule update --init --recursive`, but it should have been @ `v1`, the version checked out in myrepo. See my answer below – NoMad Mar 13 '17 at 12:09
2

First, manually add and check out needed submodules at their desired location and version. To update all submodules, but keep their respective version that is checked out in the repo containing them, one can use

git submodule update --init --recursive --rebase --force

The --rebase will cause git to check out the exact commit, that the submodule is checked out at in the containing repo.

This will fail if the local repo has changes made to submodule files, so we have to reset all submodules first. For script usage:

git submodule foreach 'git reset --hard && git checkout . && git clean -fdx'
git submodule update --init --recursive --rebase --force

The reset commands were taken straight from git undo all uncommitted changes - Let me know if something else is more appropriate for this usecase.

No extra config required, just check out the submodule @ desired commit or tag and push that change in the containing repo.

These commands satisfy my first 2 initial requirements: As long as git tracks the submodule, all changes are fully sync'd to "clients" that run the commands. If a submodule is removed, git clean can be run on the repository containing the submodule(s) to delete orohaned submodule files.

Community
  • 1
  • 1
NoMad
  • 702
  • 2
  • 11
  • 27