Code

Merge branch 'db/push-single-with-HEAD'
authorJunio C Hamano <gitster@pobox.com>
Wed, 27 Feb 2008 19:54:28 +0000 (11:54 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 27 Feb 2008 19:54:28 +0000 (11:54 -0800)
* db/push-single-with-HEAD:
  Resolve value supplied for no-colon push refspecs

1  2 
remote.c
t/t5516-fetch-push.sh

diff --combined remote.c
index 1f836967588456b03c1390157ca04aad7b8e3eac,8ee2487ed3af70685e6e30e46373cd3cbc6ff074..45560d900fec047346fa09c1847ed36b8139da26
+++ b/remote.c
  #include "remote.h"
  #include "refs.h"
  
 +struct counted_string {
 +      size_t len;
 +      const char *s;
 +};
 +struct rewrite {
 +      const char *base;
 +      size_t baselen;
 +      struct counted_string *instead_of;
 +      int instead_of_nr;
 +      int instead_of_alloc;
 +};
 +
  static struct remote **remotes;
 -static int allocated_remotes;
 +static int remotes_alloc;
 +static int remotes_nr;
  
  static struct branch **branches;
 -static int allocated_branches;
 +static int branches_alloc;
 +static int branches_nr;
  
  static struct branch *current_branch;
  static const char *default_remote_name;
  
 +static struct rewrite **rewrite;
 +static int rewrite_alloc;
 +static int rewrite_nr;
 +
  #define BUF_SIZE (2048)
  static char buffer[BUF_SIZE];
  
 +static const char *alias_url(const char *url)
 +{
 +      int i, j;
 +      char *ret;
 +      struct counted_string *longest;
 +      int longest_i;
 +
 +      longest = NULL;
 +      longest_i = -1;
 +      for (i = 0; i < rewrite_nr; i++) {
 +              if (!rewrite[i])
 +                      continue;
 +              for (j = 0; j < rewrite[i]->instead_of_nr; j++) {
 +                      if (!prefixcmp(url, rewrite[i]->instead_of[j].s) &&
 +                          (!longest ||
 +                           longest->len < rewrite[i]->instead_of[j].len)) {
 +                              longest = &(rewrite[i]->instead_of[j]);
 +                              longest_i = i;
 +                      }
 +              }
 +      }
 +      if (!longest)
 +              return url;
 +
 +      ret = malloc(rewrite[longest_i]->baselen +
 +                   (strlen(url) - longest->len) + 1);
 +      strcpy(ret, rewrite[longest_i]->base);
 +      strcpy(ret + rewrite[longest_i]->baselen, url + longest->len);
 +      return ret;
 +}
 +
  static void add_push_refspec(struct remote *remote, const char *ref)
  {
 -      int nr = remote->push_refspec_nr + 1;
 -      remote->push_refspec =
 -              xrealloc(remote->push_refspec, nr * sizeof(char *));
 -      remote->push_refspec[nr-1] = ref;
 -      remote->push_refspec_nr = nr;
 +      ALLOC_GROW(remote->push_refspec,
 +                 remote->push_refspec_nr + 1,
 +                 remote->push_refspec_alloc);
 +      remote->push_refspec[remote->push_refspec_nr++] = ref;
  }
  
  static void add_fetch_refspec(struct remote *remote, const char *ref)
  {
 -      int nr = remote->fetch_refspec_nr + 1;
 -      remote->fetch_refspec =
 -              xrealloc(remote->fetch_refspec, nr * sizeof(char *));
 -      remote->fetch_refspec[nr-1] = ref;
 -      remote->fetch_refspec_nr = nr;
 +      ALLOC_GROW(remote->fetch_refspec,
 +                 remote->fetch_refspec_nr + 1,
 +                 remote->fetch_refspec_alloc);
 +      remote->fetch_refspec[remote->fetch_refspec_nr++] = ref;
  }
  
  static void add_url(struct remote *remote, const char *url)
  {
 -      int nr = remote->url_nr + 1;
 -      remote->url =
 -              xrealloc(remote->url, nr * sizeof(char *));
 -      remote->url[nr-1] = url;
 -      remote->url_nr = nr;
 +      ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
 +      remote->url[remote->url_nr++] = url;
 +}
 +
 +static void add_url_alias(struct remote *remote, const char *url)
 +{
 +      add_url(remote, alias_url(url));
  }
  
  static struct remote *make_remote(const char *name, int len)
  {
 -      int i, empty = -1;
 +      struct remote *ret;
 +      int i;
  
 -      for (i = 0; i < allocated_remotes; i++) {
 -              if (!remotes[i]) {
 -                      if (empty < 0)
 -                              empty = i;
 -              } else {
 -                      if (len ? (!strncmp(name, remotes[i]->name, len) &&
 -                                 !remotes[i]->name[len]) :
 -                          !strcmp(name, remotes[i]->name))
 -                              return remotes[i];
 -              }
 +      for (i = 0; i < remotes_nr; i++) {
 +              if (len ? (!strncmp(name, remotes[i]->name, len) &&
 +                         !remotes[i]->name[len]) :
 +                  !strcmp(name, remotes[i]->name))
 +                      return remotes[i];
        }
  
 -      if (empty < 0) {
 -              empty = allocated_remotes;
 -              allocated_remotes += allocated_remotes ? allocated_remotes : 1;
 -              remotes = xrealloc(remotes,
 -                                 sizeof(*remotes) * allocated_remotes);
 -              memset(remotes + empty, 0,
 -                     (allocated_remotes - empty) * sizeof(*remotes));
 -      }
 -      remotes[empty] = xcalloc(1, sizeof(struct remote));
 +      ret = xcalloc(1, sizeof(struct remote));
 +      ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
 +      remotes[remotes_nr++] = ret;
        if (len)
 -              remotes[empty]->name = xstrndup(name, len);
 +              ret->name = xstrndup(name, len);
        else
 -              remotes[empty]->name = xstrdup(name);
 -      return remotes[empty];
 +              ret->name = xstrdup(name);
 +      return ret;
  }
  
  static void add_merge(struct branch *branch, const char *name)
  {
 -      int nr = branch->merge_nr + 1;
 -      branch->merge_name =
 -              xrealloc(branch->merge_name, nr * sizeof(char *));
 -      branch->merge_name[nr-1] = name;
 -      branch->merge_nr = nr;
 +      ALLOC_GROW(branch->merge_name, branch->merge_nr + 1,
 +                 branch->merge_alloc);
 +      branch->merge_name[branch->merge_nr++] = name;
  }
  
  static struct branch *make_branch(const char *name, int len)
  {
 -      int i, empty = -1;
 +      struct branch *ret;
 +      int i;
        char *refname;
  
 -      for (i = 0; i < allocated_branches; i++) {
 -              if (!branches[i]) {
 -                      if (empty < 0)
 -                              empty = i;
 -              } else {
 -                      if (len ? (!strncmp(name, branches[i]->name, len) &&
 -                                 !branches[i]->name[len]) :
 -                          !strcmp(name, branches[i]->name))
 -                              return branches[i];
 -              }
 +      for (i = 0; i < branches_nr; i++) {
 +              if (len ? (!strncmp(name, branches[i]->name, len) &&
 +                         !branches[i]->name[len]) :
 +                  !strcmp(name, branches[i]->name))
 +                      return branches[i];
        }
  
 -      if (empty < 0) {
 -              empty = allocated_branches;
 -              allocated_branches += allocated_branches ? allocated_branches : 1;
 -              branches = xrealloc(branches,
 -                                 sizeof(*branches) * allocated_branches);
 -              memset(branches + empty, 0,
 -                     (allocated_branches - empty) * sizeof(*branches));
 -      }
 -      branches[empty] = xcalloc(1, sizeof(struct branch));
 +      ALLOC_GROW(branches, branches_nr + 1, branches_alloc);
 +      ret = xcalloc(1, sizeof(struct branch));
 +      branches[branches_nr++] = ret;
        if (len)
 -              branches[empty]->name = xstrndup(name, len);
 +              ret->name = xstrndup(name, len);
        else
 -              branches[empty]->name = xstrdup(name);
 +              ret->name = xstrdup(name);
        refname = malloc(strlen(name) + strlen("refs/heads/") + 1);
        strcpy(refname, "refs/heads/");
 -      strcpy(refname + strlen("refs/heads/"),
 -             branches[empty]->name);
 -      branches[empty]->refname = refname;
 +      strcpy(refname + strlen("refs/heads/"), ret->name);
 +      ret->refname = refname;
 +
 +      return ret;
 +}
 +
 +static struct rewrite *make_rewrite(const char *base, int len)
 +{
 +      struct rewrite *ret;
 +      int i;
 +
 +      for (i = 0; i < rewrite_nr; i++) {
 +              if (len
 +                  ? (len == rewrite[i]->baselen &&
 +                     !strncmp(base, rewrite[i]->base, len))
 +                  : !strcmp(base, rewrite[i]->base))
 +                      return rewrite[i];
 +      }
  
 -      return branches[empty];
 +      ALLOC_GROW(rewrite, rewrite_nr + 1, rewrite_alloc);
 +      ret = xcalloc(1, sizeof(struct rewrite));
 +      rewrite[rewrite_nr++] = ret;
 +      if (len) {
 +              ret->base = xstrndup(base, len);
 +              ret->baselen = len;
 +      }
 +      else {
 +              ret->base = xstrdup(base);
 +              ret->baselen = strlen(base);
 +      }
 +      return ret;
 +}
 +
 +static void add_instead_of(struct rewrite *rewrite, const char *instead_of)
 +{
 +      ALLOC_GROW(rewrite->instead_of, rewrite->instead_of_nr + 1, rewrite->instead_of_alloc);
 +      rewrite->instead_of[rewrite->instead_of_nr].s = instead_of;
 +      rewrite->instead_of[rewrite->instead_of_nr].len = strlen(instead_of);
 +      rewrite->instead_of_nr++;
  }
  
  static void read_remotes_file(struct remote *remote)
  
                switch (value_list) {
                case 0:
 -                      add_url(remote, xstrdup(s));
 +                      add_url_alias(remote, xstrdup(s));
                        break;
                case 1:
                        add_push_refspec(remote, xstrdup(s));
@@@ -267,7 -206,7 +267,7 @@@ static void read_branches_file(struct r
        } else {
                branch = "refs/heads/master";
        }
 -      add_url(remote, p);
 +      add_url_alias(remote, p);
        add_fetch_refspec(remote, branch);
        remote->fetch_tags = 1; /* always auto-follow */
  }
@@@ -297,19 -236,6 +297,19 @@@ static int handle_config(const char *ke
                }
                return 0;
        }
 +      if (!prefixcmp(key, "url.")) {
 +              struct rewrite *rewrite;
 +              name = key + 5;
 +              subkey = strrchr(name, '.');
 +              if (!subkey)
 +                      return 0;
 +              rewrite = make_rewrite(name, subkey - name);
 +              if (!strcmp(subkey, ".insteadof")) {
 +                      if (!value)
 +                              return config_error_nonbool(key);
 +                      add_instead_of(rewrite, xstrdup(value));
 +              }
 +      }
        if (prefixcmp(key,  "remote."))
                return 0;
        name = key + 7;
        return 0;
  }
  
 +static void alias_all_urls(void)
 +{
 +      int i, j;
 +      for (i = 0; i < remotes_nr; i++) {
 +              if (!remotes[i])
 +                      continue;
 +              for (j = 0; j < remotes[i]->url_nr; j++) {
 +                      remotes[i]->url[j] = alias_url(remotes[i]->url[j]);
 +              }
 +      }
 +}
 +
  static void read_config(void)
  {
        unsigned char sha1[20];
                        make_branch(head_ref + strlen("refs/heads/"), 0);
        }
        git_config(handle_config);
 +      alias_all_urls();
  }
  
  struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
