Merge branch 'jk/for-each-ref-icase'
authorJunio C Hamano <gitster@pobox.com>
Tue, 24 Jul 2018 21:50:44 +0000 (14:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 24 Jul 2018 21:50:44 +0000 (14:50 -0700)
The "--ignore-case" option of "git for-each-ref" (and its friends)
did not work correctly, which has been fixed.

* jk/for-each-ref-icase:
ref-filter: avoid backend filtering with --ignore-case
for-each-ref: consistently pass WM_IGNORECASE flag
t6300: add a test for --ignore-case

1  2 
ref-filter.c
t/t6300-for-each-ref.sh
diff --combined ref-filter.c
index 0ab893a250f565ef8be1c449542d4e70e7bc10d5,85057234eed4a444f285932ab7d8aaa62a3ca943..492f2b770d909185dbeb65a0d42e62186981ab8a
@@@ -3,7 -3,6 +3,7 @@@
  #include "parse-options.h"
  #include "refs.h"
  #include "wildmatch.h"
 +#include "object-store.h"
  #include "commit.h"
  #include "remote.h"
  #include "color.h"
@@@ -17,7 -16,6 +17,7 @@@
  #include "trailer.h"
  #include "wt-status.h"
  #include "commit-slab.h"
 +#include "commit-graph.h"
  
  static struct ref_msg {
        const char *gone;
@@@ -103,38 -101,22 +103,38 @@@ static struct used_atom 
  } *used_atom;
  static int used_atom_cnt, need_tagged, need_symref;
  
 -static void color_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *color_value)
 +/*
 + * Expand string, append it to strbuf *sb, then return error code ret.
 + * Allow to save few lines of code.
 + */
 +static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
 +{
 +      va_list ap;
 +      va_start(ap, fmt);
 +      strbuf_vaddf(sb, fmt, ap);
 +      va_end(ap);
 +      return ret;
 +}
 +
 +static int color_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                           const char *color_value, struct strbuf *err)
  {
        if (!color_value)
 -              die(_("expected format: %%(color:<color>)"));
 +              return strbuf_addf_ret(err, -1, _("expected format: %%(color:<color>)"));
        if (color_parse(color_value, atom->u.color) < 0)
 -              die(_("unrecognized color: %%(color:%s)"), color_value);
 +              return strbuf_addf_ret(err, -1, _("unrecognized color: %%(color:%s)"),
 +                                     color_value);
        /*
         * We check this after we've parsed the color, which lets us complain
         * about syntactically bogus color names even if they won't be used.
         */
        if (!want_color(format->use_color))
                color_parse("", atom->u.color);
 +      return 0;
  }
  
 -static void refname_atom_parser_internal(struct refname_atom *atom,
 -                                       const char *arg, const char *name)
 +static int refname_atom_parser_internal(struct refname_atom *atom, const char *arg,
 +                                       const char *name, struct strbuf *err)
  {
        if (!arg)
                atom->option = R_NORMAL;
                 skip_prefix(arg, "strip=", &arg)) {
                atom->option = R_LSTRIP;
                if (strtol_i(arg, 10, &atom->lstrip))
 -                      die(_("Integer value expected refname:lstrip=%s"), arg);
 +                      return strbuf_addf_ret(err, -1, _("Integer value expected refname:lstrip=%s"), arg);
        } else if (skip_prefix(arg, "rstrip=", &arg)) {
                atom->option = R_RSTRIP;
                if (strtol_i(arg, 10, &atom->rstrip))
 -                      die(_("Integer value expected refname:rstrip=%s"), arg);
 +                      return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
        } else
 -              die(_("unrecognized %%(%s) argument: %s"), name, arg);
 +              return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), name, arg);
 +      return 0;
  }
  
 -static void remote_ref_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int remote_ref_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                                const char *arg, struct strbuf *err)
  {
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
  
        if (!arg) {
                atom->u.remote_ref.option = RR_REF;
 -              refname_atom_parser_internal(&atom->u.remote_ref.refname,
 -                                           arg, atom->name);
 -              return;
 +              return refname_atom_parser_internal(&atom->u.remote_ref.refname,
 +                                                  arg, atom->name, err);
        }
  
        atom->u.remote_ref.nobracket = 0;
                        atom->u.remote_ref.push_remote = 1;
                } else {
                        atom->u.remote_ref.option = RR_REF;
 -                      refname_atom_parser_internal(&atom->u.remote_ref.refname,
 -                                                   arg, atom->name);
 +                      if (refname_atom_parser_internal(&atom->u.remote_ref.refname,
 +                                                       arg, atom->name, err)) {
 +                              string_list_clear(&params, 0);
 +                              return -1;
 +                      }
                }
        }
  
        string_list_clear(&params, 0);
 +      return 0;
  }
  
 -static void body_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int body_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                          const char *arg, struct strbuf *err)
  {
        if (arg)
 -              die(_("%%(body) does not take arguments"));
 +              return strbuf_addf_ret(err, -1, _("%%(body) does not take arguments"));
        atom->u.contents.option = C_BODY_DEP;
 +      return 0;
  }
  
 -static void subject_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int subject_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                             const char *arg, struct strbuf *err)
  {
        if (arg)
 -              die(_("%%(subject) does not take arguments"));
 +              return strbuf_addf_ret(err, -1, _("%%(subject) does not take arguments"));
        atom->u.contents.option = C_SUB;
 +      return 0;
  }
  
 -static void trailers_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int trailers_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                              const char *arg, struct strbuf *err)
  {
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
                                atom->u.contents.trailer_opts.unfold = 1;
                        else if (!strcmp(s, "only"))
                                atom->u.contents.trailer_opts.only_trailers = 1;
 -                      else
 -                              die(_("unknown %%(trailers) argument: %s"), s);
 +                      else {
 +                              strbuf_addf(err, _("unknown %%(trailers) argument: %s"), s);
 +                              string_list_clear(&params, 0);
 +                              return -1;
 +                      }
                }
        }
        atom->u.contents.option = C_TRAILERS;
        string_list_clear(&params, 0);
 +      return 0;
  }
  
 -static void contents_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int contents_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                              const char *arg, struct strbuf *err)
  {
        if (!arg)
                atom->u.contents.option = C_BARE;
                atom->u.contents.option = C_SUB;
        else if (skip_prefix(arg, "trailers", &arg)) {
                skip_prefix(arg, ":", &arg);
 -              trailers_atom_parser(format, atom, *arg ? arg : NULL);
 +              if (trailers_atom_parser(format, atom, *arg ? arg : NULL, err))
 +                      return -1;
        } else if (skip_prefix(arg, "lines=", &arg)) {
                atom->u.contents.option = C_LINES;
                if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
 -                      die(_("positive value expected contents:lines=%s"), arg);
 +                      return strbuf_addf_ret(err, -1, _("positive value expected contents:lines=%s"), arg);
        } else
 -              die(_("unrecognized %%(contents) argument: %s"), arg);
 +              return strbuf_addf_ret(err, -1, _("unrecognized %%(contents) argument: %s"), arg);
 +      return 0;
  }
  
 -static void objectname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int objectname_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                                const char *arg, struct strbuf *err)
  {
        if (!arg)
                atom->u.objectname.option = O_FULL;
                atom->u.objectname.option = O_LENGTH;
                if (strtoul_ui(arg, 10, &atom->u.objectname.length) ||
                    atom->u.objectname.length == 0)
 -                      die(_("positive value expected objectname:short=%s"), arg);
 +                      return strbuf_addf_ret(err, -1, _("positive value expected objectname:short=%s"), arg);
                if (atom->u.objectname.length < MINIMUM_ABBREV)
                        atom->u.objectname.length = MINIMUM_ABBREV;
        } else
 -              die(_("unrecognized %%(objectname) argument: %s"), arg);
 +              return strbuf_addf_ret(err, -1, _("unrecognized %%(objectname) argument: %s"), arg);
 +      return 0;
  }
  
 -static void refname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int refname_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                             const char *arg, struct strbuf *err)
  {
 -      refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
 +      return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err);
  }
  
  static align_type parse_align_position(const char *s)
        return -1;
  }
  
 -static void align_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int align_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                           const char *arg, struct strbuf *err)
  {
        struct align *align = &atom->u.align;
        struct string_list params = STRING_LIST_INIT_DUP;
        unsigned int width = ~0U;
  
        if (!arg)
 -              die(_("expected format: %%(align:<width>,<position>)"));
 +              return strbuf_addf_ret(err, -1, _("expected format: %%(align:<width>,<position>)"));
  
        align->position = ALIGN_LEFT;
  
  
                if (skip_prefix(s, "position=", &s)) {
                        position = parse_align_position(s);
 -                      if (position < 0)
 -                              die(_("unrecognized position:%s"), s);
 +                      if (position < 0) {
 +                              strbuf_addf(err, _("unrecognized position:%s"), s);
 +                              string_list_clear(&params, 0);
 +                              return -1;
 +                      }
                        align->position = position;
                } else if (skip_prefix(s, "width=", &s)) {
 -                      if (strtoul_ui(s, 10, &width))
 -                              die(_("unrecognized width:%s"), s);
 +                      if (strtoul_ui(s, 10, &width)) {
 +                              strbuf_addf(err, _("unrecognized width:%s"), s);
 +                              string_list_clear(&params, 0);
 +                              return -1;
 +                      }
                } else if (!strtoul_ui(s, 10, &width))
                        ;
                else if ((position = parse_align_position(s)) >= 0)
                        align->position = position;
 -              else
 -                      die(_("unrecognized %%(align) argument: %s"), s);
 +              else {
 +                      strbuf_addf(err, _("unrecognized %%(align) argument: %s"), s);
 +                      string_list_clear(&params, 0);
 +                      return -1;
 +              }
        }
  
 -      if (width == ~0U)
 -              die(_("positive width expected with the %%(align) atom"));
 +      if (width == ~0U) {
 +              string_list_clear(&params, 0);
 +              return strbuf_addf_ret(err, -1, _("positive width expected with the %%(align) atom"));
 +      }
        align->width = width;
        string_list_clear(&params, 0);
 +      return 0;
  }
  
 -static void if_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int if_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                        const char *arg, struct strbuf *err)
  {
        if (!arg) {
                atom->u.if_then_else.cmp_status = COMPARE_NONE;
 -              return;
 +              return 0;
        } else if (skip_prefix(arg, "equals=", &atom->u.if_then_else.str)) {
                atom->u.if_then_else.cmp_status = COMPARE_EQUAL;
        } else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
                atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
 -      } else {
 -              die(_("unrecognized %%(if) argument: %s"), arg);
 -      }
 +      } else
 +              return strbuf_addf_ret(err, -1, _("unrecognized %%(if) argument: %s"), arg);
 +      return 0;
  }
  
 -static void head_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 +static int head_atom_parser(const struct ref_format *format, struct used_atom *atom,
 +                          const char *arg, struct strbuf *unused_err)
  {
        atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 +      return 0;
  }
  
  static struct {
        const char *name;
        cmp_type cmp_type;
 -      void (*parser)(const struct ref_format *format, struct used_atom *atom, const char *arg);
 +      int (*parser)(const struct ref_format *format, struct used_atom *atom,
 +                    const char *arg, struct strbuf *err);
  } valid_atom[] = {
        { "refname" , FIELD_STR, refname_atom_parser },
        { "objecttype" },
@@@ -442,8 -387,7 +442,8 @@@ struct ref_formatting_state 
  
  struct atom_value {
        const char *s;
 -      void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
 +      int (*handler)(struct atom_value *atomv, struct ref_formatting_state *state,
 +                     struct strbuf *err);
        uintmax_t value; /* used for sorting when not FIELD_STR */
        struct used_atom *atom;
  };
   * Used to parse format string and sort specifiers
   */
  static int parse_ref_filter_atom(const struct ref_format *format,
 -                               const char *atom, const char *ep)
 +                               const char *atom, const char *ep,
 +                               struct strbuf *err)
  {
        const char *sp;
        const char *arg;
        if (*sp == '*' && sp < ep)
                sp++; /* deref */
        if (ep <= sp)
 -              die(_("malformed field name: %.*s"), (int)(ep-atom), atom);
 +              return strbuf_addf_ret(err, -1, _("malformed field name: %.*s"),
 +                                     (int)(ep-atom), atom);
  
        /* Do we have the atom already used elsewhere? */
        for (i = 0; i < used_atom_cnt; i++) {
        }
  
        if (ARRAY_SIZE(valid_atom) <= i)
 -              die(_("unknown field name: %.*s"), (int)(ep-atom), atom);
 +              return strbuf_addf_ret(err, -1, _("unknown field name: %.*s"),
 +                                     (int)(ep-atom), atom);
  
        /* Add it in, including the deref prefix */
        at = used_atom_cnt;
                }
        }
        memset(&used_atom[at].u, 0, sizeof(used_atom[at].u));
 -      if (valid_atom[i].parser)
 -              valid_atom[i].parser(format, &used_atom[at], arg);
 +      if (valid_atom[i].parser && valid_atom[i].parser(format, &used_atom[at], arg, err))
 +              return -1;
        if (*atom == '*')
                need_tagged = 1;
        if (!strcmp(valid_atom[i].name, "symref"))
@@@ -540,8 -481,7 +540,8 @@@ static void quote_formatting(struct str
        }
  }
  
 -static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
 +static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
 +                     struct strbuf *unused_err)
  {
        /*
         * Quote formatting is only done when the stack has a single
                quote_formatting(&state->stack->output, v->s, state->quote_style);
        else
                strbuf_addstr(&state->stack->output, v->s);
 +      return 0;
  }
  
  static void push_stack_element(struct ref_formatting_stack **stack)
@@@ -588,8 -527,7 +588,8 @@@ static void end_align_handler(struct re
        strbuf_release(&s);
  }
  
 -static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
 +static int align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
 +                            struct strbuf *unused_err)
  {
        struct ref_formatting_stack *new_stack;
  
        new_stack = state->stack;
        new_stack->at_end = end_align_handler;
        new_stack->at_end_data = &atomv->atom->u.align;
 +      return 0;
  }
  
  static void if_then_else_handler(struct ref_formatting_stack **stack)
        free(if_then_else);
  }
  
 -static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
 +static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
 +                         struct strbuf *unused_err)
  {
        struct ref_formatting_stack *new_stack;
        struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
        new_stack = state->stack;
        new_stack->at_end = if_then_else_handler;
        new_stack->at_end_data = if_then_else;
 +      return 0;
  }
  
  static int is_empty(const char *s)
        return 1;
  }
  
 -static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
 +static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
 +                           struct strbuf *err)
  {
        struct ref_formatting_stack *cur = state->stack;
        struct if_then_else *if_then_else = NULL;
        if (cur->at_end == if_then_else_handler)
                if_then_else = (struct if_then_else *)cur->at_end_data;
        if (!if_then_else)
 -              die(_("format: %%(then) atom used without an %%(if) atom"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(then) atom used without an %%(if) atom"));
        if (if_then_else->then_atom_seen)
 -              die(_("format: %%(then) atom used more than once"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(then) atom used more than once"));
        if (if_then_else->else_atom_seen)
 -              die(_("format: %%(then) atom used after %%(else)"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(then) atom used after %%(else)"));
        if_then_else->then_atom_seen = 1;
        /*
         * If the 'equals' or 'notequals' attribute is used then
        } else if (cur->output.len && !is_empty(cur->output.buf))
                if_then_else->condition_satisfied = 1;
        strbuf_reset(&cur->output);
 +      return 0;
  }
  
 -static void else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
 +static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
 +                           struct strbuf *err)
  {
        struct ref_formatting_stack *prev = state->stack;
        struct if_then_else *if_then_else = NULL;
        if (prev->at_end == if_then_else_handler)
                if_then_else = (struct if_then_else *)prev->at_end_data;
        if (!if_then_else)
 -              die(_("format: %%(else) atom used without an %%(if) atom"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(else) atom used without an %%(if) atom"));
        if (!if_then_else->then_atom_seen)
 -              die(_("format: %%(else) atom used without a %%(then) atom"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(else) atom used without a %%(then) atom"));
        if (if_then_else->else_atom_seen)
 -              die(_("format: %%(else) atom used more than once"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(else) atom used more than once"));
        if_then_else->else_atom_seen = 1;
        push_stack_element(&state->stack);
        state->stack->at_end_data = prev->at_end_data;
        state->stack->at_end = prev->at_end;
 +      return 0;
  }
  
 -static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
 +static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
 +                          struct strbuf *err)
  {
        struct ref_formatting_stack *current = state->stack;
        struct strbuf s = STRBUF_INIT;
  
        if (!current->at_end)
 -              die(_("format: %%(end) atom used without corresponding atom"));
 +              return strbuf_addf_ret(err, -1, _("format: %%(end) atom used without corresponding atom"));
        current->at_end(&state->stack);
  
        /*  Stack may have been popped within at_end(), hence reset the current pointer */
        }
        strbuf_release(&s);
        pop_stack_element(&state->stack);
 +      return 0;
  }
  
  /*
@@@ -773,21 -702,17 +773,21 @@@ int verify_ref_format(struct ref_forma
  
        format->need_color_reset_at_eol = 0;
        for (cp = format->format; *cp && (sp = find_next(cp)); ) {
 +              struct strbuf err = STRBUF_INIT;
                const char *color, *ep = strchr(sp, ')');
                int at;
  
                if (!ep)
                        return error(_("malformed format string %s"), sp);
                /* sp points at "%(" and ep points at the closing ")" */
 -              at = parse_ref_filter_atom(format, sp + 2, ep);
 +              at = parse_ref_filter_atom(format, sp + 2, ep, &err);
 +              if (at < 0)
 +                      die("%s", err.buf);
                cp = ep + 1;
  
                if (skip_prefix(used_atom[at].name, "color:", &color))
                        format->need_color_reset_at_eol = !!strcmp(color, "reset");
 +              strbuf_release(&err);
        }
        if (format->need_color_reset_at_eol && !want_color(format->use_color))
                format->need_color_reset_at_eol = 0;
  static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten)
  {
        enum object_type type;
 -      void *buf = read_sha1_file(oid->hash, &type, sz);
 +      void *buf = read_object_file(oid, &type, sz);
  
        if (buf)
                *obj = parse_object_buffer(oid, type, *sz, buf, eaten);
        return buf;
  }
  
 -static int grab_objectname(const char *name, const unsigned char *sha1,
 +static int grab_objectname(const char *name, const struct object_id *oid,
                           struct atom_value *v, struct used_atom *atom)
  {
        if (starts_with(name, "objectname")) {
                if (atom->u.objectname.option == O_SHORT) {
 -                      v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
 +                      v->s = xstrdup(find_unique_abbrev(oid, DEFAULT_ABBREV));
                        return 1;
                } else if (atom->u.objectname.option == O_FULL) {
 -                      v->s = xstrdup(sha1_to_hex(sha1));
 +                      v->s = xstrdup(oid_to_hex(oid));
                        return 1;
                } else if (atom->u.objectname.option == O_LENGTH) {
 -                      v->s = xstrdup(find_unique_abbrev(sha1, atom->u.objectname.length));
 +                      v->s = xstrdup(find_unique_abbrev(oid, atom->u.objectname.length));
                        return 1;
                } else
 -                      die("BUG: unknown %%(objectname) option");
 +                      BUG("unknown %%(objectname) option");
        }
        return 0;
  }
@@@ -850,7 -775,7 +850,7 @@@ static void grab_common_values(struct a
                        v->s = xstrfmt("%lu", sz);
                }
                else if (deref)
 -                      grab_objectname(name, obj->oid.hash, v, &used_atom[i]);
 +                      grab_objectname(name, &obj->oid, v, &used_atom[i]);
        }
  }
  
@@@ -890,7 -815,7 +890,7 @@@ static void grab_commit_values(struct a
                if (deref)
                        name++;
                if (!strcmp(name, "tree")) {
 -                      v->s = xstrdup(oid_to_hex(&commit->tree->object.oid));
 +                      v->s = xstrdup(oid_to_hex(get_commit_tree_oid(commit)));
                }
                else if (!strcmp(name, "numparent")) {
                        v->value = commit_list_count(commit->parents);
@@@ -1374,7 -1299,7 +1374,7 @@@ static void fill_remote_ref_details(str
                else
                        *s = "";
        } else
 -              die("BUG: unhandled RR_* enum");
 +              BUG("unhandled RR_* enum");
  }
  
  char *get_head_description(void)
        memset(&state, 0, sizeof(state));
        wt_status_get_state(&state, 1);
        if (state.rebase_in_progress ||
 -          state.rebase_interactive_in_progress)
 -              strbuf_addf(&desc, _("(no branch, rebasing %s)"),
 -                          state.branch);
 -      else if (state.bisect_in_progress)
 +          state.rebase_interactive_in_progress) {
 +              if (state.branch)
 +                      strbuf_addf(&desc, _("(no branch, rebasing %s)"),
 +                                  state.branch);
 +              else
 +                      strbuf_addf(&desc, _("(no branch, rebasing detached HEAD %s)"),
 +                                  state.detached_from);
 +      } else if (state.bisect_in_progress)
                strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
                            state.branch);
        else if (state.detached_from) {
@@@ -1433,30 -1354,28 +1433,30 @@@ static const char *get_refname(struct u
        return show_ref(&atom->u.refname, ref->refname);
  }
  
 -static void get_object(struct ref_array_item *ref, const struct object_id *oid,
 -                     int deref, struct object **obj)
 +static int get_object(struct ref_array_item *ref, const struct object_id *oid,
 +                     int deref, struct object **obj, struct strbuf *err)
  {
        int eaten;
 +      int ret = 0;
        unsigned long size;
        void *buf = get_obj(oid, obj, &size, &eaten);
        if (!buf)
 -              die(_("missing object %s for %s"),
 -                  oid_to_hex(oid), ref->refname);
 -      if (!*obj)
 -              die(_("parse_object_buffer failed on %s for %s"),
 -                  oid_to_hex(oid), ref->refname);
 -
 -      grab_values(ref->value, deref, *obj, buf, size);
 +              ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"),
 +                                    oid_to_hex(oid), ref->refname);
 +      else if (!*obj)
 +              ret = strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
 +                                    oid_to_hex(oid), ref->refname);
 +      else
 +              grab_values(ref->value, deref, *obj, buf, size);
        if (!eaten)
                free(buf);
 +      return ret;
  }
  
  /*
   * Parse the object referred by ref, and grab needed value.
   */
 -static void populate_value(struct ref_array_item *ref)
 +static int populate_value(struct ref_array_item *ref, struct strbuf *err)
  {
        struct object *obj;
        int i;
                                v->s = xstrdup(buf + 1);
                        }
                        continue;
 -              } else if (!deref && grab_objectname(name, ref->objectname.hash, v, atom)) {
 +              } else if (!deref && grab_objectname(name, &ref->objectname, v, atom)) {
                        continue;
                } else if (!strcmp(name, "HEAD")) {
                        if (atom->u.head && !strcmp(ref->refname, atom->u.head))
                        break;
        }
        if (used_atom_cnt <= i)
 -              return;
 +              return 0;
  
 -      get_object(ref, &ref->objectname, 0, &obj);
 +      if (get_object(ref, &ref->objectname, 0, &obj, err))
 +              return -1;
  
        /*
         * If there is no atom that wants to know about tagged
         * object, we are done.
         */
        if (!need_tagged || (obj->type != OBJ_TAG))
 -              return;
 +              return 0;
  
        /*
         * If it is a tag object, see if we use a value that derefs
         * is not consistent with what deref_tag() does
         * which peels the onion to the core.
         */
 -      get_object(ref, tagged, 1, &obj);
 +      return get_object(ref, tagged, 1, &obj, err);
  }
  
  /*
   * Given a ref, return the value for the atom.  This lazily gets value
   * out of the object by calling populate value.
   */
 -static void get_ref_atom_value(struct ref_array_item *ref, int atom, struct atom_value **v)
 +static int get_ref_atom_value(struct ref_array_item *ref, int atom,
 +                            struct atom_value **v, struct strbuf *err)
  {
        if (!ref->value) {
 -              populate_value(ref);
 +              if (populate_value(ref, err))
 +                      return -1;
                fill_missing_values(ref->value);
        }
        *v = &ref->value[atom];
 +      return 0;
  }
  
  /*
@@@ -1664,13 -1579,12 +1664,13 @@@ static int in_commit_list(const struct 
  }
  
  /*
 - * Test whether the candidate or one of its parents is contained in the list.
 + * Test whether the candidate is contained in the list.
   * Do not recurse to find out, though, but return -1 if inconclusive.
   */
  static enum contains_result contains_test(struct commit *candidate,
                                          const struct commit_list *want,
 -                                        struct contains_cache *cache)
 +                                        struct contains_cache *cache,
 +                                        uint32_t cutoff)
  {
        enum contains_result *cached = contains_cache_at(cache, candidate);
  
  
        /* Otherwise, we don't know; prepare to recurse */
        parse_commit_or_die(candidate);
 +
 +      if (candidate->generation < cutoff)
 +              return CONTAINS_NO;
 +
        return CONTAINS_UNKNOWN;
  }
  
