push, fetch: error out for submodule entries not pointing to commits

The check_has_commit helper uses resolves a submodule entry to a commit, when validating its existence. As a side effect this means tolerates a submodule entry pointing to a tag, which is not a valid submodule entry that git commands would know how to cope with. Tighten the check to require an actual commit, not a tag pointing to a commit. Also improve the error handling when a submodule entry points to non-commit (e.g., a blob) to error out instead of warning and pretending the pointed to object doesn't exist. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stefan Beller committed Sep 12, 2017 at 10:30 UTC 3c96aa97232367a24eef8b3b387f5ddae5b0c10f
2 files changed +35 -8
submodule.c
+25 -8
@@ -767,19 +767,36 @@ static int append_oid_to_argv(const struct object_id *oid, void *data)
767 return 0;
768 }
769
770 +struct has_commit_data {
771 + int result;
772 + const char *path;
773 +};
774 +
775 static int check_has_commit(const struct object_id *oid, void *data)
776 {
772 - int *has_commit = data;
777 + struct has_commit_data *cb = data;
778
774 - if (!lookup_commit_reference(oid))
775 - *has_commit = 0;
779 + enum object_type type = sha1_object_info(oid->hash, NULL);
780
777 - return 0;
781 + switch (type) {
782 + case OBJ_COMMIT:
783 + return 0;
784 + case OBJ_BAD:
785 + /*
786 + * Object is missing or invalid. If invalid, an error message
787 + * has already been printed.
788 + */
789 + cb->result = 0;
790 + return 0;
791 + default:
792 + die(_("submodule entry '%s' (%s) is a %s, not a commit"),
793 + cb->path, oid_to_hex(oid), typename(type));
794 + }
795 }
796
797 static int submodule_has_commits(const char *path, struct oid_array *commits)
798 {
782 - int has_commit = 1;
799 + struct has_commit_data has_commit = { 1, path };
800
801 /*
802 * Perform a cheap, but incorrect check for the existence of 'commits'.
@@ -795,7 +812,7 @@ static int submodule_has_commits(const char *path, struct oid_array *commits)
812
813 oid_array_for_each_unique(commits, check_has_commit, &has_commit);
814
798 - if (has_commit) {
815 + if (has_commit.result) {
816 /*
817 * Even if the submodule is checked out and the commit is
818 * present, make sure it exists in the submodule's object store
@@ -814,12 +831,12 @@ static int submodule_has_commits(const char *path, struct oid_array *commits)
831 cp.dir = path;
832
833 if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len)
817 - has_commit = 0;
834 + has_commit.result = 0;
835
836 strbuf_release(&out);
837 }
838
822 - return has_commit;
839 + return has_commit.result;
840 }
841
842 static int submodule_needs_pushing(const char *path, struct oid_array *commits)
t/t5531-deep-submodule-push.sh
+10
@@ -298,6 +298,16 @@ test_expect_success 'push succeeds if submodule commit disabling recursion from
298 )
299 '
300
301 +test_expect_success 'submodule entry pointing at a tag is error' '
302 + git -C work/gar/bage tag -a test1 -m "tag" &&
303 + tag=$(git -C work/gar/bage rev-parse test1^{tag}) &&
304 + git -C work update-index --cacheinfo 160000 "$tag" gar/bage &&
305 + git -C work commit -m "bad commit" &&
306 + test_when_finished "git -C work reset --hard HEAD^" &&
307 + test_must_fail git -C work push --recurse-submodules=on-demand ../pub.git master 2>err &&
308 + test_i18ngrep "is a tag, not a commit" err
309 +'
310 +
311 test_expect_success 'push fails if recurse submodules option passed as yes' '
312 (
313 cd work/gar/bage &&