From: Caspar Duregger <caspar.duregger@gmail.com>
To: git@vger.kernel.org
Cc: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>,
Junio C Hamano <gitster@pobox.com>, Jeff King <peff@peff.net>,
"brian m . carlson" <sandals@crustytoothpaste.net>,
Caspar Duregger <caspar.duregger@gmail.com>
Subject: [PATCH 3/4] refs: let read_ref_at() fail gently on an empty reflog
Date: Fri, 13 Nov 2026 15:28:03 +0100 [thread overview]
Message-ID: <20261113142804.7465-4-caspar.duregger@gmail.com> (raw)
In-Reply-To: <20260212040708.GA1894049@coredump.intra.peff.net>
When a reflog exists but has no entries, read_ref_at() can answer
"ref@{0}" with the current value of the ref. For any other request it
dies with "log for <ref> is empty", or exits silently with
GET_OID_QUIETLY, even when the caller asked for GET_OID_GENTLY. Such
reflogs are left behind by "git reflog expire --expire=all".
Return -1 in this case when GET_OID_GENTLY is given, and make
get_oid_basic() treat it as a failed lookup. "git stash export" on an
emptied stash reflog now reports "unable to find stash entry" instead
of exiting without a word.
Signed-off-by: Caspar Duregger <caspar.duregger@gmail.com>
---
object-name.c | 13 +++++++++----
refs.c | 2 ++
refs.h | 4 ++++
t/t3903-stash.sh | 8 ++++++++
4 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/object-name.c b/object-name.c
index c066a7d6a2..1d7cbd8a03 100644
--- a/object-name.c
+++ b/object-name.c
@@ -761,7 +761,7 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
warning(warn_msg, len, str);
if (reflog_len) {
- int nth, i;
+ int nth, i, ret;
timestamp_t at_time;
timestamp_t co_time;
int co_tz, co_cnt;
@@ -789,9 +789,14 @@ static int get_oid_basic(struct repository *r, const char *str, int len,
return -1;
}
}
- if (read_ref_at(get_main_ref_store(r),
- real_ref, flags, at_time, nth, oid, NULL,
- &co_time, &co_tz, &co_cnt)) {
+ ret = read_ref_at(get_main_ref_store(r),
+ real_ref, flags, at_time, nth, oid, NULL,
+ &co_time, &co_tz, &co_cnt);
+ if (ret < 0) {
+ free(real_ref);
+ return -1;
+ }
+ if (ret) {
if (!len) {
if (!skip_prefix(real_ref, "refs/heads/", &str))
str = "HEAD";
diff --git a/refs.c b/refs.c
index 3f7458332e..b6ce62b12a 100644
--- a/refs.c
+++ b/refs.c
@@ -1227,6 +1227,8 @@ int read_ref_at(struct ref_store *refs, const char *refname,
set_read_ref_cutoffs(&cb, 0, 0, "empty reflog");
return 1;
}
+ if (flags & GET_OID_GENTLY)
+ return -1;
if (flags & GET_OID_QUIETLY)
exit(128);
else
diff --git a/refs.h b/refs.h
index ee3b8a62ef..25b8987ca9 100644
--- a/refs.h
+++ b/refs.h
@@ -603,6 +603,10 @@ int refs_create_reflog(struct ref_store *refs, const char *refname,
* that there is one important special case here! If the reflog was empty
* and the caller asked for the 0-th cnt, we will return "1" but leave the
* "oid" field untouched.
+ *
+ * If the reflog was empty and the caller asked for anything else, we die,
+ * or exit silently if "flags" contains GET_OID_QUIETLY. If "flags" contains
+ * GET_OID_GENTLY, we instead return -1.
**/
int read_ref_at(struct ref_store *refs,
const char *refname, unsigned int flags,
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 74ac66f22e..2c41cc2b3f 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -1566,6 +1566,14 @@ test_expect_success 'stash export resolves stash reflog selectors like rev-parse
test_grep "unable to find stash entry stash@{2}" err
'
+test_expect_success 'stash export reports entries of an empty stash reflog' '
+ git stash clear &&
+ git stash import refs/heads/bar &&
+ git reflog expire --expire=all refs/stash &&
+ test_must_fail git stash export --print stash@{1} 2>err &&
+ test_grep "unable to find stash entry stash@{1}" err
+'
+
test_expect_success 'stash export rejects invalid arguments' '
test_must_fail git stash export --print --to-ref refs/heads/invalid 2>err &&
test_grep "exactly one of --print and --to-ref is required" err &&
--
2.56.1.windows.1
next prev parent reply other threads:[~2026-11-13 14:28 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-11 23:13 cat-file: dies with --batch if reflog entry is out of bounds Kristoffer Haugsbakk
2026-02-11 23:40 ` Junio C Hamano
2026-02-12 4:07 ` Jeff King
2026-11-13 14:28 ` [PATCH 0/4] cat-file: do not die on reflog entries out of range Caspar Duregger
2026-11-13 14:28 ` [PATCH 1/4] object-name: do not read a peel suffix as a reflog selector Caspar Duregger
2026-11-13 14:28 ` [PATCH 2/4] object-name: let GET_OID_GENTLY affect only failing lookups Caspar Duregger
2026-11-13 14:28 ` Caspar Duregger [this message]
2026-11-13 14:28 ` [PATCH 4/4] cat-file: report out-of-range reflog entries as missing Caspar Duregger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261113142804.7465-4-caspar.duregger@gmail.com \
--to=caspar.duregger@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=kristofferhaugsbakk@fastmail.com \
--cc=peff@peff.net \
--cc=sandals@crustytoothpaste.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox