]> git.ipfire.org Git - thirdparty/git.git/blobdiff - ref-filter.c
Git 2.24.3
[thirdparty/git.git] / ref-filter.c
index 01c1a82075eca737c2e3749e295ca24bbab870b6..6867e33648cb58d6836594a5cf145a58f81a884e 100644 (file)
@@ -3,6 +3,8 @@
 #include "parse-options.h"
 #include "refs.h"
 #include "wildmatch.h"
+#include "object-store.h"
+#include "repository.h"
 #include "commit.h"
 #include "remote.h"
 #include "color.h"
 #include "trailer.h"
 #include "wt-status.h"
 #include "commit-slab.h"
+#include "commit-graph.h"
+#include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
+#include "argv-array.h"
 
 static struct ref_msg {
        const char *gone;
@@ -40,6 +47,7 @@ void setup_ref_filter_porcelain_msg(void)
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
+typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source;
 
 struct align {
        align_type position;
@@ -59,6 +67,41 @@ struct refname_atom {
        int lstrip, rstrip;
 };
 
+static struct expand_data {
+       struct object_id oid;
+       enum object_type type;
+       unsigned long size;
+       off_t disk_size;
+       struct object_id delta_base_oid;
+       void *content;
+
+       struct object_info info;
+} oi, oi_deref;
+
+struct ref_to_worktree_entry {
+       struct hashmap_entry ent;
+       struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+                                     const struct hashmap_entry *eptr,
+                                     const struct hashmap_entry *kptr,
+                                     const void *keydata_aka_refname)
+{
+       const struct ref_to_worktree_entry *e, *k;
+
+       e = container_of(eptr, const struct ref_to_worktree_entry, ent);
+       k = container_of(kptr, const struct ref_to_worktree_entry, ent);
+
+       return strcmp(e->wt->head_ref,
+               keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct ref_to_worktree_map {
+       struct hashmap map;
+       struct worktree **worktrees;
+} ref_to_worktree_map;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -72,6 +115,7 @@ struct refname_atom {
 static struct used_atom {
        const char *name;
        cmp_type type;
+       info_source source;
        union {
                char color[COLOR_MAXLEN];
                struct align align;
@@ -199,6 +243,48 @@ static int remote_ref_atom_parser(const struct ref_format *format, struct used_a
        return 0;
 }
 
+static int objecttype_atom_parser(const struct ref_format *format, struct used_atom *atom,
+                                 const char *arg, struct strbuf *err)
+{
+       if (arg)
+               return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take arguments"));
+       if (*atom->name == '*')
+               oi_deref.info.typep = &oi_deref.type;
+       else
+               oi.info.typep = &oi.type;
+       return 0;
+}
+
+static int objectsize_atom_parser(const struct ref_format *format, struct used_atom *atom,
+                                 const char *arg, struct strbuf *err)
+{
+       if (!arg) {
+               if (*atom->name == '*')
+                       oi_deref.info.sizep = &oi_deref.size;
+               else
+                       oi.info.sizep = &oi.size;
+       } else if (!strcmp(arg, "disk")) {
+               if (*atom->name == '*')
+                       oi_deref.info.disk_sizep = &oi_deref.disk_size;
+               else
+                       oi.info.disk_sizep = &oi.disk_size;
+       } else
+               return strbuf_addf_ret(err, -1, _("unrecognized %%(objectsize) argument: %s"), arg);
+       return 0;
+}
+
+static int deltabase_atom_parser(const struct ref_format *format, struct used_atom *atom,
+                                const char *arg, struct strbuf *err)
+{
+       if (arg)
+               return strbuf_addf_ret(err, -1, _("%%(deltabase) does not take arguments"));
+       if (*atom->name == '*')
+               oi_deref.info.delta_base_sha1 = oi_deref.delta_base_oid.hash;
+       else
+               oi.info.delta_base_sha1 = oi.delta_base_oid.hash;
+       return 0;
+}
+
 static int body_atom_parser(const struct ref_format *format, struct used_atom *atom,
                            const char *arg, struct strbuf *err)
 {
@@ -223,6 +309,8 @@ static int trailers_atom_parser(const struct ref_format *format, struct used_ato
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
 
+       atom->u.contents.trailer_opts.no_divider = 1;
+
        if (arg) {
                string_list_split(&params, arg, ',', -1);
                for (i = 0; i < params.nr; i++) {
@@ -379,49 +467,56 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 
 static struct {
        const char *name;
+       info_source source;
        cmp_type cmp_type;
        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" },
-       { "objectsize", FIELD_ULONG },
-       { "objectname", FIELD_STR, objectname_atom_parser },
-       { "tree" },
-       { "parent" },
-       { "numparent", FIELD_ULONG },
-       { "object" },
-       { "type" },
-       { "tag" },
-       { "author" },
-       { "authorname" },
-       { "authoremail" },
-       { "authordate", FIELD_TIME },
-       { "committer" },
-       { "committername" },
-       { "committeremail" },
-       { "committerdate", FIELD_TIME },
-       { "tagger" },
-       { "taggername" },
-       { "taggeremail" },
-       { "taggerdate", FIELD_TIME },
-       { "creator" },
-       { "creatordate", FIELD_TIME },
-       { "subject", FIELD_STR, subject_atom_parser },
-       { "body", FIELD_STR, body_atom_parser },
-       { "trailers", FIELD_STR, trailers_atom_parser },
-       { "contents", FIELD_STR, contents_atom_parser },
-       { "upstream", FIELD_STR, remote_ref_atom_parser },
-       { "push", FIELD_STR, remote_ref_atom_parser },
-       { "symref", FIELD_STR, refname_atom_parser },
-       { "flag" },
-       { "HEAD", FIELD_STR, head_atom_parser },
-       { "color", FIELD_STR, color_atom_parser },
-       { "align", FIELD_STR, align_atom_parser },
-       { "end" },
-       { "if", FIELD_STR, if_atom_parser },
-       { "then" },
-       { "else" },
+       { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+       { "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
+       { "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
+       { "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
+       { "deltabase", SOURCE_OTHER, FIELD_STR, deltabase_atom_parser },
+       { "tree", SOURCE_OBJ },
+       { "parent", SOURCE_OBJ },
+       { "numparent", SOURCE_OBJ, FIELD_ULONG },
+       { "object", SOURCE_OBJ },
+       { "type", SOURCE_OBJ },
+       { "tag", SOURCE_OBJ },
+       { "author", SOURCE_OBJ },
+       { "authorname", SOURCE_OBJ },
+       { "authoremail", SOURCE_OBJ },
+       { "authordate", SOURCE_OBJ, FIELD_TIME },
+       { "committer", SOURCE_OBJ },
+       { "committername", SOURCE_OBJ },
+       { "committeremail", SOURCE_OBJ },
+       { "committerdate", SOURCE_OBJ, FIELD_TIME },
+       { "tagger", SOURCE_OBJ },
+       { "taggername", SOURCE_OBJ },
+       { "taggeremail", SOURCE_OBJ },
+       { "taggerdate", SOURCE_OBJ, FIELD_TIME },
+       { "creator", SOURCE_OBJ },
+       { "creatordate", SOURCE_OBJ, FIELD_TIME },
+       { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
+       { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
+       { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
+       { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser },
+       { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+       { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser },
+       { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
+       { "flag", SOURCE_NONE },
+       { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
+       { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+       { "worktreepath", SOURCE_NONE },
+       { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
+       { "end", SOURCE_NONE },
+       { "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
+       { "then", SOURCE_NONE },
+       { "else", SOURCE_NONE },
+       /*
+        * Please update $__git_ref_fieldlist in git-completion.bash
+        * when you add new atoms
+        */
 };
 
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
@@ -490,6 +585,10 @@ static int parse_ref_filter_atom(const struct ref_format *format,
        if (ARRAY_SIZE(valid_atom) <= i)
                return strbuf_addf_ret(err, -1, _("unknown field name: %.*s"),
                                       (int)(ep-atom), atom);
+       if (valid_atom[i].source != SOURCE_NONE && !have_git_dir())
+               return strbuf_addf_ret(err, -1,
+                                      _("not a git repository, but the field '%.*s' requires access to object data"),
+                                      (int)(ep-atom), atom);
 
        /* Add it in, including the deref prefix */
        at = used_atom_cnt;
@@ -497,6 +596,13 @@ static int parse_ref_filter_atom(const struct ref_format *format,
        REALLOC_ARRAY(used_atom, used_atom_cnt);
        used_atom[at].name = xmemdupz(atom, ep - atom);
        used_atom[at].type = valid_atom[i].cmp_type;
+       used_atom[at].source = valid_atom[i].source;
+       if (used_atom[at].source == SOURCE_OBJ) {
+               if (*atom == '*')
+                       oi_deref.info.contentp = &oi_deref.content;
+               else
+                       oi.info.contentp = &oi.content;
+       }
        if (arg) {
                arg = used_atom[at].name + (arg - atom) + 1;
                if (!*arg) {
@@ -792,24 +898,6 @@ int verify_ref_format(struct ref_format *format)
        return 0;
 }
 
-/*
- * Given an object name, read the object data and size, and return a
- * "struct object".  If the object data we are returning is also borrowed
- * by the "struct object" representation, set *eaten as well---it is a
- * signal from parse_object_buffer to us not to free the buffer.
- */
-static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten)
-{
-       enum object_type type;
-       void *buf = read_object_file(oid, &type, sz);
-
-       if (buf)
-               *obj = parse_object_buffer(oid, type, *sz, buf, eaten);
-       else
-               *obj = NULL;
-       return buf;
-}
-
 static int grab_objectname(const char *name, const struct object_id *oid,
                           struct atom_value *v, struct used_atom *atom)
 {
@@ -830,7 +918,7 @@ static int grab_objectname(const char *name, const struct object_id *oid,
 }
 
 /* See grab_values */
-static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_common_values(struct atom_value *val, int deref, struct expand_data *oi)
 {
        int i;
 
@@ -842,18 +930,22 @@ static void grab_common_values(struct atom_value *val, int deref, struct object
                if (deref)
                        name++;
                if (!strcmp(name, "objecttype"))
-                       v->s = type_name(obj->type);
-               else if (!strcmp(name, "objectsize")) {
-                       v->value = sz;
-                       v->s = xstrfmt("%lu", sz);
-               }
+                       v->s = xstrdup(type_name(oi->type));
+               else if (!strcmp(name, "objectsize:disk")) {
+                       v->value = oi->disk_size;
+                       v->s = xstrfmt("%"PRIuMAX, (uintmax_t)oi->disk_size);
+               } else if (!strcmp(name, "objectsize")) {
+                       v->value = oi->size;
+                       v->s = xstrfmt("%"PRIuMAX , (uintmax_t)oi->size);
+               } else if (!strcmp(name, "deltabase"))
+                       v->s = xstrdup(oid_to_hex(&oi->delta_base_oid));
                else if (deref)
-                       grab_objectname(name, &obj->oid, v, &used_atom[i]);
+                       grab_objectname(name, &oi->oid, v, &used_atom[i]);
        }
 }
 
 /* See grab_values */
-static void grab_tag_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_tag_values(struct atom_value *val, int deref, struct object *obj)
 {
        int i;
        struct tag *tag = (struct tag *) obj;
@@ -866,16 +958,16 @@ static void grab_tag_values(struct atom_value *val, int deref, struct object *ob
                if (deref)
                        name++;
                if (!strcmp(name, "tag"))
-                       v->s = tag->tag;
+                       v->s = xstrdup(tag->tag);
                else if (!strcmp(name, "type") && tag->tagged)
-                       v->s = type_name(tag->tagged->type);
+                       v->s = xstrdup(type_name(tag->tagged->type));
                else if (!strcmp(name, "object") && tag->tagged)
                        v->s = xstrdup(oid_to_hex(&tag->tagged->oid));
        }
 }
 
 /* See grab_values */
-static void grab_commit_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_commit_values(struct atom_value *val, int deref, struct object *obj)
 {
        int i;
        struct commit *commit = (struct commit *) obj;
@@ -908,7 +1000,7 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
        }
 }
 
-static const char *find_wholine(const char *who, int wholen, const char *buf, unsigned long sz)
+static const char *find_wholine(const char *who, int wholen, const char *buf)
 {
        const char *eol;
        while (*buf) {
@@ -939,7 +1031,7 @@ static const char *copy_name(const char *buf)
                if (!strncmp(cp, " <", 2))
                        return xmemdupz(buf, cp - buf);
        }
-       return "";
+       return xstrdup("");
 }
 
 static const char *copy_email(const char *buf)
@@ -947,10 +1039,10 @@ static const char *copy_email(const char *buf)
        const char *email = strchr(buf, '<');
        const char *eoemail;
        if (!email)
-               return "";
+               return xstrdup("");
        eoemail = strchr(email, '>');
        if (!eoemail)
-               return "";
+               return xstrdup("");
        return xmemdupz(email, eoemail + 1 - email);
 }
 
@@ -999,12 +1091,12 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
        v->value = timestamp;
        return;
  bad:
-       v->s = "";
+       v->s = xstrdup("");
        v->value = 0;
 }
 
 /* See grab_values */
-static void grab_person(const char *who, struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_person(const char *who, struct atom_value *val, int deref, void *buf)
 {
        int i;
        int wholen = strlen(who);
@@ -1025,7 +1117,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
                    !starts_with(name + wholen, "date"))
                        continue;
                if (!wholine)
-                       wholine = find_wholine(who, wholen, buf, sz);
+                       wholine = find_wholine(who, wholen, buf);
                if (!wholine)
                        return; /* no point looking for it */
                if (name[wholen] == 0)
@@ -1045,7 +1137,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
        if (strcmp(who, "tagger") && strcmp(who, "committer"))
                return; /* "author" for commit object is not wanted */
        if (!wholine)
-               wholine = find_wholine(who, wholen, buf, sz);
+               wholine = find_wholine(who, wholen, buf);
        if (!wholine)
                return;
        for (i = 0; i < used_atom_cnt; i++) {
@@ -1063,7 +1155,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
        }
 }
 
-static void find_subpos(const char *buf, unsigned long sz,
+static void find_subpos(const char *buf,
                        const char **sub, unsigned long *sublen,
                        const char **body, unsigned long *bodylen,
                        unsigned long *nonsiglen,
@@ -1132,7 +1224,7 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
 }
 
 /* See grab_values */
-static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
 {
        int i;
        const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL;
@@ -1152,7 +1244,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
                    !starts_with(name, "contents"))
                        continue;
                if (!subpos)
-                       find_subpos(buf, sz,
+                       find_subpos(buf,
                                    &subpos, &sublen,
                                    &bodypos, &bodylen, &nonsiglen,
                                    &sigpos, &siglen);
@@ -1194,7 +1286,7 @@ static void fill_missing_values(struct atom_value *val)
        for (i = 0; i < used_atom_cnt; i++) {
                struct atom_value *v = &val[i];
                if (v->s == NULL)
-                       v->s = "";
+                       v->s = xstrdup("");
        }
 }
 
@@ -1205,20 +1297,19 @@ static void fill_missing_values(struct atom_value *val)
  * pointed at by the ref itself; otherwise it is the object the
  * ref (which is a tag) refers to.
  */
-static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
+static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf)
 {
-       grab_common_values(val, deref, obj, buf, sz);
        switch (obj->type) {
        case OBJ_TAG:
-               grab_tag_values(val, deref, obj, buf, sz);
-               grab_sub_body_contents(val, deref, obj, buf, sz);
-               grab_person("tagger", val, deref, obj, buf, sz);
+               grab_tag_values(val, deref, obj);
+               grab_sub_body_contents(val, deref, buf);
+               grab_person("tagger", val, deref, buf);
                break;
        case OBJ_COMMIT:
-               grab_commit_values(val, deref, obj, buf, sz);
-               grab_sub_body_contents(val, deref, obj, buf, sz);
-               grab_person("author", val, deref, obj, buf, sz);
-               grab_person("committer", val, deref, obj, buf, sz);
+               grab_commit_values(val, deref, obj);
+               grab_sub_body_contents(val, deref, buf);
+               grab_person("author", val, deref, buf);
+               grab_person("committer", val, deref, buf);
                break;
        case OBJ_TREE:
                /* grab_tree_values(val, deref, obj, buf, sz); */
@@ -1241,7 +1332,8 @@ static inline char *copy_advance(char *dst, const char *src)
 static const char *lstrip_ref_components(const char *refname, int len)
 {
        long remaining = len;
-       const char *start = refname;
+       const char *start = xstrdup(refname);
+       const char *to_free = start;
 
        if (len < 0) {
                int i;
@@ -1262,20 +1354,24 @@ static const char *lstrip_ref_components(const char *refname, int len)
        while (remaining > 0) {
                switch (*start++) {
                case '\0':
-                       return "";
+                       free((char *)to_free);
+                       return xstrdup("");
                case '/':
                        remaining--;
                        break;
                }
        }
 
+       start = xstrdup(start);
+       free((char *)to_free);
        return start;
 }
 
 static const char *rstrip_ref_components(const char *refname, int len)
 {
        long remaining = len;
-       char *start = xstrdup(refname);
+       const char *start = xstrdup(refname);
+       const char *to_free = start;
 
        if (len < 0) {
                int i;
@@ -1295,9 +1391,10 @@ static const char *rstrip_ref_components(const char *refname, int len)
 
        while (remaining-- > 0) {
                char *p = strrchr(start, '/');
-               if (p == NULL)
-                       return "";
-               else
+               if (p == NULL) {
+                       free((char *)to_free);
+                       return xstrdup("");
+               } else
                        p[0] = '\0';
        }
        return start;
@@ -1312,7 +1409,7 @@ static const char *show_ref(struct refname_atom *atom, const char *refname)
        else if (atom->option == R_RSTRIP)
                return rstrip_ref_components(refname, atom->rstrip);
        else
-               return refname;
+               return xstrdup(refname);
 }
 
 static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
@@ -1323,10 +1420,11 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
                *s = show_ref(&atom->u.remote_ref.refname, refname);
        else if (atom->u.remote_ref.option == RR_TRACK) {
                if (stat_tracking_info(branch, &num_ours, &num_theirs,
-                                      NULL, AHEAD_BEHIND_FULL) < 0) {
+                                      NULL, atom->u.remote_ref.push,
+                                      AHEAD_BEHIND_FULL) < 0) {
                        *s = xstrdup(msgs.gone);
                } else if (!num_ours && !num_theirs)
-                       *s = "";
+                       *s = xstrdup("");
                else if (!num_ours)
                        *s = xstrfmt(msgs.behind, num_theirs);
                else if (!num_theirs)
@@ -1341,36 +1439,32 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
                }
        } else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
                if (stat_tracking_info(branch, &num_ours, &num_theirs,
-                                      NULL, AHEAD_BEHIND_FULL) < 0)
+                                      NULL, atom->u.remote_ref.push,
+                                      AHEAD_BEHIND_FULL) < 0) {
+                       *s = xstrdup("");
                        return;
-
+               }
                if (!num_ours && !num_theirs)
-                       *s = "=";
+                       *s = xstrdup("=");
                else if (!num_ours)
-                       *s = "<";
+                       *s = xstrdup("<");
                else if (!num_theirs)
-                       *s = ">";
+                       *s = xstrdup(">");
                else
-                       *s = "<>";
+                       *s = xstrdup("<>");
        } else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {
                int explicit;
                const char *remote = atom->u.remote_ref.push ?
                        pushremote_for_branch(branch, &explicit) :
                        remote_for_branch(branch, &explicit);
-               if (explicit)
-                       *s = xstrdup(remote);
-               else
-                       *s = "";
+               *s = xstrdup(explicit ? remote : "");
        } else if (atom->u.remote_ref.option == RR_REMOTE_REF) {
                int explicit;
                const char *merge;
 
                merge = remote_ref_for_branch(branch, atom->u.remote_ref.push,
                                              &explicit);
-               if (explicit)
-                       *s = xstrdup(merge);
-               else
-                       *s = "";
+               *s = xstrdup(explicit ? merge : "");
        } else
                BUG("unhandled RR_* enum");
 }
@@ -1380,36 +1474,36 @@ char *get_head_description(void)
        struct strbuf desc = STRBUF_INIT;
        struct wt_status_state state;
        memset(&state, 0, sizeof(state));
-       wt_status_get_state(&state, 1);
+       wt_status_get_state(the_repository, &state, 1);
+
+       /*
+        * The ( character must be hard-coded and not part of a localizable
+        * string, since the description is used as a sort key and compared
+        * with ref names.
+        */
+       strbuf_addch(&desc, '(');
        if (state.rebase_in_progress ||
            state.rebase_interactive_in_progress) {
                if (state.branch)
-                       strbuf_addf(&desc, _("(no branch, rebasing %s)"),
+                       strbuf_addf(&desc, _("no branch, rebasing %s"),
                                    state.branch);
                else
-                       strbuf_addf(&desc, _("(no branch, rebasing detached HEAD %s)"),
+                       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)"),
+               strbuf_addf(&desc, _("no branch, bisect started on %s"),
                            state.branch);
        else if (state.detached_from) {
                if (state.detached_at)
-                       /*
-                        * TRANSLATORS: make sure this matches "HEAD
-                        * detached at " in wt-status.c
-                        */
-                       strbuf_addf(&desc, _("(HEAD detached at %s)"),
-                               state.detached_from);
+                       strbuf_addstr(&desc, HEAD_DETACHED_AT);
                else
-                       /*
-                        * TRANSLATORS: make sure this matches "HEAD
-                        * detached from " in wt-status.c
-                        */
-                       strbuf_addf(&desc, _("(HEAD detached from %s)"),
-                               state.detached_from);
+                       strbuf_addstr(&desc, HEAD_DETACHED_FROM);
+               strbuf_addstr(&desc, state.detached_from);
        }
        else
-               strbuf_addstr(&desc, _("(no branch)"));
+               strbuf_addstr(&desc, _("no branch"));
+       strbuf_addch(&desc, ')');
+
        free(state.branch);
        free(state.onto);
        free(state.detached_from);
@@ -1419,7 +1513,7 @@ char *get_head_description(void)
 static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref)
 {
        if (!ref->symref)
-               return "";
+               return xstrdup("");
        else
                return show_ref(&atom->u.refname, ref->symref);
 }
@@ -1431,24 +1525,83 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re
        return show_ref(&atom->u.refname, ref->refname);
 }
 
-static int get_object(struct ref_array_item *ref, const struct object_id *oid,
-                      int deref, struct object **obj, struct strbuf *err)
+static int get_object(struct ref_array_item *ref, int deref, struct object **obj,
+                     struct expand_data *oi, struct strbuf *err)
 {
-       int eaten;
-       int ret = 0;
-       unsigned long size;
-       void *buf = get_obj(oid, obj, &size, &eaten);
-       if (!buf)
-               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);
+       /* parse_object_buffer() will set eaten to 0 if free() will be needed */
+       int eaten = 1;
+       if (oi->info.contentp) {
+               /* We need to know that to use parse_object_buffer properly */
+               oi->info.sizep = &oi->size;
+               oi->info.typep = &oi->type;
+       }
+       if (oid_object_info_extended(the_repository, &oi->oid, &oi->info,
+                                    OBJECT_INFO_LOOKUP_REPLACE))
+               return strbuf_addf_ret(err, -1, _("missing object %s for %s"),
+                                      oid_to_hex(&oi->oid), ref->refname);
+       if (oi->info.disk_sizep && oi->disk_size < 0)
+               BUG("Object size is less than zero.");
+
+       if (oi->info.contentp) {
+               *obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);
+               if (!obj) {
+                       if (!eaten)
+                               free(oi->content);
+                       return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"),
+                                              oid_to_hex(&oi->oid), ref->refname);
+               }
+               grab_values(ref->value, deref, *obj, oi->content);
+       }
+
+       grab_common_values(ref->value, deref, oi);
        if (!eaten)
-               free(buf);
-       return ret;
+               free(oi->content);
+       return 0;
+}
+
+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
+{
+       int i;
+
+       for (i = 0; worktrees[i]; i++) {
+               if (worktrees[i]->head_ref) {
+                       struct ref_to_worktree_entry *entry;
+                       entry = xmalloc(sizeof(*entry));
+                       entry->wt = worktrees[i];
+                       hashmap_entry_init(&entry->ent,
+                                       strhash(worktrees[i]->head_ref));
+
+                       hashmap_add(map, &entry->ent);
+               }
+       }
+}
+
+static void lazy_init_worktree_map(void)
+{
+       if (ref_to_worktree_map.worktrees)
+               return;
+
+       ref_to_worktree_map.worktrees = get_worktrees(0);
+       hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
+       populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
+}
+
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+       struct hashmap_entry entry, *e;
+       struct ref_to_worktree_entry *lookup_result;
+
+       lazy_init_worktree_map();
+
+       hashmap_entry_init(&entry, strhash(ref->refname));
+       e = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+
+       if (!e)
+               return xstrdup("");
+
+       lookup_result = container_of(e, struct ref_to_worktree_entry, ent);
+
+       return xstrdup(lookup_result->wt->path);
 }
 
 /*
@@ -1458,7 +1611,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 {
        struct object *obj;
        int i;
-       const struct object_id *tagged;
+       struct object_info empty = OBJECT_INFO_INIT;
 
        ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value));
 
@@ -1466,7 +1619,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
                ref->symref = resolve_refdup(ref->refname, RESOLVE_REF_READING,
                                             NULL, NULL);
                if (!ref->symref)
-                       ref->symref = "";
+                       ref->symref = xstrdup("");
        }
 
        /* Fill in specials first */
@@ -1488,22 +1641,34 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
                if (starts_with(name, "refname"))
                        refname = get_refname(atom, ref);
+               else if (!strcmp(name, "worktreepath")) {
+                       if (ref->kind == FILTER_REFS_BRANCHES)
+                               v->s = get_worktree_path(atom, ref);
+                       else
+                               v->s = xstrdup("");
+                       continue;
+               }
                else if (starts_with(name, "symref"))
                        refname = get_symref(atom, ref);
                else if (starts_with(name, "upstream")) {
                        const char *branch_name;
                        /* only local branches may have an upstream */
                        if (!skip_prefix(ref->refname, "refs/heads/",
-                                        &branch_name))
+                                        &branch_name)) {
+                               v->s = xstrdup("");
                                continue;
+                       }
                        branch = branch_get(branch_name);
 
                        refname = branch_get_upstream(branch, NULL);
                        if (refname)
                                fill_remote_ref_details(atom, refname, branch, &v->s);
+                       else
+                               v->s = xstrdup("");
                        continue;
                } else if (atom->u.remote_ref.push) {
                        const char *branch_name;
+                       v->s = xstrdup("");
                        if (!skip_prefix(ref->refname, "refs/heads/",
                                         &branch_name))
                                continue;
@@ -1516,10 +1681,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
                                if (!refname)
                                        continue;
                        }
+                       /* We will definitely re-init v->s on the next line. */
+                       free((char *)v->s);
                        fill_remote_ref_details(atom, refname, branch, &v->s);
                        continue;
                } else if (starts_with(name, "color:")) {
-                       v->s = atom->u.color;
+                       v->s = xstrdup(atom->u.color);
                        continue;
                } else if (!strcmp(name, "flag")) {
                        char buf[256], *cp = buf;
@@ -1528,7 +1695,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
                        if (ref->flag & REF_ISPACKED)
                                cp = copy_advance(cp, ",packed");
                        if (cp == buf)
-                               v->s = "";
+                               v->s = xstrdup("");
                        else {
                                *cp = '\0';
                                v->s = xstrdup(buf + 1);
@@ -1538,47 +1705,60 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
                        continue;
                } else if (!strcmp(name, "HEAD")) {
                        if (atom->u.head && !strcmp(ref->refname, atom->u.head))
-                               v->s = "*";
+                               v->s = xstrdup("*");
                        else
-                               v->s = " ";
+                               v->s = xstrdup(" ");
                        continue;
                } else if (starts_with(name, "align")) {
                        v->handler = align_atom_handler;
+                       v->s = xstrdup("");
                        continue;
                } else if (!strcmp(name, "end")) {
                        v->handler = end_atom_handler;
+                       v->s = xstrdup("");
                        continue;
                } else if (starts_with(name, "if")) {
                        const char *s;
-
                        if (skip_prefix(name, "if:", &s))
                                v->s = xstrdup(s);
+                       else
+                               v->s = xstrdup("");
                        v->handler = if_atom_handler;
                        continue;
                } else if (!strcmp(name, "then")) {
                        v->handler = then_atom_handler;
+                       v->s = xstrdup("");
                        continue;
                } else if (!strcmp(name, "else")) {
                        v->handler = else_atom_handler;
+                       v->s = xstrdup("");
                        continue;
                } else
                        continue;
 
                if (!deref)
-                       v->s = refname;
+                       v->s = xstrdup(refname);
                else
                        v->s = xstrfmt("%s^{}", refname);
+               free((char *)refname);
        }
 
        for (i = 0; i < used_atom_cnt; i++) {
                struct atom_value *v = &ref->value[i];
-               if (v->s == NULL)
-                       break;
+               if (v->s == NULL && used_atom[i].source == SOURCE_NONE)
+                       return strbuf_addf_ret(err, -1, _("missing object %s for %s"),
+                                              oid_to_hex(&ref->objectname), ref->refname);
        }
-       if (used_atom_cnt <= i)
+
+       if (need_tagged)
+               oi.info.contentp = &oi.content;
+       if (!memcmp(&oi.info, &empty, sizeof(empty)) &&
+           !memcmp(&oi_deref.info, &empty, sizeof(empty)))
                return 0;
 
-       if (get_object(ref, &ref->objectname, 0, &obj, err))
+
+       oi.oid = ref->objectname;
+       if (get_object(ref, 0, &obj, &oi, err))
                return -1;
 
        /*
@@ -1592,7 +1772,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
         * If it is a tag object, see if we use a value that derefs
         * the object, and if we do grab the object it refers to.
         */
-       tagged = &((struct tag *)obj)->tagged->oid;
+       oi_deref.oid = *get_tagged_oid((struct tag *)obj);
 
        /*
         * NEEDSWORK: This derefs tag only once, which
@@ -1600,7 +1780,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
         * is not consistent with what deref_tag() does
         * which peels the onion to the core.
         */
-       return get_object(ref, tagged, 1, &obj, err);
+       return get_object(ref, 1, &obj, &oi_deref, err);
 }
 
 /*
@@ -1619,129 +1799,6 @@ static int get_ref_atom_value(struct ref_array_item *ref, int atom,
        return 0;
 }
 
-/*
- * Unknown has to be "0" here, because that's the default value for
- * contains_cache slab entries that have not yet been assigned.
- */
-enum contains_result {
-       CONTAINS_UNKNOWN = 0,
-       CONTAINS_NO,
-       CONTAINS_YES
-};
-
-define_commit_slab(contains_cache, enum contains_result);
-
-struct ref_filter_cbdata {
-       struct ref_array *array;
-       struct ref_filter *filter;
-       struct contains_cache contains_cache;
-       struct contains_cache no_contains_cache;
-};
-
-/*
- * Mimicking the real stack, this stack lives on the heap, avoiding stack
- * overflows.
- *
- * At each recursion step, the stack items points to the commits whose
- * ancestors are to be inspected.
- */
-struct contains_stack {
-       int nr, alloc;
-       struct contains_stack_entry {
-               struct commit *commit;
-               struct commit_list *parents;
-       } *contains_stack;
-};
-
-static int in_commit_list(const struct commit_list *want, struct commit *c)
-{
-       for (; want; want = want->next)
-               if (!oidcmp(&want->item->object.oid, &c->object.oid))
-                       return 1;
-       return 0;
-}
-
-/*
- * Test whether the candidate or one of its parents 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)
-{
-       enum contains_result *cached = contains_cache_at(cache, candidate);
-
-       /* If we already have the answer cached, return that. */
-       if (*cached)
-               return *cached;
-
-       /* or are we it? */
-       if (in_commit_list(want, candidate)) {
-               *cached = CONTAINS_YES;
-               return CONTAINS_YES;
-       }
-
-       /* Otherwise, we don't know; prepare to recurse */
-       parse_commit_or_die(candidate);
-       return CONTAINS_UNKNOWN;
-}
-
-static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
-{
-       ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc);
-       contains_stack->contains_stack[contains_stack->nr].commit = candidate;
-       contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents;
-}
-
-static enum contains_result contains_tag_algo(struct commit *candidate,
-                                             const struct commit_list *want,
-                                             struct contains_cache *cache)
-{
-       struct contains_stack contains_stack = { 0, 0, NULL };
-       enum contains_result result = contains_test(candidate, want, cache);
-
-       if (result != CONTAINS_UNKNOWN)
-               return result;
-
-       push_to_contains_stack(candidate, &contains_stack);
-       while (contains_stack.nr) {
-               struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
-               struct commit *commit = entry->commit;
-               struct commit_list *parents = entry->parents;
-
-               if (!parents) {
-                       *contains_cache_at(cache, commit) = CONTAINS_NO;
-                       contains_stack.nr--;
-               }
-               /*
-                * 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)) {
-               case CONTAINS_YES:
-                       *contains_cache_at(cache, commit) = CONTAINS_YES;
-                       contains_stack.nr--;
-                       break;
-               case CONTAINS_NO:
-                       entry->parents = parents->next;
-                       break;
-               case CONTAINS_UNKNOWN:
-                       push_to_contains_stack(parents->item, &contains_stack);
-                       break;
-               }
-       }
-       free(contains_stack.contains_stack);
-       return contains_test(candidate, want, cache);
-}
-
-static int commit_contains(struct ref_filter *filter, struct commit *commit,
-                          struct commit_list *list, struct contains_cache *cache)
-{
-       if (filter->with_commit_tag_algo)
-               return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
-       return is_descendant_of(commit, list);
-}
-
 /*
  * Return 1 if the refname matches one of the patterns, otherwise 0.
  * A pattern can be a literal prefix (e.g. a refname "refs/heads/master"
@@ -1797,7 +1854,7 @@ static int match_name_as_path(const struct ref_filter *filter, const char *refna
                     refname[plen] == '/' ||
                     p[plen-1] == '/'))
                        return 1;
-               if (!wildmatch(p, refname, WM_PATHNAME))
+               if (!wildmatch(p, refname, flags))
                        return 1;
        }
        return 0;
@@ -1813,21 +1870,62 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
        return match_pattern(filter, refname);
 }
 
-/*
- * Find the longest prefix of pattern we can pass to
- * `for_each_fullref_in()`, namely the part of pattern preceding the
- * first glob character. (Note that `for_each_fullref_in()` is
- * perfectly happy working with a prefix that doesn't end at a
- * pathname component boundary.)
- */
-static void find_longest_prefix(struct strbuf *out, const char *pattern)
+static int qsort_strcmp(const void *va, const void *vb)
 {
-       const char *p;
+       const char *a = *(const char **)va;
+       const char *b = *(const char **)vb;
+
+       return strcmp(a, b);
+}
+
+static void find_longest_prefixes_1(struct string_list *out,
+                                 struct strbuf *prefix,
+                                 const char **patterns, size_t nr)
+{
+       size_t i;
+
+       for (i = 0; i < nr; i++) {
+               char c = patterns[i][prefix->len];
+               if (!c || is_glob_special(c)) {
+                       string_list_append(out, prefix->buf);
+                       return;
+               }
+       }
+
+       i = 0;
+       while (i < nr) {
+               size_t end;
+
+               /*
+               * Set "end" to the index of the element _after_ the last one
+               * in our group.
+               */
+               for (end = i + 1; end < nr; end++) {
+                       if (patterns[i][prefix->len] != patterns[end][prefix->len])
+                               break;
+               }
 
-       for (p = pattern; *p && !is_glob_special(*p); p++)
-               ;
+               strbuf_addch(prefix, patterns[i][prefix->len]);
+               find_longest_prefixes_1(out, prefix, patterns + i, end - i);
+               strbuf_setlen(prefix, prefix->len - 1);
 
-       strbuf_add(out, pattern, p - pattern);
+               i = end;
+       }
+}
+
+static void find_longest_prefixes(struct string_list *out,
+                                 const char **patterns)
+{
+       struct argv_array sorted = ARGV_ARRAY_INIT;
+       struct strbuf prefix = STRBUF_INIT;
+
+       argv_array_pushv(&sorted, patterns);
+       QSORT(sorted.argv, sorted.argc, qsort_strcmp);
+
+       find_longest_prefixes_1(out, &prefix, sorted.argv, sorted.argc);
+
+       argv_array_clear(&sorted);
+       strbuf_release(&prefix);
 }
 
 /*
@@ -1840,7 +1938,8 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
                                       void *cb_data,
                                       int broken)
 {
-       struct strbuf prefix = STRBUF_INIT;
+       struct string_list prefixes = STRING_LIST_INIT_DUP;
+       struct string_list_item *prefix;
        int ret;
 
        if (!filter->match_as_path) {
@@ -1852,26 +1951,29 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
                return for_each_fullref_in("", cb, cb_data, broken);
        }
 
-       if (!filter->name_patterns[0]) {
-               /* no patterns; we have to look at everything */
+       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[1]) {
-               /*
-                * multiple patterns; in theory this could still work as long
-                * as the patterns are disjoint. We'd just make multiple calls
-                * to for_each_ref(). But if they're not disjoint, we'd end up
-                * reporting the same ref multiple times. So let's punt on that
-                * for now.
-                */
+       if (!filter->name_patterns[0]) {
+               /* no patterns; we have to look at everything */
                return for_each_fullref_in("", cb, cb_data, broken);
        }
 
-       find_longest_prefix(&prefix, filter->name_patterns[0]);
+       find_longest_prefixes(&prefixes, filter->name_patterns);
 
-       ret = for_each_fullref_in(prefix.buf, cb, cb_data, broken);
-       strbuf_release(&prefix);
+       for_each_string_list_item(prefix, &prefixes) {
+               ret = for_each_fullref_in(prefix->string, cb, cb_data, broken);
+               if (ret)
+                       break;
+       }
+
+       string_list_clear(&prefixes, 0);
        return ret;
 }
 
@@ -1897,11 +1999,11 @@ static const struct object_id *match_points_at(struct oid_array *points_at,
 
        if (oid_array_lookup(points_at, oid) >= 0)
                return oid;
-       obj = parse_object(oid);
+       obj = parse_object(the_repository, oid);
        if (!obj)
                die(_("malformed object at '%s'"), refname);
        if (obj->type == OBJ_TAG)
-               tagged_oid = &((struct tag *)obj)->tagged->oid;
+               tagged_oid = get_tagged_oid((struct tag *)obj);
        if (tagged_oid && oid_array_lookup(points_at, tagged_oid) >= 0)
                return tagged_oid;
        return NULL;
@@ -1968,6 +2070,13 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)
        return ref_kind_from_refname(refname);
 }
 
+struct ref_filter_cbdata {
+       struct ref_array *array;
+       struct ref_filter *filter;
+       struct contains_cache contains_cache;
+       struct contains_cache no_contains_cache;
+};
+
 /*
  * A call-back given to for_each_ref().  Filter refs and keep them for
  * later object processing.
@@ -2007,7 +2116,8 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
         * non-commits early. The actual filtering is done later.
         */
        if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) {
-               commit = lookup_commit_reference_gently(oid, 1);
+               commit = lookup_commit_reference_gently(the_repository, oid,
+                                                       1);
                if (!commit)
                        return 0;
                /* We perform the filtering for the '--contains' option... */
@@ -2037,6 +2147,12 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
 static void free_array_item(struct ref_array_item *item)
 {
        free((char *)item->symref);
+       if (item->value) {
+               int i;
+               for (i = 0; i < used_atom_cnt; i++)
+                       free((char *)item->value[i].s);
+               free(item->value);
+       }
        free(item);
 }
 
@@ -2049,6 +2165,18 @@ void ref_array_clear(struct ref_array *array)
                free_array_item(array->items[i]);
        FREE_AND_NULL(array->items);
        array->nr = array->alloc = 0;
+
+       for (i = 0; i < used_atom_cnt; i++)
+               free((char *)used_atom[i].name);
+       FREE_AND_NULL(used_atom);
+       used_atom_cnt = 0;
+
+       if (ref_to_worktree_map.worktrees) {
+               hashmap_free_entries(&(ref_to_worktree_map.map),
+                                       struct ref_to_worktree_entry, ent);
+               free_worktrees(ref_to_worktree_map.worktrees);
+               ref_to_worktree_map.worktrees = NULL;
+       }
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
@@ -2059,7 +2187,7 @@ static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
        struct ref_array *array = ref_cbdata->array;
        struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
 
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
 
        for (i = 0; i < array->nr; i++) {
                struct ref_array_item *item = array->items[i];
@@ -2337,8 +2465,13 @@ void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
 
 int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
 {
-       if (!arg) /* should --no-sort void the list ? */
-               return -1;
+       /*
+        * NEEDSWORK: We should probably clear the list in this case, but we've
+        * already munged the global used_atoms list, which would need to be
+        * undone.
+        */
+       BUG_ON_OPT_NEG(unset);
+
        parse_ref_sorting(opt->value, arg);
        return 0;
 }
@@ -2349,11 +2482,15 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
        struct object_id oid;
        int no_merged = starts_with(opt->long_name, "no");
 
+       BUG_ON_OPT_NEG(unset);
+
        if (rf->merge) {
                if (no_merged) {
-                       return opterror(opt, "is incompatible with --merged", 0);
+                       return error(_("option `%s' is incompatible with --merged"),
+                                    opt->long_name);
                } else {
-                       return opterror(opt, "is incompatible with --no-merged", 0);
+                       return error(_("option `%s' is incompatible with --no-merged"),
+                                    opt->long_name);
                }
        }
 
@@ -2364,9 +2501,10 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
        if (get_oid(arg, &oid))
                die(_("malformed object name %s"), arg);
 
-       rf->merge_commit = lookup_commit_reference_gently(&oid, 0);
+       rf->merge_commit = lookup_commit_reference_gently(the_repository,
+                                                         &oid, 0);
        if (!rf->merge_commit)
-               return opterror(opt, "must point to a commit", 0);
+               return error(_("option `%s' must point to a commit"), opt->long_name);
 
        return 0;
 }