aboutsummaryrefslogtreecommitdiffstats
path: root/refs.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2024-03-05 09:44:42 -0800
committerJunio C Hamano <gitster@pobox.com>2024-03-05 09:44:42 -0800
commit74522bbd98418bf94e918cef2cf911402eca692f (patch)
treedfe7e57ac15749074e68e24972d048b8ca47e3c0 /refs.c
parentMerge branch 'jc/no-include-of-compat-util-from-headers' (diff)
parentread_ref_at(): special-case ref@{0} for an empty reflog (diff)
downloadgit-74522bbd98418bf94e918cef2cf911402eca692f.tar.gz
git-74522bbd98418bf94e918cef2cf911402eca692f.zip
Merge branch 'jk/reflog-special-cases-fix'
The logic to access reflog entries by date and number had ugly corner cases at the boundaries, which have been cleaned up. * jk/reflog-special-cases-fix: read_ref_at(): special-case ref@{0} for an empty reflog get_oid_basic(): special-case ref@{n} for oldest reflog entry Revert "refs: allow @{n} to work with n-sized reflog"
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c65
1 files changed, 30 insertions, 35 deletions
diff --git a/refs.c b/refs.c
index f9261267f0..c6d412877d 100644
--- a/refs.c
+++ b/refs.c
@@ -1039,55 +1039,40 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
const char *message, void *cb_data)
{
struct read_ref_at_cb *cb = cb_data;
- int reached_count;
cb->tz = tz;
cb->date = timestamp;
- /*
- * 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) {
+ if (timestamp <= cb->at_time || cb->cnt == 0) {
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) && !oideq(&cb->ooid, noid))
- warning(_("log for ref %s has gap after %s"),
+ if (!is_null_oid(&cb->ooid)) {
+ oidcpy(cb->oid, noid);
+ if (!oideq(&cb->ooid, noid))
+ warning(_("log for ref %s has gap after %s"),
cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
- if (reached_count)
- oidcpy(cb->oid, ooid);
- else if (!is_null_oid(&cb->ooid) || cb->date == cb->at_time)
+ }
+ else if (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)));
+ cb->reccnt++;
+ oidcpy(&cb->ooid, ooid);
+ oidcpy(&cb->noid, noid);
cb->found_it = 1;
+ return 1;
}
cb->reccnt++;
oidcpy(&cb->ooid, ooid);
oidcpy(&cb->noid, noid);
- return cb->found_it;
-}
-
-static int read_ref_at_ent_newest(struct object_id *ooid UNUSED,
- struct object_id *noid,
- const char *email UNUSED,
- 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;
+ if (cb->cnt > 0)
+ cb->cnt--;
+ return 0;
}
static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
@@ -1099,7 +1084,7 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid
set_read_ref_cutoffs(cb, timestamp, tz, message);
oidcpy(cb->oid, ooid);
- if (is_null_oid(cb->oid))
+ if (cb->at_time && is_null_oid(cb->oid))
oidcpy(cb->oid, noid);
/* We just want the first entry */
return 1;
@@ -1122,14 +1107,24 @@ 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) {
+ if (cnt == 0) {
+ /*
+ * The caller asked for ref@{0}, and we had no entries.
+ * It's a bit subtle, but in practice all callers have
+ * prepped the "oid" field with the current value of
+ * the ref, which is the most reasonable fallback.
+ *
+ * We'll put dummy values into the out-parameters (so
+ * they're not just uninitialized garbage), and the
+ * caller can take our return value as a hint that
+ * we did not find any such reflog.
+ */
+ set_read_ref_cutoffs(&cb, 0, 0, "empty reflog");
+ return 1;
+ }
if (flags & GET_OID_QUIETLY)
exit(128);
else