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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.