@@@ -1705,18 -1615,8 +1705,18 @@@ static enum contains_result contains_ta
                                              struct contains_cache *cache)
  {
        struct contains_stack contains_stack = { 0, 0, NULL };
 -      enum contains_result result = contains_test(candidate, want, cache);
 +      enum contains_result result;
 +      uint32_t cutoff = GENERATION_NUMBER_INFINITY;
 +      const struct commit_list *p;
 +
 +      for (p = want; p; p = p->next) {
 +              struct commit *c = p->item;
 +              load_commit_graph_info(c);
 +              if (c->generation < cutoff)
 +                      cutoff = c->generation;
 +      }
  
 +      result = contains_test(candidate, want, cache, cutoff);
        if (result != CONTAINS_UNKNOWN)
                return result;
  
                 * If we just popped the stack, parents->item has been marked,
                 * therefore contains_test will return a meaningful yes/no.
                 */
 -              else switch (contains_test(parents->item, want, cache)) {
 +              else switch (contains_test(parents->item, want, cache, cutoff)) {
                case CONTAINS_YES:
                        *contains_cache_at(cache, commit) = CONTAINS_YES;
                        contains_stack.nr--;
                }
        }
        free(contains_stack.contains_stack);
 -      return contains_test(candidate, want, cache);
 +      return contains_test(candidate, want, cache, cutoff);
  }
  
  static int commit_contains(struct ref_filter *filter, struct commit *commit,
@@@ -1814,7 -1714,7 +1814,7 @@@ static int match_name_as_path(const str
                     refname[plen] == '/' ||
                     p[plen-1] == '/'))
                        return 1;
-               if (!wildmatch(p, refname, WM_PATHNAME))
+               if (!wildmatch(p, refname, flags))
                        return 1;
        }
        return 0;
@@@ -1869,6 -1769,15 +1869,15 @@@ static int for_each_fullref_in_pattern(
                return for_each_fullref_in("", cb, cb_data, broken);
        }
  
+       if (filter->ignore_case) {
+               /*
+                * we can't handle case-insensitive comparisons,
+                * so just return everything and let the caller
+                * sort it out.
+                */
+               return for_each_fullref_in("", cb, cb_data, broken);
+       }
        if (!filter->name_patterns[0]) {
                /* no patterns; we have to look at everything */
                return for_each_fullref_in("", cb, cb_data, broken);
@@@ -1924,30 -1833,15 +1933,30 @@@ static const struct object_id *match_po
        return NULL;
  }
  
 -/* Allocate space for a new ref_array_item and copy the objectname and flag to it */
 +/*
 + * Allocate space for a new ref_array_item and copy the name and oid to it.
 + *
 + * Callers can then fill in other struct members at their leisure.
 + */
  static struct ref_array_item *new_ref_array_item(const char *refname,
 -                                               const unsigned char *objectname,
 -                                               int flag)
 +                                               const struct object_id *oid)
  {
        struct ref_array_item *ref;
 +
        FLEX_ALLOC_STR(ref, refname, refname);
 -      hashcpy(ref->objectname.hash, objectname);
 -      ref->flag = flag;
 +      oidcpy(&ref->objectname, oid);
 +
 +      return ref;
 +}
 +
 +struct ref_array_item *ref_array_push(struct ref_array *array,
 +                                    const char *refname,
 +                                    const struct object_id *oid)
 +{
 +      struct ref_array_item *ref = new_ref_array_item(refname, oid);
 +
 +      ALLOC_GROW(array->items, array->nr + 1, array->alloc);
 +      array->items[array->nr++] = ref;
  
        return ref;
  }
