]> git.ipfire.org Git - thirdparty/git.git/blobdiff - refs.c
Merge branch 'dl/stash-cleanup'
[thirdparty/git.git] / refs.c
diff --git a/refs.c b/refs.c
index 13dc2c3291b398aae7c9797155363922def64eff..a665ed5e10acb65f821cfed9e6586c277bdceb48 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -882,51 +882,71 @@ struct read_ref_at_cb {
        int *cutoff_cnt;
 };
 
+static void set_read_ref_cutoffs(struct read_ref_at_cb *cb,
+               timestamp_t timestamp, int tz, const char *message)
+{
+       if (cb->msg)
+               *cb->msg = xstrdup(message);
+       if (cb->cutoff_time)
+               *cb->cutoff_time = timestamp;
+       if (cb->cutoff_tz)
+               *cb->cutoff_tz = tz;
+       if (cb->cutoff_cnt)
+               *cb->cutoff_cnt = cb->reccnt;
+}
+
 static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
                const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
 {
        struct read_ref_at_cb *cb = cb_data;
+       int reached_count;
 
-       cb->reccnt++;
        cb->tz = tz;
        cb->date = timestamp;
 
-       if (timestamp <= cb->at_time || cb->cnt == 0) {
-               if (cb->msg)
-                       *cb->msg = xstrdup(message);
-               if (cb->cutoff_time)
-                       *cb->cutoff_time = timestamp;
-               if (cb->cutoff_tz)
-                       *cb->cutoff_tz = tz;
-               if (cb->cutoff_cnt)
-                       *cb->cutoff_cnt = cb->reccnt - 1;
+       /*
+        * It is not possible for cb->cnt == 0 on the first iteration because
+        * that special case is handled in read_ref_at().
+        */
+       if (cb->cnt > 0)
+               cb->cnt--;
+       reached_count = cb->cnt == 0 && !is_null_oid(ooid);
+       if (timestamp <= cb->at_time || reached_count) {
+               set_read_ref_cutoffs(cb, timestamp, tz, message);
                /*
                 * we have not yet updated cb->[n|o]oid so they still
                 * hold the values for the previous record.
                 */
-               if (!is_null_oid(&cb->ooid)) {
-                       oidcpy(cb->oid, noid);
-                       if (!oideq(&cb->ooid, noid))
-                               warning(_("log for ref %s has gap after %s"),
+               if (!is_null_oid(&cb->ooid) && !oideq(&cb->ooid, noid))
+                       warning(_("log for ref %s has gap after %s"),
                                        cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
-               }
-               else if (cb->date == cb->at_time)
+               if (reached_count)
+                       oidcpy(cb->oid, ooid);
+               else if (!is_null_oid(&cb->ooid) || cb->date == cb->at_time)
                        oidcpy(cb->oid, noid);
                else if (!oideq(noid, cb->oid))
                        warning(_("log for ref %s unexpectedly ended on %s"),
                                cb->refname, show_date(cb->date, cb->tz,
                                                       DATE_MODE(RFC2822)));
-               oidcpy(&cb->ooid, ooid);
-               oidcpy(&cb->noid, noid);
                cb->found_it = 1;
-               return 1;
        }
+       cb->reccnt++;
        oidcpy(&cb->ooid, ooid);
        oidcpy(&cb->noid, noid);
-       if (cb->cnt > 0)
-               cb->cnt--;
-       return 0;
+       return cb->found_it;
+}
+
+static int read_ref_at_ent_newest(struct object_id *ooid, struct object_id *noid,
+                                 const char *email, timestamp_t timestamp,
+                                 int tz, const char *message, void *cb_data)
+{
+       struct read_ref_at_cb *cb = cb_data;
+
+       set_read_ref_cutoffs(cb, timestamp, tz, message);
+       oidcpy(cb->oid, noid);
+       /* We just want the first entry */
+       return 1;
 }
 
 static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
@@ -935,14 +955,7 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid
 {
        struct read_ref_at_cb *cb = cb_data;
 
-       if (cb->msg)
-               *cb->msg = xstrdup(message);
-       if (cb->cutoff_time)
-               *cb->cutoff_time = timestamp;
-       if (cb->cutoff_tz)
-               *cb->cutoff_tz = tz;
-       if (cb->cutoff_cnt)
-               *cb->cutoff_cnt = cb->reccnt;
+       set_read_ref_cutoffs(cb, timestamp, tz, message);
        oidcpy(cb->oid, ooid);
        if (is_null_oid(cb->oid))
                oidcpy(cb->oid, noid);
@@ -967,6 +980,11 @@ int read_ref_at(struct ref_store *refs, const char *refname,
        cb.cutoff_cnt = cutoff_cnt;
        cb.oid = oid;
 
+       if (cb.cnt == 0) {
+               refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent_newest, &cb);
+               return 0;
+       }
+
        refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent, &cb);
 
        if (!cb.reccnt) {
@@ -1546,6 +1564,93 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
        return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
 }
 
+static int qsort_strcmp(const void *va, const void *vb)
+{
+       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;
+               }
+
+               strbuf_addch(prefix, patterns[i][prefix->len]);
+               find_longest_prefixes_1(out, prefix, patterns + i, end - i);
+               strbuf_setlen(prefix, prefix->len - 1);
+
+               i = end;
+       }
+}
+
+static void find_longest_prefixes(struct string_list *out,
+                                 const char **patterns)
+{
+       struct strvec sorted = STRVEC_INIT;
+       struct strbuf prefix = STRBUF_INIT;
+
+       strvec_pushv(&sorted, patterns);
+       QSORT(sorted.v, sorted.nr, qsort_strcmp);
+
+       find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr);
+
+       strvec_clear(&sorted);
+       strbuf_release(&prefix);
+}
+
+int for_each_fullref_in_prefixes(const char *namespace,
+                                const char **patterns,
+                                each_ref_fn fn, void *cb_data,
+                                unsigned int broken)
+{
+       struct string_list prefixes = STRING_LIST_INIT_DUP;
+       struct string_list_item *prefix;
+       struct strbuf buf = STRBUF_INIT;
+       int ret = 0, namespace_len;
+
+       find_longest_prefixes(&prefixes, patterns);
+
+       if (namespace)
+               strbuf_addstr(&buf, namespace);
+       namespace_len = buf.len;
+
+       for_each_string_list_item(prefix, &prefixes) {
+               strbuf_addstr(&buf, prefix->string);
+               ret = for_each_fullref_in(buf.buf, fn, cb_data, broken);
+               if (ret)
+                       break;
+               strbuf_setlen(&buf, namespace_len);
+       }
+
+       string_list_clear(&prefixes, 0);
+       strbuf_release(&buf);
+       return ret;
+}
+
 static int refs_read_special_head(struct ref_store *ref_store,
                                  const char *refname, struct object_id *oid,
                                  struct strbuf *referent, unsigned int *type)
