Merge branch 'jk/validate-headref-fix' into maint
[gitweb.git] / builtin / submodule--helper.c
index 3a3c9ca72b678f1a446013cc17cc36caa3e47355..895555c93a3bb86ad5511a2ded2350614732d618 100644 (file)
@@ -1108,9 +1108,28 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,
 static int push_check(int argc, const char **argv, const char *prefix)
 {
        struct remote *remote;
+       const char *superproject_head;
+       char *head;
+       int detached_head = 0;
+       struct object_id head_oid;
 
-       if (argc < 2)
-               die("submodule--helper push-check requires at least 1 argument");
+       if (argc < 3)
+               die("submodule--helper push-check requires at least 2 arguments");
+
+       /*
+        * superproject's resolved head ref.
+        * if HEAD then the superproject is in a detached head state, otherwise
+        * it will be the resolved head ref.
+        */
+       superproject_head = argv[1];
+       argv++;
+       argc--;
+       /* Get the submodule's head ref and determine if it is detached */
+       head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+       if (!head)
+               die(_("Failed to resolve HEAD as a valid ref."));
+       if (!strcmp(head, "HEAD"))
+               detached_head = 1;
 
        /*
         * The remote must be configured.
@@ -1133,18 +1152,30 @@ static int push_check(int argc, const char **argv, const char *prefix)
                        if (rs->pattern || rs->matching)
                                continue;
 
-                       /*
-                        * LHS must match a single ref
-                        * NEEDSWORK: add logic to special case 'HEAD' once
-                        * working with submodules in a detached head state
-                        * ceases to be the norm.
-                        */
-                       if (count_refspec_match(rs->src, local_refs, NULL) != 1)
+                       /* LHS must match a single ref */
+                       switch (count_refspec_match(rs->src, local_refs, NULL)) {
+                       case 1:
+                               break;
+                       case 0:
+                               /*
+                                * If LHS matches 'HEAD' then we need to ensure
+                                * that it matches the same named branch
+                                * checked out in the superproject.
+                                */
+                               if (!strcmp(rs->src, "HEAD")) {
+                                       if (!detached_head &&
+                                           !strcmp(head, superproject_head))
+                                               break;
+                                       die("HEAD does not match the named branch in the superproject");
+                               }
+                       default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
+                       }
                }
                free_refspec(refspec_nr, refspec);
        }
+       free(head);
 
        return 0;
 }