Git development
 help / color / mirror / Atom feed
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


  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