@@@ -2042,11 -1936,12 +2051,11 @@@ static int ref_filter_handler(const cha
         * to do its job and the resulting list may yet to be pruned
         * by maxcount logic.
         */
 -      ref = new_ref_array_item(refname, oid->hash, flag);
 +      ref = ref_array_push(ref_cbdata->array, refname, oid);
        ref->commit = commit;
 -
 -      REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);
 -      ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;
 +      ref->flag = flag;
        ref->kind = kind;
 +
        return 0;
  }
  
@@@ -2171,13 -2066,9 +2180,13 @@@ static int cmp_ref_sorting(struct ref_s
        int cmp;
        cmp_type cmp_type = used_atom[s->atom].type;
        int (*cmp_fn)(const char *, const char *);
 +      struct strbuf err = STRBUF_INIT;
  
 -      get_ref_atom_value(a, s->atom, &va);
 -      get_ref_atom_value(b, s->atom, &vb);
 +      if (get_ref_atom_value(a, s->atom, &va, &err))
 +              die("%s", err.buf);
 +      if (get_ref_atom_value(b, s->atom, &vb, &err))
 +              die("%s", err.buf);
 +      strbuf_release(&err);
        cmp_fn = s->ignore_case ? strcasecmp : strcmp;
        if (s->version)
                cmp = versioncmp(va->s, vb->s);
@@@ -2236,10 -2127,9 +2245,10 @@@ static void append_literal(const char *
        }
  }
  
 -void format_ref_array_item(struct ref_array_item *info,
 +int format_ref_array_item(struct ref_array_item *info,
                           const struct ref_format *format,
 -                         struct strbuf *final_buf)
 +                         struct strbuf *final_buf,
 +                         struct strbuf *error_buf)
  {
        const char *cp, *sp, *ep;
        struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
  
        for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
                struct atom_value *atomv;
 +              int pos;
  
                ep = strchr(sp, ')');
                if (cp < sp)
                        append_literal(cp, sp, &state);
 -              get_ref_atom_value(info,
 -                                 parse_ref_filter_atom(format, sp + 2, ep),
 -                                 &atomv);
 -              atomv->handler(atomv, &state);
 +              pos = parse_ref_filter_atom(format, sp + 2, ep, error_buf);
 +              if (pos < 0 || get_ref_atom_value(info, pos, &atomv, error_buf) ||
 +                  atomv->handler(atomv, &state, error_buf)) {
 +                      pop_stack_element(&state.stack);
 +                      return -1;
 +              }
        }
        if (*cp) {
                sp = cp + strlen(cp);
        if (format->need_color_reset_at_eol) {
                struct atom_value resetv;
                resetv.s = GIT_COLOR_RESET;
 -              append_atom(&resetv, &state);
 +              if (append_atom(&resetv, &state, error_buf)) {
 +                      pop_stack_element(&state.stack);
 +                      return -1;
 +              }
 +      }
 +      if (state.stack->prev) {
 +              pop_stack_element(&state.stack);
 +              return strbuf_addf_ret(error_buf, -1, _("format: %%(end) atom missing"));
        }
 -      if (state.stack->prev)
 -              die(_("format: %%(end) atom missing"));
        strbuf_addbuf(final_buf, &state.stack->output);
        pop_stack_element(&state.stack);
 +      return 0;
  }
  
  void show_ref_array_item(struct ref_array_item *info,
                         const struct ref_format *format)
  {
        struct strbuf final_buf = STRBUF_INIT;
 +      struct strbuf error_buf = STRBUF_INIT;
  
 -      format_ref_array_item(info, format, &final_buf);
 +      if (format_ref_array_item(info, format, &final_buf, &error_buf))
 +              die("%s", error_buf.buf);
        fwrite(final_buf.buf, 1, final_buf.len, stdout);
 +      strbuf_release(&error_buf);
        strbuf_release(&final_buf);
        putchar('\n');
  }
  
 -void pretty_print_ref(const char *name, const unsigned char *sha1,
 +void pretty_print_ref(const char *name, const struct object_id *oid,
                      const struct ref_format *format)
  {
        struct ref_array_item *ref_item;
 -      ref_item = new_ref_array_item(name, sha1, 0);
 +      ref_item = new_ref_array_item(name, oid);
        ref_item->kind = ref_kind_from_refname(name);
        show_ref_array_item(ref_item, format);
        free_array_item(ref_item);
@@@ -2314,12 -2192,7 +2323,12 @@@ static int parse_sorting_atom(const cha
         */
        struct ref_format dummy = REF_FORMAT_INIT;
        const char *end = atom + strlen(atom);
 -      return parse_ref_filter_atom(&dummy, atom, end);
 +      struct strbuf err = STRBUF_INIT;
 +      int res = parse_ref_filter_atom(&dummy, atom, end, &err);
 +      if (res < 0)
 +              die("%s", err.buf);
 +      strbuf_release(&err);
 +      return res;
  }
  
  /*  If no sorting option is given, use refname to sort as default */
diff --combined t/t6300-for-each-ref.sh
index 48379aa0ee874b0250e2348d47eded09713a0a79,3bb901d50f5bdaadd74a4c869991c6315c66a8bc..e0496da812f34df16ef7c3417788f9096ddc1e0f
@@@ -310,7 -310,7 +310,7 @@@ test_expect_success 'exercise strftime 
        echo >expected &&
        git for-each-ref --format="%(authordate:format:)" refs/heads >actual &&
        test_cmp expected actual &&
 -      long="long format -- $_z40$_z40$_z40$_z40$_z40$_z40$_z40" &&
 +      long="long format -- $ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID$ZERO_OID" &&
        echo $long >expected &&
        git for-each-ref --format="%(authordate:format:$long)" refs/heads >actual &&
        test_cmp expected actual
@@@ -795,4 -795,15 +795,15 @@@ test_expect_success ':remotename and :r
        )
  '
  
+ test_expect_success 'for-each-ref --ignore-case ignores case' '
+       >expect &&
+       git for-each-ref --format="%(refname)" refs/heads/MASTER >actual &&
+       test_cmp expect actual &&
+       echo refs/heads/master >expect &&
+       git for-each-ref --format="%(refname)" --ignore-case \
+               refs/heads/MASTER >actual &&
+       test_cmp expect actual
+ '
  test_done