Merge branch 'jk/ignore-broken-tags-when-ignoring-missing-links'
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 May 2017 03:34:54 +0000 (12:34 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 May 2017 03:34:54 +0000 (12:34 +0900)
Tag objects, which are not reachable from any ref, that point at
missing objects were mishandled by "git gc" and friends (they
should silently be ignored instead)

* jk/ignore-broken-tags-when-ignoring-missing-links:
revision.c: ignore broken tags with ignore_missing_links

1  2 
revision.c
diff --combined revision.c
index 9c67cb6026e8d39a1f72be35c030297e1ad84784,7d57d440a10e9192491056b4168c3bdc5137d1a9..b02394530926ebe24233de5e6653e7127755675a
@@@ -59,10 -59,10 +59,10 @@@ static void mark_tree_contents_unintere
        while (tree_entry(&desc, &entry)) {
                switch (object_type(entry.mode)) {
                case OBJ_TREE:
 -                      mark_tree_uninteresting(lookup_tree(entry.oid->hash));
 +                      mark_tree_uninteresting(lookup_tree(entry.oid));
                        break;
                case OBJ_BLOB:
 -                      mark_blob_uninteresting(lookup_blob(entry.oid->hash));
 +                      mark_blob_uninteresting(lookup_blob(entry.oid));
                        break;
                default:
                        /* Subproject commit - not in this repository */
@@@ -147,7 -147,7 +147,7 @@@ static void add_pending_object_with_pat
                revs->no_walk = 0;
        if (revs->reflog_info && obj->type == OBJ_COMMIT) {
                struct strbuf buf = STRBUF_INIT;
 -              int len = interpret_branch_name(name, 0, &buf);
 +              int len = interpret_branch_name(name, 0, &buf, 0);
                int st;
  
                if (0 < len && name[len] && buf.len)
@@@ -177,23 -177,23 +177,23 @@@ void add_pending_object(struct rev_inf
  
  void add_head_to_pending(struct rev_info *revs)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct object *obj;
 -      if (get_sha1("HEAD", sha1))
 +      if (get_oid("HEAD", &oid))
                return;
 -      obj = parse_object(sha1);
 +      obj = parse_object(&oid);
        if (!obj)
                return;
        add_pending_object(revs, obj, "HEAD");
  }
  
  static struct object *get_reference(struct rev_info *revs, const char *name,
 -                                  const unsigned char *sha1,
 +                                  const struct object_id *oid,
                                    unsigned int flags)
  {
        struct object *object;
  
 -      object = parse_object(sha1);
 +      object = parse_object(oid);
        if (!object) {
                if (revs->ignore_missing)
                        return object;
        return object;
  }
  
 -void add_pending_sha1(struct rev_info *revs, const char *name,
 -                    const unsigned char *sha1, unsigned int flags)
 +void add_pending_oid(struct rev_info *revs, const char *name,
 +                    const struct object_id *oid, unsigned int flags)
  {
 -      struct object *object = get_reference(revs, name, sha1, flags);
 +      struct object *object = get_reference(revs, name, oid, flags);
        add_pending_object(revs, object, name);
  }
  
@@@ -228,9 -228,9 +228,9 @@@ static struct commit *handle_commit(str
                        add_pending_object(revs, object, tag->tag);
                if (!tag->tagged)
                        die("bad tag");
 -              object = parse_object(tag->tagged->oid.hash);
 +              object = parse_object(&tag->tagged->oid);
                if (!object) {
-                       if (flags & UNINTERESTING)
+                       if (revs->ignore_missing_links || (flags & UNINTERESTING))
                                return NULL;
                        die("bad object %s", oid_to_hex(&tag->tagged->oid));
                }
@@@ -884,7 -884,7 +884,7 @@@ static void cherry_pick_list(struct com
  /* How many extra uninteresting commits we want to see.. */
  #define SLOP 5
  
 -static int still_interesting(struct commit_list *src, unsigned long date, int slop,
 +static int still_interesting(struct commit_list *src, timestamp_t date, int slop,
                             struct commit **interesting_cache)
  {
        /*
@@@ -1018,7 -1018,7 +1018,7 @@@ static void limit_left_right(struct com
  static int limit_list(struct rev_info *revs)
  {
        int slop = SLOP;
 -      unsigned long date = ~0ul;
 +      timestamp_t date = TIME_MAX;
        struct commit_list *list = revs->commits;
        struct commit_list *newlist = NULL;
        struct commit_list **p = &newlist;
@@@ -1157,9 -1157,9 +1157,9 @@@ static int handle_one_ref(const char *p
        if (ref_excluded(cb->all_revs->ref_excludes, path))
            return 0;
  
 -      object = get_reference(cb->all_revs, path, oid->hash, cb->all_flags);
 +      object = get_reference(cb->all_revs, path, oid, cb->all_flags);
        add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
 -      add_pending_sha1(cb->all_revs, path, oid->hash, cb->all_flags);
 +      add_pending_oid(cb->all_revs, path, oid, cb->all_flags);
        return 0;
  }
  
@@@ -1196,11 -1196,11 +1196,11 @@@ static void handle_refs(const char *sub
        for_each(submodule, handle_one_ref, &cb);
  }
  
 -static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)
 +static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
  {
        struct all_refs_cb *cb = cb_data;
 -      if (!is_null_sha1(sha1)) {
 -              struct object *o = parse_object(sha1);
 +      if (!is_null_oid(oid)) {
 +              struct object *o = parse_object(oid);
                if (o) {
                        o->flags |= cb->all_flags;
                        /* ??? CMDLINEFLAGS ??? */
        }
  }
  
 -static int handle_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
 -              const char *email, unsigned long timestamp, int tz,
 +static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
 -      handle_one_reflog_commit(osha1, cb_data);
 -      handle_one_reflog_commit(nsha1, cb_data);
 +      handle_one_reflog_commit(ooid, cb_data);
 +      handle_one_reflog_commit(noid, cb_data);
        return 0;
  }
  
@@@ -1249,7 -1249,7 +1249,7 @@@ static void add_cache_tree(struct cache
        int i;
  
        if (it->entry_count >= 0) {
 -              struct tree *tree = lookup_tree(it->sha1);
 +              struct tree *tree = lookup_tree(&it->oid);
                add_pending_object_with_path(revs, &tree->object, "",
                                             040000, path->buf);
        }
@@@ -1275,7 -1275,7 +1275,7 @@@ void add_index_objects_to_pending(struc
                if (S_ISGITLINK(ce->ce_mode))
                        continue;
  
 -              blob = lookup_blob(ce->sha1);
 +              blob = lookup_blob(&ce->oid);
                if (!blob)
                        die("unable to add index blob to traversal");
                add_pending_object_with_path(revs, &blob->object, "",
        }
  }
  
 -static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)
 +static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
 +                          int exclude_parent)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct object *it;
        struct commit *commit;
        struct commit_list *parents;
 +      int parent_number;
        const char *arg = arg_;
  
        if (*arg == '^') {
                flags ^= UNINTERESTING | BOTTOM;
                arg++;
        }
 -      if (get_sha1_committish(arg, sha1))
 +      if (get_sha1_committish(arg, oid.hash))
                return 0;
        while (1) {
 -              it = get_reference(revs, arg, sha1, 0);
 +              it = get_reference(revs, arg, &oid, 0);
                if (!it && revs->ignore_missing)
                        return 0;
                if (it->type != OBJ_TAG)
                        break;
                if (!((struct tag*)it)->tagged)
                        return 0;
 -              hashcpy(sha1, ((struct tag*)it)->tagged->oid.hash);
 +              oidcpy(&oid, &((struct tag*)it)->tagged->oid);
        }
        if (it->type != OBJ_COMMIT)
                return 0;
        commit = (struct commit *)it;
 -      for (parents = commit->parents; parents; parents = parents->next) {
 +      if (exclude_parent &&
 +          exclude_parent > commit_list_count(commit->parents))
 +              return 0;
 +      for (parents = commit->parents, parent_number = 1;
 +           parents;
 +           parents = parents->next, parent_number++) {
 +              if (exclude_parent && parent_number != exclude_parent)
 +                      continue;
 +
                it = &parents->item->object;
                it->flags |= flags;
                add_rev_cmdline(revs, it, arg_, REV_CMD_PARENTS_ONLY, flags);
@@@ -1389,16 -1379,16 +1389,16 @@@ static void prepare_show_merge(struct r
  {
        struct commit_list *bases;
        struct commit *head, *other;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        const char **prune = NULL;
        int i, prune_num = 1; /* counting terminating NULL */
  
 -      if (get_sha1("HEAD", sha1))
 +      if (get_oid("HEAD", &oid))
                die("--merge without HEAD?");
 -      head = lookup_commit_or_die(sha1, "HEAD");
 -      if (get_sha1("MERGE_HEAD", sha1))
 +      head = lookup_commit_or_die(&oid, "HEAD");
 +      if (get_oid("MERGE_HEAD", &oid))
                die("--merge without MERGE_HEAD?");
 -      other = lookup_commit_or_die(sha1, "MERGE_HEAD");
 +      other = lookup_commit_or_die(&oid, "MERGE_HEAD");
        add_pending_object(revs, &head->object, "HEAD");
        add_pending_object(revs, &other->object, "MERGE_HEAD");
        bases = get_merge_bases(head, other);
@@@ -1434,7 -1424,7 +1434,7 @@@ int handle_revision_arg(const char *arg
        struct object_context oc;
        char *dotdot;
        struct object *object;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        int local_flags;
        const char *arg = arg_;
        int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
  
        dotdot = strstr(arg, "..");
        if (dotdot) {
 -              unsigned char from_sha1[20];
 +              struct object_id from_oid;
                const char *next = dotdot + 2;
                const char *this = arg;
                int symmetric = *next == '.';
                                return -1;
                        }
                }
 -              if (!get_sha1_committish(this, from_sha1) &&
 -                  !get_sha1_committish(next, sha1)) {
 +              if (!get_sha1_committish(this, from_oid.hash) &&
 +                  !get_sha1_committish(next, oid.hash)) {
                        struct object *a_obj, *b_obj;
  
                        if (!cant_be_filename) {
                                verify_non_filename(revs->prefix, arg);
                        }
  
 -                      a_obj = parse_object(from_sha1);
 -                      b_obj = parse_object(sha1);
 +                      a_obj = parse_object(&from_oid);
 +                      b_obj = parse_object(&oid);
                        if (!a_obj || !b_obj) {
                        missing:
                                if (revs->ignore_missing)
  
                                a = (a_obj->type == OBJ_COMMIT
                                     ? (struct commit *)a_obj
 -                                   : lookup_commit_reference(a_obj->oid.hash));
 +                                   : lookup_commit_reference(&a_obj->oid));
                                b = (b_obj->type == OBJ_COMMIT
                                     ? (struct commit *)b_obj
 -                                   : lookup_commit_reference(b_obj->oid.hash));
 +                                   : lookup_commit_reference(&b_obj->oid));
                                if (!a || !b)
                                        goto missing;
                                exclude = get_merge_bases(a, b);
                }
                *dotdot = '.';
        }
 +
        dotdot = strstr(arg, "^@");
        if (dotdot && !dotdot[2]) {
                *dotdot = 0;
 -              if (add_parents_only(revs, arg, flags))
 +              if (add_parents_only(revs, arg, flags, 0))
                        return 0;
                *dotdot = '^';
        }
        dotdot = strstr(arg, "^!");
        if (dotdot && !dotdot[2]) {
                *dotdot = 0;
 -              if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM)))
 +              if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0))
 +                      *dotdot = '^';
 +      }
 +      dotdot = strstr(arg, "^-");
 +      if (dotdot) {
 +              int exclude_parent = 1;
 +
 +              if (dotdot[2]) {
 +                      char *end;
 +                      exclude_parent = strtoul(dotdot + 2, &end, 10);
 +                      if (*end != '\0' || !exclude_parent)
 +                              return -1;
 +              }
 +
 +              *dotdot = 0;
 +              if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent))
                        *dotdot = '^';
        }
  
        if (revarg_opt & REVARG_COMMITTISH)
                get_sha1_flags = GET_SHA1_COMMITTISH;
  
 -      if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
 +      if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
 -      object = get_reference(revs, arg, sha1, flags ^ local_flags);
 +      object = get_reference(revs, arg, &oid, flags ^ local_flags);
        add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
        add_pending_object_with_mode(revs, object, arg, oc.mode);
        return 0;
@@@ -2287,12 -2261,12 +2287,12 @@@ int setup_revisions(int argc, const cha
        if (revs->show_merge)
                prepare_show_merge(revs);
        if (revs->def && !revs->pending.nr && !got_rev_arg) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct object *object;
                struct object_context oc;
 -              if (get_sha1_with_context(revs->def, 0, sha1, &oc))
 +              if (get_sha1_with_context(revs->def, 0, oid.hash, &oc))
                        diagnose_missing_default(revs->def);
 -              object = get_reference(revs, revs->def, sha1, 0);
 +              object = get_reference(revs, revs->def, &oid, 0);
                add_pending_object_with_mode(revs, object, revs->def, oc.mode);
        }