All of lore.kernel.org
 help / color / mirror / Atom feed
From: Patrick Steinhardt <ps@pks.im>
To: Daniel Zoghalchali <daniel@latchkey.dev>
Cc: git@vger.kernel.org
Subject: Re: [BUG] 2.56.0: filtered --unshallow of a moved ref aborts in pack-objects (should_include_obj) via inherited GIT_SHALLOW_FILE
Date: Mon, 26 Oct 2026 14:04:30 +0100	[thread overview]
Message-ID: <at9P0ctULX1BBD8y@pks.im> (raw)
In-Reply-To: <CAJwQ=KQynymg4CJOLkyebACYVQa+LhXB2UifniTASkLyArWejA@mail.gmail.com>

Hi,

On Sat, Oct 24, 2026 at 10:59:55AM -0700, Daniel Zoghalchali wrote:
> Hi,
> 
> Since v2.56.0, a fetch that combines a tree filter with --unshallow
> (or --deepen) aborts in a non-partial shallow clone when the fetched
> ref has moved past the local tip:
> 
>   BUG: builtin/pack-objects.c:5098: should_include_obj should only be
> called on existing objects
>   error: pack-objects died of signal 6
>   fatal: could not finish pack-objects to repack local links
>   fatal: index-pack failed
> 
> v2.55.0 completes the same fetch. We hit it in CI, where a job checks
> out a single commit at depth 1 and then unshallows its branch, which
> by then has moved on.
> 
> Reproduction (offline, any Linux):
> 
>   set -e
>   W=$(mktemp -d); cd "$W"
>   git init -q -b dev seed
>   for i in 1 2 3 4; do
>     mkdir -p seed/src; echo "$i" > seed/src/f.txt
>     git -C seed add -A
>     git -C seed -c user.name=t -c user.email=t@t \
>       commit -q -m "c$i"
>   done
>   git init -q --bare o.git
>   git -C seed push -q "$W/o.git" dev
>   git -C o.git config uploadpack.allowFilter true
>   git -C o.git config uploadpack.allowAnySHA1InWant true
>   git init -q co
>   git -C co remote add origin "file://$W/o.git"
>   TIP1=$(git -C seed rev-parse dev~1)
>   git -C co fetch -q --no-tags --depth=1 origin \
>     "+$TIP1:refs/remotes/origin/dev"
>   git -C co checkout -q -B dev refs/remotes/origin/dev
>   git -C co fetch --no-tags --filter=tree:0 --unshallow origin \
>     +refs/heads/dev:refs/remotes/origin/dev

Thanks, this reproducer works for me.

> The last command dies as above with 2.56.0, both Ubuntu 24.04's
> git-core PPA build (1:2.56.0-0ppa1~ubuntu24.04.2) and v2.56.0 built
> from source. It succeeds with v2.55.0 built from source. With 2.56.0
> it also succeeds when dev has not moved past the checkout, with
> --filter=blob:none, or without a filter. --deepen=N with the same
> filter aborts the same way.
> 
> What happens:
> - fetch-pack runs "git --shallow-file '' index-pack --promisor ...".
> - The pack names the local tip as the parent of the new dev commit, so
>   index-pack's repack_local_links() starts "git pack-objects
>   --exclude-promisor-objects-best-effort".
> - Since d43b9acb05 (setup: unify setup of shallow file), --shallow-file
>   is applied by exporting GIT_SHALLOW_FILE, so that grandchild inherits
>   the empty shallow file.
> - The grandchild no longer treats the local tip as a shallow boundary.
>   It walks to the tip's parent, a promisor commit fetched without trees,
>   and is_not_in_promisor_pack_obj() hits the BUG on that parent's
>   missing root tree.
> - Before d43b9acb05, the grandchild read $GIT_DIR/shallow and stopped at
>   the tip.
> 
> To confirm this, we wrapped only the repack child. Unsetting
> GIT_SHALLOW_FILE for it makes 2.56.0 pass, and setting
> GIT_SHALLOW_FILE= for it makes 2.55.0 fail the same way, at its
> builtin/pack-objects.c:5004.

Makes sense. Even though I think that the bug isn't actually that we
started propagating GIT_SHALLOW_FILE, as we now basically behave like we
do it with all other global variables, too. And if we were to execute a
non-local command like git-receive-pack(1) we already know to unset that
value again via `local_repo_env`.

What's fishy is "builtin/pack-objects.c:is_not_in_promisor_pack_obj()",
which explicitly checks whether a given object is in a promisor or not.
But in the case where we assume that an object may be a promisor object
we know that we're running in a repostitory that may not even have all
of its objects in the first place -- that's the whole ponit of a partial
clone after all. But when `odb_read_object_info_ext()` returns an error
we simply `BUG()` right away, which does not make any sense to me.

> Separately, the BUG() is reachable without the environment change. On
> 2.55.0, a filtered --unshallow of the local tip, followed by a
> filtered fetch of a moved ref, also dies there, because the walk from
> the local tip reaches promisor commits whose trees were never fetched.

Yeah, this bug has the same root cause and I was able to reproduce it,
too. And indeed it confirms my above take as it already exists before
the change to how we propagate GIT_SHALLOW_FILE. So overall, I think the
fix is as simple as this:

diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index ca3a891dfbc..e634173fb1f 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -5085,7 +5085,7 @@ static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
        };

        if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0))
-               BUG("should_include_obj should only be called on existing objects");
+               return 0;
        return source_info.source->type != ODB_SOURCE_PACKED || !source_info.u.packed.pack->pack_promisor;
 }

I'll think a bit more about this and send a patch tomorrow. Thanks!

Patrick

  reply	other threads:[~2026-10-26 13:04 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24 17:59 [BUG] 2.56.0: filtered --unshallow of a moved ref aborts in pack-objects (should_include_obj) via inherited GIT_SHALLOW_FILE Daniel Zoghalchali
2026-10-26 13:04 ` Patrick Steinhardt [this message]
2026-10-27  7:03   ` Patrick Steinhardt

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=at9P0ctULX1BBD8y@pks.im \
    --to=ps@pks.im \
    --cc=daniel@latchkey.dev \
    --cc=git@vger.kernel.org \
    /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.