Skip to content

Commit 440acfb

Browse files
committed
Merge branch 'dl/reflog-with-single-entry'
After expiring a reflog and making a single commit, the reflog for the branch would record a single entry that knows both @{0} and @{1}, but we failed to answer "what commit were we on?", i.e. @{1} * dl/reflog-with-single-entry: refs: allow @{n} to work with n-sized reflog refs: factor out set_read_ref_cutoffs()
2 parents 0806279 + 6436a20 commit 440acfb

File tree

3 files changed

+63
-32
lines changed

3 files changed

+63
-32
lines changed

refs.c

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -882,51 +882,71 @@ struct read_ref_at_cb {
882882
int *cutoff_cnt;
883883
};
884884

885+
static void set_read_ref_cutoffs(struct read_ref_at_cb *cb,
886+
timestamp_t timestamp, int tz, const char *message)
887+
{
888+
if (cb->msg)
889+
*cb->msg = xstrdup(message);
890+
if (cb->cutoff_time)
891+
*cb->cutoff_time = timestamp;
892+
if (cb->cutoff_tz)
893+
*cb->cutoff_tz = tz;
894+
if (cb->cutoff_cnt)
895+
*cb->cutoff_cnt = cb->reccnt;
896+
}
897+
885898
static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
886899
const char *email, timestamp_t timestamp, int tz,
887900
const char *message, void *cb_data)
888901
{
889902
struct read_ref_at_cb *cb = cb_data;
903+
int reached_count;
890904

891-
cb->reccnt++;
892905
cb->tz = tz;
893906
cb->date = timestamp;
894907

895-
if (timestamp <= cb->at_time || cb->cnt == 0) {
896-
if (cb->msg)
897-
*cb->msg = xstrdup(message);
898-
if (cb->cutoff_time)
899-
*cb->cutoff_time = timestamp;
900-
if (cb->cutoff_tz)
901-
*cb->cutoff_tz = tz;
902-
if (cb->cutoff_cnt)
903-
*cb->cutoff_cnt = cb->reccnt - 1;
908+
/*
909+
* It is not possible for cb->cnt == 0 on the first iteration because
910+
* that special case is handled in read_ref_at().
911+
*/
912+
if (cb->cnt > 0)
913+
cb->cnt--;
914+
reached_count = cb->cnt == 0 && !is_null_oid(ooid);
915+
if (timestamp <= cb->at_time || reached_count) {
916+
set_read_ref_cutoffs(cb, timestamp, tz, message);
904917
/*
905918
* we have not yet updated cb->[n|o]oid so they still
906919
* hold the values for the previous record.
907920
*/
908-
if (!is_null_oid(&cb->ooid)) {
909-
oidcpy(cb->oid, noid);
910-
if (!oideq(&cb->ooid, noid))
911-
warning(_("log for ref %s has gap after %s"),
921+
if (!is_null_oid(&cb->ooid) && !oideq(&cb->ooid, noid))
922+
warning(_("log for ref %s has gap after %s"),
912923
cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
913-
}
914-
else if (cb->date == cb->at_time)
924+
if (reached_count)
925+
oidcpy(cb->oid, ooid);
926+
else if (!is_null_oid(&cb->ooid) || cb->date == cb->at_time)
915927
oidcpy(cb->oid, noid);
916928
else if (!oideq(noid, cb->oid))
917929
warning(_("log for ref %s unexpectedly ended on %s"),
918930
cb->refname, show_date(cb->date, cb->tz,
919931
DATE_MODE(RFC2822)));
920-
oidcpy(&cb->ooid, ooid);
921-
oidcpy(&cb->noid, noid);
922932
cb->found_it = 1;
923-
return 1;
924933
}
934+
cb->reccnt++;
925935
oidcpy(&cb->ooid, ooid);
926936
oidcpy(&cb->noid, noid);
927-
if (cb->cnt > 0)
928-
cb->cnt--;
929-
return 0;
937+
return cb->found_it;
938+
}
939+
940+
static int read_ref_at_ent_newest(struct object_id *ooid, struct object_id *noid,
941+
const char *email, timestamp_t timestamp,
942+
int tz, const char *message, void *cb_data)
943+
{
944+
struct read_ref_at_cb *cb = cb_data;
945+
946+
set_read_ref_cutoffs(cb, timestamp, tz, message);
947+
oidcpy(cb->oid, noid);
948+
/* We just want the first entry */
949+
return 1;
930950
}
931951

932952
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
935955
{
936956
struct read_ref_at_cb *cb = cb_data;
937957

938-
if (cb->msg)
939-
*cb->msg = xstrdup(message);
940-
if (cb->cutoff_time)
941-
*cb->cutoff_time = timestamp;
942-
if (cb->cutoff_tz)
943-
*cb->cutoff_tz = tz;
944-
if (cb->cutoff_cnt)
945-
*cb->cutoff_cnt = cb->reccnt;
958+
set_read_ref_cutoffs(cb, timestamp, tz, message);
946959
oidcpy(cb->oid, ooid);
947960
if (is_null_oid(cb->oid))
948961
oidcpy(cb->oid, noid);
@@ -967,6 +980,11 @@ int read_ref_at(struct ref_store *refs, const char *refname,
967980
cb.cutoff_cnt = cutoff_cnt;
968981
cb.oid = oid;
969982

983+
if (cb.cnt == 0) {
984+
refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent_newest, &cb);
985+
return 0;
986+
}
987+
970988
refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent, &cb);
971989

972990
if (!cb.reccnt) {

t/t1503-rev-parse-verify.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ test_expect_success 'fails silently when using -q' '
8686
test_expect_success 'fails silently when using -q with deleted reflogs' '
8787
ref=$(git rev-parse HEAD) &&
8888
git update-ref --create-reflog -m "message for refs/test" refs/test "$ref" &&
89-
git reflog delete --updateref --rewrite refs/test@{0} &&
90-
test_must_fail git rev-parse -q --verify refs/test@{0} >error 2>&1 &&
89+
git reflog delete --updateref --rewrite refs/test@{1} &&
90+
test_must_fail git rev-parse -q --verify refs/test@{1} >error 2>&1 &&
9191
test_must_be_empty error
9292
'
9393

t/t1508-at-combinations.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,17 @@ test_expect_success 'create path with @' '
9999
check "@:normal" blob content
100100
check "@:fun@ny" blob content
101101

102+
test_expect_success '@{1} works with only one reflog entry' '
103+
git checkout -B newbranch master &&
104+
git reflog expire --expire=now refs/heads/newbranch &&
105+
git commit --allow-empty -m "first after expiration" &&
106+
test_cmp_rev newbranch~ newbranch@{1}
107+
'
108+
109+
test_expect_success '@{0} works with empty reflog' '
110+
git checkout -B newbranch master &&
111+
git reflog expire --expire=now refs/heads/newbranch &&
112+
test_cmp_rev newbranch newbranch@{0}
113+
'
114+
102115
test_done

0 commit comments

Comments
 (0)