Merge branch 'jc/nobody-sets-src-peer-ref'
authorJunio C Hamano <gitster@pobox.com>
Mon, 1 Apr 2013 16:05:35 +0000 (09:05 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 1 Apr 2013 16:05:35 +0000 (09:05 -0700)
Dead code removal.

* jc/nobody-sets-src-peer-ref:
match_push_refs(): nobody sets src->peer_ref anymore

1  2 
remote.c
diff --combined remote.c
index 57f36e14da7a8a33ae8c02a4bf46492936c79fdd,f065603c5db36318f33eaa3e244d0d6791db3d15..ca1edd901e4e64cb497b790f675537283c4ee1c0
+++ b/remote.c
@@@ -15,7 -15,6 +15,7 @@@ static struct refspec s_tag_refspec = 
        0,
        1,
        0,
 +      0,
        "refs/tags/*",
        "refs/tags/*"
  };
@@@ -539,7 -538,7 +539,7 @@@ static struct refspec *parse_refspec_in
  
                /*
                 * Before going on, special case ":" (or "+:") as a refspec
 -               * for matching refs.
 +               * for pushing matching refs.
                 */
                if (!fetch && rhs == lhs && rhs[1] == '\0') {
                        rs[i].matching = 1;
                flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
  
                if (fetch) {
 -                      /*
 -                       * LHS
 -                       * - empty is allowed; it means HEAD.
 -                       * - otherwise it must be a valid looking ref.
 -                       */
 +                      unsigned char unused[40];
 +
 +                      /* LHS */
                        if (!*rs[i].src)
 -                              ; /* empty is ok */
 -                      else if (check_refname_format(rs[i].src, flags))
 +                              ; /* empty is ok; it means "HEAD" */
 +                      else if (llen == 40 && !get_sha1_hex(rs[i].src, unused))
 +                              rs[i].exact_sha1 = 1; /* ok */
 +                      else if (!check_refname_format(rs[i].src, flags))
 +                              ; /* valid looking ref is ok */
 +                      else
                                goto invalid;
 -                      /*
 -                       * RHS
 -                       * - missing is ok, and is same as empty.
 -                       * - empty is ok; it means not to store.
 -                       * - otherwise it must be a valid looking ref.
 -                       */
 +                      /* RHS */
                        if (!rs[i].dst)
 -                              ; /* ok */
 +                              ; /* missing is ok; it is the same as empty */
                        else if (!*rs[i].dst)
 -                              ; /* ok */
 -                      else if (check_refname_format(rs[i].dst, flags))
 +                              ; /* empty is ok; it means "do not store" */
 +                      else if (!check_refname_format(rs[i].dst, flags))
 +                              ; /* valid looking ref is ok */
 +                      else
                                goto invalid;
                } else {
                        /*
@@@ -1195,101 -1195,6 +1195,101 @@@ static struct ref **tail_ref(struct re
        return tail;
  }
  
 +struct tips {
 +      struct commit **tip;
 +      int nr, alloc;
 +};
 +
 +static void add_to_tips(struct tips *tips, const unsigned char *sha1)
 +{
 +      struct commit *commit;
 +
 +      if (is_null_sha1(sha1))
 +              return;
 +      commit = lookup_commit_reference_gently(sha1, 1);
 +      if (!commit || (commit->object.flags & TMP_MARK))
 +              return;
 +      commit->object.flags |= TMP_MARK;
 +      ALLOC_GROW(tips->tip, tips->nr + 1, tips->alloc);
 +      tips->tip[tips->nr++] = commit;
 +}
 +
 +static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***dst_tail)
 +{
 +      struct string_list dst_tag = STRING_LIST_INIT_NODUP;
 +      struct string_list src_tag = STRING_LIST_INIT_NODUP;
 +      struct string_list_item *item;
 +      struct ref *ref;
 +      struct tips sent_tips;
 +
 +      /*
 +       * Collect everything we know they would have at the end of
 +       * this push, and collect all tags they have.
 +       */
 +      memset(&sent_tips, 0, sizeof(sent_tips));
 +      for (ref = *dst; ref; ref = ref->next) {
 +              if (ref->peer_ref &&
 +                  !is_null_sha1(ref->peer_ref->new_sha1))
 +                      add_to_tips(&sent_tips, ref->peer_ref->new_sha1);
 +              else
 +                      add_to_tips(&sent_tips, ref->old_sha1);
 +              if (!prefixcmp(ref->name, "refs/tags/"))
 +                      string_list_append(&dst_tag, ref->name);
 +      }
 +      clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
 +
 +      sort_string_list(&dst_tag);
 +
 +      /* Collect tags they do not have. */
 +      for (ref = src; ref; ref = ref->next) {
 +              if (prefixcmp(ref->name, "refs/tags/"))
 +                      continue; /* not a tag */
 +              if (string_list_has_string(&dst_tag, ref->name))
 +                      continue; /* they already have it */
 +              if (sha1_object_info(ref->new_sha1, NULL) != OBJ_TAG)
 +                      continue; /* be conservative */
 +              item = string_list_append(&src_tag, ref->name);
 +              item->util = ref;
 +      }
 +      string_list_clear(&dst_tag, 0);
 +
 +      /*
 +       * At this point, src_tag lists tags that are missing from
 +       * dst, and sent_tips lists the tips we are pushing or those
 +       * that we know they already have. An element in the src_tag
 +       * that is an ancestor of any of the sent_tips needs to be
 +       * sent to the other side.
 +       */
 +      if (sent_tips.nr) {
 +              for_each_string_list_item(item, &src_tag) {
 +                      struct ref *ref = item->util;
 +                      struct ref *dst_ref;
 +                      struct commit *commit;
 +
 +                      if (is_null_sha1(ref->new_sha1))
 +                              continue;
 +                      commit = lookup_commit_reference_gently(ref->new_sha1, 1);
 +                      if (!commit)
 +                              /* not pushing a commit, which is not an error */
 +                              continue;
 +
 +                      /*
 +                       * Is this tag, which they do not have, reachable from
 +                       * any of the commits we are sending?
 +                       */
 +                      if (!in_merge_bases_many(commit, sent_tips.nr, sent_tips.tip))
 +                              continue;
 +
 +                      /* Add it in */
 +                      dst_ref = make_linked_ref(ref->name, dst_tail);
 +                      hashcpy(dst_ref->new_sha1, ref->new_sha1);
 +                      dst_ref->peer_ref = copy_ref(ref);
 +              }
 +      }
 +      string_list_clear(&src_tag, 0);
 +      free(sent_tips.tip);
 +}
 +
  /*
   * Given the set of refs the local repository has, the set of refs the
   * remote repository has, and the refspec used for push, determine
@@@ -1322,9 -1227,6 +1322,6 @@@ int match_push_refs(struct ref *src, st
                const struct refspec *pat = NULL;
                char *dst_name;
  
-               if (ref->peer_ref)
-                       continue;
                dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
                if (!dst_name)
                        continue;
        free_name:
                free(dst_name);
        }
 +
 +      if (flags & MATCH_REFS_FOLLOW_TAGS)
 +              add_missing_tags(src, dst, &dst_tail);
 +
        if (send_prune) {
                /* check for missing refs on the remote */
                for (ref = *dst; ref; ref = ref->next) {
@@@ -1384,8 -1282,6 +1381,8 @@@ void set_ref_status_for_push(struct re
        struct ref *ref;
  
        for (ref = remote_refs; ref; ref = ref->next) {
 +              int force_ref_update = ref->force || force_update;
 +
                if (ref->peer_ref)
                        hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
                else if (!send_mirror)
                        continue;
                }
  
 -              /* This part determines what can overwrite what.
 -               * The rules are:
 -               *
 -               * (0) you can always use --force or +A:B notation to
 -               *     selectively force individual ref pairs.
 +              /*
 +               * Decide whether an individual refspec A:B can be
 +               * pushed.  The push will succeed if any of the
 +               * following are true:
                 *
 -               * (1) if the old thing does not exist, it is OK.
 +               * (1) the remote reference B does not exist
                 *
 -               * (2) if you do not have the old thing, you are not allowed
 -               *     to overwrite it; you would not know what you are losing
 -               *     otherwise.
 +               * (2) the remote reference B is being removed (i.e.,
 +               *     pushing :B where no source is specified)
                 *
 -               * (3) if both new and old are commit-ish, and new is a
 -               *     descendant of old, it is OK.
 +               * (3) the destination is not under refs/tags/, and
 +               *     if the old and new value is a commit, the new
 +               *     is a descendant of the old.
                 *
 -               * (4) regardless of all of the above, removing :B is
 -               *     always allowed.
 +               * (4) it is forced using the +A:B notation, or by
 +               *     passing the --force argument
                 */
  
 -              ref->nonfastforward =
 -                      !ref->deletion &&
 -                      !is_null_sha1(ref->old_sha1) &&
 -                      (!has_sha1_file(ref->old_sha1)
 -                        || !ref_newer(ref->new_sha1, ref->old_sha1));
 -
 -              if (ref->nonfastforward && !ref->force && !force_update) {
 -                      ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
 -                      continue;
 +              if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
 +                      int why = 0; /* why would this push require --force? */
 +
 +                      if (!prefixcmp(ref->name, "refs/tags/"))
 +                              why = REF_STATUS_REJECT_ALREADY_EXISTS;
 +                      else if (!has_sha1_file(ref->old_sha1))
 +                              why = REF_STATUS_REJECT_FETCH_FIRST;
 +                      else if (!lookup_commit_reference_gently(ref->old_sha1, 1) ||
 +                               !lookup_commit_reference_gently(ref->new_sha1, 1))
 +                              why = REF_STATUS_REJECT_NEEDS_FORCE;
 +                      else if (!ref_newer(ref->new_sha1, ref->old_sha1))
 +                              why = REF_STATUS_REJECT_NONFASTFORWARD;
 +
 +                      if (!force_ref_update)
 +                              ref->status = why;
 +                      else if (why)
 +                              ref->forced_update = 1;
                }
        }
  }
@@@ -1565,12 -1454,7 +1562,12 @@@ int get_fetch_map(const struct ref *rem
        } else {
                const char *name = refspec->src[0] ? refspec->src : "HEAD";
  
 -              ref_map = get_remote_ref(remote_refs, name);
 +              if (refspec->exact_sha1) {
 +                      ref_map = alloc_ref(name);
 +                      get_sha1_hex(name, ref_map->old_sha1);
 +              } else {
 +                      ref_map = get_remote_ref(remote_refs, name);
 +              }
                if (!missing_ok && !ref_map)
                        die("Couldn't find remote ref %s", name);
                if (ref_map) {
@@@ -1631,8 -1515,7 +1628,8 @@@ int ref_newer(const unsigned char *new_
        struct commit_list *list, *used;
        int found = 0;
  
 -      /* Both new and old must be commit-ish and new is descendant of
 +      /*
 +       * Both new and old must be commit-ish and new is descendant of
         * old.  Otherwise we require --force.
         */
        o = deref_tag(parse_object(old_sha1), NULL, 0);