{"thread":{"id":"51293","subject":"push.recurseSubmodules=check doesn't consider tags","startedAt":"2019-06-12T02:04:47Z","lastAt":"2019-06-12T17:26:09Z","messageCount":2,"participants":["Scott Johnson","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"377048","messageId":"62F6F2E3-FAED-4EE9-BDB8-D484252A845F@arilinc.com","threadId":"51293","inReplyTo":null,"subject":"push.recurseSubmodules=check doesn't consider tags","fromName":"Scott Johnson","fromEmail":"scott.johnson@arilinc.com","sentAt":"2019-06-12T02:04:40Z","receivedAt":"2019-06-12T02:04:47Z","isPatch":false,"sender":{"key":"scott.johnson@arilinc.com","avatar":null},"body":"I occasionally rebase my submodules. I realize the danger (historical submodule pointers could point to commits that get garbage-collected away) so I always create and push a tag before the rebase, to make sure the old commits will never get purged. I believe this is safe, based on some experiments I’ve run.\n\nThe issue: I set the config var push.recurseSubmodules=check, and it seems to insist on having a branch and not merely a tag. When I push the parent repo’s commits, I get failures: \"The following submodule paths contain changes that can not be found on any remote”. This is overly pessimistic: the commits are there on the remote, and the tag demonstrates that.\n\nExpected behavior: when the submodule remote has a branch or a tag with the submodule pointer as ancestor, the push.recurseSubmodules=check should succeed.\n\nActual behavior: the push.recurseSubmodules=check fails when only a tag, and not any branch, contains the specific commit hash.\n\nI’m using Git 2.18.0, but I’ve checked newer Release Notes and didn’t see anything.\n\nBelow is a Makefile that demonstrates the unexpected failure. The “pre-rebase” tag should be sufficient to allow the check to succeed. Run this in an empty directory.\n----\n.PHONY: all clean\n\n# Make sure no config settings, either /etc/gitconfig or ~/.gitconfig,\n# affect this experiment. We will create our own ./.gitconfig.\nGIT := GIT_CONFIG_NOSYSTEM=1 HOME=$(PWD) XDG_CONFIG_HOME= git\n\nall:\n        # Configure globally (into ./.gitconfig)\n        $(GIT) config --global user.email \"you@example.com\"\n        $(GIT) config --global user.name \"Your Name\"\n        $(GIT) config --global push.recurseSubmodules check\n        # Create upstream repos\n        mkdir sub.git && cd sub.git && $(GIT) init --bare\n        mkdir repo.git && cd repo.git && $(GIT) init --bare\n        # Create local repos\n        $(GIT) clone repo.git repo\n        $(GIT) clone sub.git sub\n        # Populate submodule\n        cd sub && echo \"foo\" > foo && $(GIT) add foo && $(GIT) commit -m 'rev 1 of foo' && $(GIT) push\n        # Add submodule to parent repo\n        cd repo && $(GIT) submodule add ../sub.git && $(GIT) commit -m 'Add submodule' && $(GIT) push\n        # Track a new branch in the submodule\n        cd repo/sub && $(GIT) checkout -b aril && $(GIT) push -u origin aril\n        # Add commits to sub repo\n        cd repo/sub && echo \"bar\" > bar && $(GIT) add bar && $(GIT) commit -m 'Add bar' && $(GIT) push\n        cd repo/sub && echo \"foo2\" >> foo && $(GIT) commit -am 'Add more to foo' && $(GIT) push\n        # Update parent with new submodule commits. Note: no push\n        cd repo && $(GIT) add sub && $(GIT) commit -m 'Update sub'\n        # Sub's master branch diverges\n        cd sub && echo \"three\" > three && $(GIT) add three && $(GIT) commit -m 'Add three' && $(GIT) push\n        # Rebase submodule: this tag is enough to keep the old commits from being garbage collected\n        cd repo/sub && $(GIT) tag pre-rebase && $(GIT) push --tags origin\n        cd repo/sub && $(GIT) checkout master && $(GIT) pull --ff-only\n        cd repo/sub && $(GIT) checkout aril\n        cd repo/sub && $(GIT) rebase master && $(GIT) push --force-with-lease\n        # Update parent repo with newly rebased sub: this will FAIL due to push.recurseSubmodules=check unable to find HEAD^'s submodule pointer in any pushed branch in repo/sub\n        cd repo && $(GIT) add sub && $(GIT) commit -m 'Add rebased submodule' && $(GIT) push\n\nclean:\n        rm -rf repo repo2 repo.git sub sub.git .gitconfig\n\n"},{"id":"377091","messageId":"xmqqef3yk95i.fsf@gitster-ct.c.googlers.com","threadId":"51293","inReplyTo":"62F6F2E3-FAED-4EE9-BDB8-D484252A845F@arilinc.com","subject":"Re: push.recurseSubmodules=check doesn't consider tags","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-12T17:26:01Z","receivedAt":"2019-06-12T17:26:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Scott Johnson <scott.johnson@arilinc.com> writes:\n\n> I occasionally rebase my submodules. I realize the danger (historical submodule pointers could point to commits that get garbage-collected away) so I always create and push a tag before the rebase, to make sure the old commits will never get purged. I believe this is safe, based on some experiments I’ve run.\n>\n> The issue: I set the config var push.recurseSubmodules=check, and\n> it seems to insist on having a branch and not merely a tag.\n\nI suspect that this is pretty much by design.\n\nWhen deciding if it needs a push in a submodule repository,\nsubmodule.c::submodule_needs_pushing() gets called and asked to\ncheck what is available at the remote without actually making a\nconnection to the other side.  It is done by looking at the\nremote-tracking branches in the copy of the submodule repository we\nhave locally.  As there is no \"remote-tracking tags\" (iow, you\ncannot tell from the output of \"git -C submodule tag -l\" if each of\nthe tags you have locally in your copy of the submodule exists in\nanother repository you push to and fetch from), this process does\nnot look at refs/tags/ hierarchy of your copy of the submodule\nrepository and that is quite deliberate, I would think.\n"}]}