git push --recurse-submodules=on-demand is not truly recursive
Asked Answered
H

2

8

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

Husky answered 10/4, 2015 at 14:40 Comment(1)
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.Roley
E
4

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.
Estipulate answered 31/8, 2017 at 19:20 Comment(2)
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 uses the same named branch (master) and none of the submodules is in a detached head state.Husky
@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://mcmap.net/q/13322/-git-track-branch-in-submodule-but-commit-in-other-submodule-possibly-nested/6309)Estipulate
Q
1

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.
Querida answered 29/1, 2021 at 13:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.