6

I have the following project structure:

root-project
      |
      |-- A
      |   |
      |   |-- C
      |
      |-- B

A and B are submodules of the root-project. C is in turn a submodule of project A. Suppose I have made changes to projects A,B and C and commited these changes to the respective indices. After that I update the references to A and B in the root-project and commit that change as well. When I push the changes of the root-project with the option --recurse-submodules=on-demand, git pushes all commits of projects A, B and the root-project, but silently ignores the commits of project C. I would expect that it pushes the changes of project C as well.

I know that i can work around this problem by using the following two commands in the root-project folder.

git submodule foreach --recursive 'git push origin master'
git push

Could someone clarify whether I'm doing something wrong or if this is a bug in git-push.I have already asked this question on the git mailing list but didn't receive any response: http://thread.gmane.org/gmane.comp.version-control.git/266184

I have also written a small shell script that sets up the described project structure and executes the recursive push operation: https://gist.github.com/usommerl/6e8defcba94bd4ba1438

git version 2.3.3

Uwe Sommerlatt
  • 129
  • 1
  • 9
  • Did you `git add C` in the `A` submodule first? Committing to a submodule is like saving changes to a file, you have to `git add` the new content. – jthill Apr 11 '15 at 16:08

2 Answers2

2

git push --recurse-submodules=on-demand will be truly recursive with git 2.14.x/2.15 (Q3 2017), but with some condition.

See commit c7be720 (20 Jul 2017) by Brandon Williams (mbrandonw).
(Merged by Junio C Hamano -- gitster -- in commit a49794d, 22 Aug 2017)

submodule--helper: teach push-check to handle HEAD

In 06bf4ad (push: propagate remote and refspec with --recurse-submodules, git 2.13.0) push was taught how to propagate a refspec down to submodules when the '--recurse-submodules' flag is given.

The only refspecs that are allowed to be propagated are ones which name a ref which exists in both the superproject and the submodule, with the caveat that 'HEAD' was disallowed.

This patch teaches push-check (the submodule helper which determines if a refspec can be propagated to a submodule) to permit propagating 'HEAD' if and only if:

  • the superproject and the submodule both have the same named branch checked out and
  • the submodule is not in a detached head state.
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thanks for your answer. I just build a version of git which includes the commit you mentioned (git version 2.14.1.459.g238e487). Unfortunately, this patch does not seem to resolve the described issue. Every repository in my [test script](https://gist.github.com/usommerl/6e8defcba94bd4ba1438) uses the same named branch (master) and none of the submodules is in a detached head state. – Uwe Sommerlatt Sep 04 '17 at 15:49
  • @UweSommerlatt OK. That is strange, as master should only be used when updating a submodule with the --remote option (it seeks to follow a default remote branch: master, see https://stackoverflow.com/q/37879715/6309) – VonC Sep 04 '17 at 15:53
0

Copy of my own answer

The command git push --recurse-submodules=on-demand does not work if you have submodules which contain submodules. (git version: 2.20.1)

Add the following alias in your ~/.gitconfig file:

[alias]
    push-all = "! find . -depth -name .git -exec dirname {} \\; 2> /dev/null | sort -n -r | xargs -I{} bash -c \"cd {}; git status | grep ahead > /dev/null && { echo '* Pushing: {}'; git push; }\""

Then issue git push-all in your parent git folder.

Explanation

  • !: We are issuing a non-git command.
  • find . -depth -name .git -exec dirname {} \\; 2> /dev/null : Find all submodules (and git repositories, which wouldn't harm)
  • | sort -n -r: Sort by path depth, deepest will be first.
  • | xargs -I{} bash -c \": Pass directories to the following commands:
    • cd {};: cd to the target directory.
    • git status | grep ahead > /dev/null: Test if it is necessary to push this repository.
    • && { echo '* Pushing: {}'; git push; }\"": Inform and push.
ceremcem
  • 3,900
  • 4
  • 28
  • 66