Merge branch 'gj/push-more-verbose-advice'
authorJunio C Hamano <gitster@pobox.com>
Fri, 7 Mar 2014 23:17:20 +0000 (15:17 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 7 Mar 2014 23:17:20 +0000 (15:17 -0800)
1  2 
builtin/push.c
diff --combined builtin/push.c
index 3dd160c6b6a9a6af5010163f86b8a1ac2095dee1,e45e6cc252b787d6058954ac705d68bf1e0eb507..cd6c1646a5fa4009664f5c96a38d7c8df3fcd467
@@@ -34,75 -34,35 +34,75 @@@ static void add_refspec(const char *ref
        refspec[refspec_nr-1] = ref;
  }
  
 -static void set_refspecs(const char **refs, int nr)
 +static const char *map_refspec(const char *ref,
 +                             struct remote *remote, struct ref *local_refs)
  {
 +      struct ref *matched = NULL;
 +
 +      /* Does "ref" uniquely name our ref? */
 +      if (count_refspec_match(ref, local_refs, &matched) != 1)
 +              return ref;
 +
 +      if (remote->push) {
 +              struct refspec query;
 +              memset(&query, 0, sizeof(struct refspec));
 +              query.src = matched->name;
 +              if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
 +                  query.dst) {
 +                      struct strbuf buf = STRBUF_INIT;
 +                      strbuf_addf(&buf, "%s%s:%s",
 +                                  query.force ? "+" : "",
 +                                  query.src, query.dst);
 +                      return strbuf_detach(&buf, NULL);
 +              }
 +      }
 +
 +      if (push_default == PUSH_DEFAULT_UPSTREAM &&
 +          !prefixcmp(matched->name, "refs/heads/")) {
 +              struct branch *branch = branch_get(matched->name + 11);
 +              if (branch->merge_nr == 1 && branch->merge[0]->src) {
 +                      struct strbuf buf = STRBUF_INIT;
 +                      strbuf_addf(&buf, "%s:%s",
 +                                  ref, branch->merge[0]->src);
 +                      return strbuf_detach(&buf, NULL);
 +              }
 +      }
 +
 +      return ref;
 +}
 +
 +static void set_refspecs(const char **refs, int nr, const char *repo)
 +{
 +      struct remote *remote = NULL;
 +      struct ref *local_refs = NULL;
        int i;
 +
        for (i = 0; i < nr; i++) {
                const char *ref = refs[i];
                if (!strcmp("tag", ref)) {
 -                      char *tag;
 -                      int len;
 +                      struct strbuf tagref = STRBUF_INIT;
                        if (nr <= ++i)
                                die(_("tag shorthand without <tag>"));
 -                      len = strlen(refs[i]) + 11;
 -                      if (deleterefs) {
 -                              tag = xmalloc(len+1);
 -                              strcpy(tag, ":refs/tags/");
 -                      } else {
 -                              tag = xmalloc(len);
 -                              strcpy(tag, "refs/tags/");
 +                      ref = refs[i];
 +                      if (deleterefs)
 +                              strbuf_addf(&tagref, ":refs/tags/%s", ref);
 +                      else
 +                              strbuf_addf(&tagref, "refs/tags/%s", ref);
 +                      ref = strbuf_detach(&tagref, NULL);
 +              } else if (deleterefs) {
 +                      struct strbuf delref = STRBUF_INIT;
 +                      if (strchr(ref, ':'))
 +                              die(_("--delete only accepts plain target ref names"));
 +                      strbuf_addf(&delref, ":%s", ref);
 +                      ref = strbuf_detach(&delref, NULL);
 +              } else if (!strchr(ref, ':')) {
 +                      if (!remote) {
 +                              /* lazily grab remote and local_refs */
 +                              remote = remote_get(repo);
 +                              local_refs = get_local_heads();
                        }
 -                      strcat(tag, refs[i]);
 -                      ref = tag;
 -              } else if (deleterefs && !strchr(ref, ':')) {
 -                      char *delref;
 -                      int len = strlen(ref)+1;
 -                      delref = xmalloc(len+1);
 -                      strcpy(delref, ":");
 -                      strcat(delref, ref);
 -                      ref = delref;
 -              } else if (deleterefs)
 -                      die(_("--delete only accepts plain target ref names"));
 +                      ref = map_refspec(ref, remote, local_refs);
 +              }
                add_refspec(ref);
        }
  }
@@@ -216,7 -176,7 +216,7 @@@ N_("push.default is unset; its implici
     "When push.default is set to 'matching', git will push local branches\n"
     "to the remote branches that already exist with the same name.\n"
     "\n"
-    "In Git 2.0, Git will default to the more conservative 'simple'\n"
+    "Since Git 2.0, Git defaults to the more conservative 'simple'\n"
     "behavior, which only pushes the current branch to the corresponding\n"
     "remote branch that 'git pull' uses to update the current branch.\n"
     "\n"
@@@ -524,7 -484,7 +524,7 @@@ int cmd_push(int argc, const char **arg
  
        if (argc > 0) {
                repo = argv[0];
 -              set_refspecs(argv + 1, argc - 1);
 +              set_refspecs(argv + 1, argc - 1, repo);
        }
  
        rc = do_push(repo, flags);