@@ -1898,31 +2003,14 @@ int refs_pack_refs(struct ref_store *refs, unsigned int flags)
        return refs->be->pack_refs(refs, flags);
 }
 
-int refs_peel_ref(struct ref_store *refs, const char *refname,
-                 struct object_id *oid)
+int peel_iterated_oid(const struct object_id *base, struct object_id *peeled)
 {
-       int flag;
-       struct object_id base;
-
-       if (current_ref_iter && current_ref_iter->refname == refname) {
-               struct object_id peeled;
-
-               if (ref_iterator_peel(current_ref_iter, &peeled))
-                       return -1;
-               oidcpy(oid, &peeled);
-               return 0;
-       }
+       if (current_ref_iter &&
+           (current_ref_iter->oid == base ||
+            oideq(current_ref_iter->oid, base)))
+               return ref_iterator_peel(current_ref_iter, peeled);
 
-       if (refs_read_ref_full(refs, refname,
-                              RESOLVE_REF_READING, &base, &flag))
-               return -1;
-
-       return peel_object(&base, oid);
-}
-
-int peel_ref(const char *refname, struct object_id *oid)
-{
-       return refs_peel_ref(get_main_ref_store(the_repository), refname, oid);
+       return peel_object(base, peeled);
 }
 
 int refs_create_symref(struct ref_store *refs,