@@@ -455,7 -368,7 +455,7 @@@ struct remote *remote_get(const char *n
                        read_branches_file(ret);
        }
        if (!ret->url)
 -              add_url(ret, name);
 +              add_url_alias(ret, name);
        if (!ret->url)
                return NULL;
        ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec);
@@@ -467,7 -380,7 +467,7 @@@ int for_each_remote(each_remote_fn fn, 
  {
        int i, result = 0;
        read_config();
 -      for (i = 0; i < allocated_remotes && !result; i++) {
 +      for (i = 0; i < remotes_nr && !result; i++) {
                struct remote *r = remotes[i];
                if (!r)
                        continue;
@@@ -730,9 -643,17 +730,17 @@@ static int match_explicit(struct ref *s
                errs = 1;
  
        if (!dst_value) {
+               unsigned char sha1[20];
+               int flag;
                if (!matched_src)
                        return errs;
-               dst_value = matched_src->name;
+               dst_value = resolve_ref(matched_src->name, sha1, 1, &flag);
+               if (!dst_value ||
+                   ((flag & REF_ISSYMREF) &&
+                    prefixcmp(dst_value, "refs/heads/")))
+                       die("%s cannot be resolved to branch.",
+                           matched_src->name);
        }
  
        switch (count_refspec_match(dst_value, dst, &matched_dst)) {
diff --combined t/t5516-fetch-push.sh
index 9023ba05af6b6fc6023fe0213b6798a3d7408750,b0d97db71c5ebeaecb019e0443ac10cb2c173361..793ffc6600202431193887a12981105c099d40df
@@@ -100,23 -100,6 +100,23 @@@ test_expect_success 'fetch with wildcar
        )
  '
  
 +test_expect_success 'fetch with insteadOf' '
 +      mk_empty &&
 +      (
 +              TRASH=$(pwd) &&
 +              cd testrepo &&
 +              git config url./$TRASH/.insteadOf trash/
 +              git config remote.up.url trash/. &&
 +              git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
 +              git fetch up &&
 +
 +              r=$(git show-ref -s --verify refs/remotes/origin/master) &&
 +              test "z$r" = "z$the_commit" &&
 +
 +              test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
 +      )
 +'
 +
  test_expect_success 'push without wildcard' '
        mk_empty &&
  
@@@ -143,20 -126,6 +143,20 @@@ test_expect_success 'push with wildcard
        )
  '
  
 +test_expect_success 'push with insteadOf' '
 +      mk_empty &&
 +      TRASH=$(pwd) &&
 +      git config url./$TRASH/.insteadOf trash/ &&
 +      git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
 +      (
 +              cd testrepo &&
 +              r=$(git show-ref -s --verify refs/remotes/origin/master) &&
 +              test "z$r" = "z$the_commit" &&
 +
 +              test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
 +      )
 +'
 +
  test_expect_success 'push with matching heads' '
  
        mk_test heads/master &&
@@@ -302,6 -271,49 +302,49 @@@ test_expect_success 'push with HEAD non
        check_push_result $the_commit heads/local
  '
  
+ test_expect_success 'push with +HEAD' '
+       mk_test heads/master &&
+       git checkout master &&
+       git branch -D local &&
+       git checkout -b local &&
+       git push testrepo master local &&
+       check_push_result $the_commit heads/master &&
+       check_push_result $the_commit heads/local &&
+       # Without force rewinding should fail
+       git reset --hard HEAD^ &&
+       ! git push testrepo HEAD &&
+       check_push_result $the_commit heads/local &&
+       # With force rewinding should succeed
+       git push testrepo +HEAD &&
+       check_push_result $the_first_commit heads/local
+ '
+ test_expect_success 'push with config remote.*.push = HEAD' '
+       mk_test heads/local &&
+       git checkout master &&
+       git branch -f local $the_commit &&
+       (
+               cd testrepo &&
+               git checkout local &&
+               git reset --hard $the_first_commit
+       ) &&
+       git config remote.there.url testrepo &&
+       git config remote.there.push HEAD &&
+       git config branch.master.remote there &&
+       git push &&
+       check_push_result $the_commit heads/master &&
+       check_push_result $the_first_commit heads/local
+ '
+ # clean up the cruft left with the previous one
+ git config --remove-section remote.there
+ git config --remove-section branch.master
  test_expect_success 'push with dry-run' '
  
        mk_test heads/master &&