Skip to content

Commit 6436a20

Browse files
Denton-Lgitster
authored andcommitted
refs: allow @{n} to work with n-sized reflog
This sequence works $ git checkout -b newbranch $ git commit --allow-empty -m one $ git show -s newbranch@{1} and shows the state that was immediately after the newbranch was created. But then if you do $ git reflog expire --expire=now refs/heads/newbranch $ git commit --allow=empty -m two $ git show -s newbranch@{1} you'd be scolded with fatal: log for 'newbranch' only has 1 entries While it is true that it has only 1 entry, we have enough information in that single entry that records the transition between the state in which the tip of the branch was pointing at commit 'one' to the new commit 'two' built on it, so we should be able to answer "what object newbranch was pointing at?". But we refuse to do so. Make @{0} the special case where we use the new side to look up that entry. Otherwise, look up @{n} using the old side of the (n-1)th entry of the reflog. Suggested-by: Junio C Hamano <[email protected]> Signed-off-by: Denton Liu <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 95c2a71 commit 6436a20

File tree

3 files changed

+47
-16
lines changed

3 files changed

+47
-16
lines changed

refs.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -900,40 +900,53 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
900900
const char *message, void *cb_data)
901901
{
902902
struct read_ref_at_cb *cb = cb_data;
903+
int reached_count;
903904

904905
cb->tz = tz;
905906
cb->date = timestamp;
906907

907-
if (timestamp <= cb->at_time || cb->cnt == 0) {
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) {
908916
set_read_ref_cutoffs(cb, timestamp, tz, message);
909917
/*
910918
* we have not yet updated cb->[n|o]oid so they still
911919
* hold the values for the previous record.
912920
*/
913-
if (!is_null_oid(&cb->ooid)) {
914-
oidcpy(cb->oid, noid);
915-
if (!oideq(&cb->ooid, noid))
916-
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"),
917923
cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
918-
}
919-
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)
920927
oidcpy(cb->oid, noid);
921928
else if (!oideq(noid, cb->oid))
922929
warning(_("log for ref %s unexpectedly ended on %s"),
923930
cb->refname, show_date(cb->date, cb->tz,
924931
DATE_MODE(RFC2822)));
925-
cb->reccnt++;
926-
oidcpy(&cb->ooid, ooid);
927-
oidcpy(&cb->noid, noid);
928932
cb->found_it = 1;
929-
return 1;
930933
}
931934
cb->reccnt++;
932935
oidcpy(&cb->ooid, ooid);
933936
oidcpy(&cb->noid, noid);
934-
if (cb->cnt > 0)
935-
cb->cnt--;
936-
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;
937950
}
938951

939952
static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *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)