summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--refs.c78
-rwxr-xr-xt/t1503-rev-parse-verify.sh4
-rwxr-xr-xt/t1508-at-combinations.sh13
3 files changed, 63 insertions, 32 deletions
diff --git a/refs.c b/refs.c
index 13dc2c3..03968ad 100644
--- 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) {
diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
index dc9fe3c..a7e9b48 100755
--- a/t/t1503-rev-parse-verify.sh
+++ b/t/t1503-rev-parse-verify.sh
@@ -86,8 +86,8 @@ test_expect_success 'fails silently when using -q' '
test_expect_success 'fails silently when using -q with deleted reflogs' '
ref=$(git rev-parse HEAD) &&
git update-ref --create-reflog -m "message for refs/test" refs/test "$ref" &&
- git reflog delete --updateref --rewrite refs/test@{0} &&
- test_must_fail git rev-parse -q --verify refs/test@{0} >error 2>&1 &&
+ git reflog delete --updateref --rewrite refs/test@{1} &&
+ test_must_fail git rev-parse -q --verify refs/test@{1} >error 2>&1 &&
test_must_be_empty error
'
diff --git a/t/t1508-at-combinations.sh b/t/t1508-at-combinations.sh
index 4a9964e..e4521b7 100755
--- a/t/t1508-at-combinations.sh
+++ b/t/t1508-at-combinations.sh
@@ -99,4 +99,17 @@ test_expect_success 'create path with @' '
check "@:normal" blob content
check "@:fun@ny" blob content
+test_expect_success '@{1} works with only one reflog entry' '
+ git checkout -B newbranch master &&
+ git reflog expire --expire=now refs/heads/newbranch &&
+ git commit --allow-empty -m "first after expiration" &&
+ test_cmp_rev newbranch~ newbranch@{1}
+'
+
+test_expect_success '@{0} works with empty reflog' '
+ git checkout -B newbranch master &&
+ git reflog expire --expire=now refs/heads/newbranch &&
+ test_cmp_rev newbranch newbranch@{0}
+'
+
test_done