# a "limbo" object-format state for empty repositories?

6 messages from 2026-10-02 to 2026-10-05. Participants: Jeff King, brian m. carlson, Junio C Hamano.
Thread: https://gitlist.dev/t/66452

## Jeff King, 2026-10-02 22:44

Subject: a "limbo" object-format state for empty repositories?
Message-ID: <20261002224400.GA834158@coredump.intra.peff.net>

```
Reading Scott's blog post and accompanying HN comments the other day,
one upcoming usability headache stood out to me: first-time pushes to
newly created repositories.

If you create a bare repo on a forge like GitHub, it must be either sha1
or sha256. If the forge continues to create sha1 bare repos by default,
then all of the post-3.0 sha256 users will get this on first push:

  $ git push
  fatal: the receiving end does not support this repository's hash algorithm
  fatal: the remote end hung up unexpectedly

And then they have to go switch or recreate their remote repo. And if
the forge flips to sha256, then we have the opposite problem for pre-3.0
users (and even 3.0 users who are doing a first-push of existing sha1
repositories).

Savvy users will of course specify the object format they expect to use
when they create the server-side repo. But most users won't know or care
about this, and even if they do, it's an easy thing to forget about. So
I expect we'll see a lot of frustration here.

It would be nice if the empty repository could adapt to the object
format used by its first push. Then everything would just work from the
user's perspective, no matter what they push.

GitHub has long done something similar for the HEAD pointer; on first
push of a single branch it is pointed at that branch. There it was not
too hard to add custom code around Git that detected the situation and
set up the symref. But I don't think you can quite do the same thing for
the object format, because the push advertisement actually says "hey,
I'm a <hash> repo" in its capabilities. So the client says "oh, that
doesn't match me" and bails before actually pushing anything.

So what I'm suggesting instead is that the server be allowed to
advertise a limbo state: it has no object format yet. And then client
can recognize object-format=limbo, and send back "I'm a <sha1|sha256>
repo, so that's what I'm sending you" in its capabilities response.  And
then the server receives that and shifts its local object-format to
match.

There are some tricky bits on the server side (e.g., you'd want to flip
the value atomically so that if you get two simultaneous mismatched
pushes, one of them gets rejected). But I can't think of any reason that
it couldn't conceptually work, and I feel like it would save a lot of
headaches.

But I also did just think of this idea, and haven't implemented anything
(nor do I have immediate plans to). So it might be half-baked. But I
thought I'd toss it out there and see if any body has thoughts, or feels
strongly enough to try implementing it.

-Peff

```

## brian m. carlson, 2026-10-03 01:07

Subject: Re: a "limbo" object-format state for empty repositories?
Message-ID: <asBVY1WniGUo6bQS@fruit.crustytoothpaste.net>
In-Reply-To: <20261002224400.GA834158@coredump.intra.peff.net>

```
On 2026-10-02 at 22:44:00, Jeff King wrote:
> It would be nice if the empty repository could adapt to the object
> format used by its first push. Then everything would just work from the
> user's perspective, no matter what they push.

I agree that would be nice.

> So what I'm suggesting instead is that the server be allowed to
> advertise a limbo state: it has no object format yet. And then client
> can recognize object-format=limbo, and send back "I'm a <sha1|sha256>
> repo, so that's what I'm sending you" in its capabilities response.  And
> then the server receives that and shifts its local object-format to
> match.
> 
> There are some tricky bits on the server side (e.g., you'd want to flip
> the value atomically so that if you get two simultaneous mismatched
> pushes, one of them gets rejected). But I can't think of any reason that
> it couldn't conceptually work, and I feel like it would save a lot of
> headaches.
> 
> But I also did just think of this idea, and haven't implemented anything
> (nor do I have immediate plans to). So it might be half-baked. But I
> thought I'd toss it out there and see if any body has thoughts, or feels
> strongly enough to try implementing it.

That is definitely something that could be added, but it's also
incompatible with every existing implementation.  Specifically using the
`object-format=limbo` approach means that no existing client from 2.29
on will work with the repository since `limbo` is not a valid hash
algorithm.

There is some support for multiple `object-format` directives, but I
don't know how well it works and I seem to remember that we had some
sort of crasher bug in the past.  That would be the best possible way to
advertise that, though, if older versions support it.

There are also going to be some policy decisions, for instance.  Some
organizations will not want to allow one algorithm or the other, so
Git will need some way to allow that behaviour to be expressed.  Or more
likely, Git needs some way to allow the fact that it's in versatile
mode to be expressed and that it's safe to rewrite the config on initial
write into the repository (which, to be clear, need not be a push; it
could also be a commit or add).

All that being said, it's not impossible, but it's also not easy.
-- 
brian m. carlson (they/them)
Toronto, Ontario, CA

```

## Jeff King, 2026-10-03 01:25

Subject: Re: a "limbo" object-format state for empty repositories?
Message-ID: <20261003012512.GA1324483@coredump.intra.peff.net>
In-Reply-To: <asBVY1WniGUo6bQS@fruit.crustytoothpaste.net>

```
On Sat, Oct 03, 2026 at 01:07:48AM +0000, brian m. carlson wrote:

> > But I also did just think of this idea, and haven't implemented anything
> > (nor do I have immediate plans to). So it might be half-baked. But I
> > thought I'd toss it out there and see if any body has thoughts, or feels
> > strongly enough to try implementing it.
> 
> That is definitely something that could be added, but it's also
> incompatible with every existing implementation.  Specifically using the
> `object-format=limbo` approach means that no existing client from 2.29
> on will work with the repository since `limbo` is not a valid hash
> algorithm.

Yeah, that is a problem. It breaks older clients (that are at least new
enough to understand object-format=) worse than a mismatched format
does. I was thinking we could solve that with a new capability, let's
call it "magic-limbo" for a moment. Older versions would ignore it.

But then what do we put in the object-format= field? We have to put
_something_ valid, as even if we put nothing that is an implicit choice
of sha1.

So I think the best we can do is advertise magic-limbo, and then new
limbo-aware clients can always do the right thing. Clients which are new
enough to understand object-format but don't understand limbo will use
the server's object-format unconditionally. So the choice there does
still matter. But if we don't switch to sha256-by-default until
magic-limbo is implemented, then anybody who has a local sha256 repo got
there intentionally, and presumably knows enough to configure the server
side to match. So the sensible protocol advertisement for a limbo repo
is "magic-limbo" plus "object-format=sha1".

> There is some support for multiple `object-format` directives, but I
> don't know how well it works and I seem to remember that we had some
> sort of crasher bug in the past.  That would be the best possible way to
> advertise that, though, if older versions support it.

Yeah, I thought about emitting multiple but it seems like that
introduces other weird corner cases. I think we really need a new
capability so that new versions and use it and old ones will ignore it.

> There are also going to be some policy decisions, for instance.  Some
> organizations will not want to allow one algorithm or the other, so
> Git will need some way to allow that behaviour to be expressed.  Or more
> likely, Git needs some way to allow the fact that it's in versatile
> mode to be expressed and that it's safe to rewrite the config on initial
> write into the repository (which, to be clear, need not be a push; it
> could also be a commit or add).

Those parts seem outside of the scope of Git, or at least its protocol.
But yeah, I'd expect a forge like GitHub to let you say "do not allow
the creation of sha1 repos in this account/org", and the object-format
selector for a new repo (at the forge UI) should be a tri-state: sha1,
sha256, or limbo. How that translates into Git commands is TBD: whether
via config, or more likely, that you have to select the limbo state
explicitly with a command-line option to git-init.

-Peff

```

## Junio C Hamano, 2026-10-03 01:31

Subject: Re: a "limbo" object-format state for empty repositories?
Message-ID: <xmqq33unvabf.fsf@gitster.g>
In-Reply-To: <asBVY1WniGUo6bQS@fruit.crustytoothpaste.net>

```
"brian m. carlson" <sandals@crustytoothpaste.net> writes:

> There is some support for multiple `object-format` directives, but I
> don't know how well it works and I seem to remember that we had some
> sort of crasher bug in the past.  That would be the best possible way to
> advertise that, though, if older versions support it.

Oh, bad.  Telling the other sides "I can accept this and that hash
algorithm" with multiple capability advertisement is so obviously
the right thing to do at the conceptual level.  It would have been
very nice if it worked.


```

## brian m. carlson, 2026-10-03 14:22

Subject: Re: a "limbo" object-format state for empty repositories?
Message-ID: <asEPp6Bg3xDpA4e1@fruit.crustytoothpaste.net>
In-Reply-To: <20261003012512.GA1324483@coredump.intra.peff.net>

```
On 2026-10-03 at 01:25:12, Jeff King wrote:
> Yeah, that is a problem. It breaks older clients (that are at least new
> enough to understand object-format=) worse than a mismatched format
> does. I was thinking we could solve that with a new capability, let's
> call it "magic-limbo" for a moment. Older versions would ignore it.
> 
> But then what do we put in the object-format= field? We have to put
> _something_ valid, as even if we put nothing that is an implicit choice
> of sha1.
> 
> So I think the best we can do is advertise magic-limbo, and then new
> limbo-aware clients can always do the right thing. Clients which are new
> enough to understand object-format but don't understand limbo will use
> the server's object-format unconditionally. So the choice there does
> still matter. But if we don't switch to sha256-by-default until
> magic-limbo is implemented, then anybody who has a local sha256 repo got
> there intentionally, and presumably knows enough to configure the server
> side to match. So the sensible protocol advertisement for a limbo repo
> is "magic-limbo" plus "object-format=sha1".

We need to declare the other object format as well because we need to
know that the server specifically supports SHA-256.  If we add a third
hash algorithm, then maybe SHA-256 is unacceptable for that reason.  So
maybe `alt-object-format=sha256`.  We do definitely need to be sure that
multiple options are accepted, though.

As I say below, we probably need to initialize with some hash algorithm
at first, so we could also have `object-format=sha256` and
`alt-object-format=sha1`.

You hint at delaying SHA-256-by-default until this is implemented, but I
don't think that's a good idea.  I agree this would be a nice feature to
implement, but I have no intention of implementing it and you said you
didn't, either, so unless someone decides that they are going to
implement it imminently, I don't think we should hold up Git 3.0 or the
default algorithm change to then.  As I mentioned, Git is really behind
the times on moving away from SHA-1 and we need our users to choose
sensible defaults as soon as possible.  Git 3.0 moving to SHA-256 by
default was announced in 2024 and given that I managed to write a
functional interoperability implementation in that time, there has been
plenty of time to say something and implement a solution.

> Yeah, I thought about emitting multiple but it seems like that
> introduces other weird corner cases. I think we really need a new
> capability so that new versions and use it and old ones will ignore it.

The bug I mentioned was apparently not a crasher but an infinite loop:
aa962fef27 ("v0 protocol: fix infinite loop when parsing multi-valued
capabilities", 2023-04-14).  However, it was fixed in 2.41, before
SHA-256 became stable in 2.44.  We could therefore implement it that way
if we're willing to abandon versions of Git that only have experimental
support for SHA-256.

> Those parts seem outside of the scope of Git, or at least its protocol.
> But yeah, I'd expect a forge like GitHub to let you say "do not allow
> the creation of sha1 repos in this account/org", and the object-format
> selector for a new repo (at the forge UI) should be a tri-state: sha1,
> sha256, or limbo. How that translates into Git commands is TBD: whether
> via config, or more likely, that you have to select the limbo state
> explicitly with a command-line option to git-init.

I disagree that they're outside the scope of Git, but I do agree that we
should add support for this either in the config or via a command-line
option.  I think config would be better here because we also have to
deal with the fact that someone might use commands other than push to
write into the repository (on a forge, that might be the API) and we
need to specify _some_ hash algorithm for that case.
-- 
brian m. carlson (they/them)
Toronto, Ontario, CA

```

## Jeff King, 2026-10-05 03:30

Subject: Re: a "limbo" object-format state for empty repositories?
Message-ID: <20261005033023.GA10271@coredump.intra.peff.net>
In-Reply-To: <asEPp6Bg3xDpA4e1@fruit.crustytoothpaste.net>

```
On Sat, Oct 03, 2026 at 02:22:32PM +0000, brian m. carlson wrote:

> > So I think the best we can do is advertise magic-limbo, and then new
> > limbo-aware clients can always do the right thing. Clients which are new
> > enough to understand object-format but don't understand limbo will use
> > the server's object-format unconditionally. So the choice there does
> > still matter. But if we don't switch to sha256-by-default until
> > magic-limbo is implemented, then anybody who has a local sha256 repo got
> > there intentionally, and presumably knows enough to configure the server
> > side to match. So the sensible protocol advertisement for a limbo repo
> > is "magic-limbo" plus "object-format=sha1".
> 
> We need to declare the other object format as well because we need to
> know that the server specifically supports SHA-256.  If we add a third
> hash algorithm, then maybe SHA-256 is unacceptable for that reason.  So
> maybe `alt-object-format=sha256`.  We do definitely need to be sure that
> multiple options are accepted, though.

Right, that makes sense. And the presence of alt-object-format would
replace the need for a separate magic-limbo at all.

> As I say below, we probably need to initialize with some hash algorithm
> at first, so we could also have `object-format=sha256` and
> `alt-object-format=sha1`.

Yeah, that makes sense.

> You hint at delaying SHA-256-by-default until this is implemented, but I
> don't think that's a good idea.

I wasn't proposing a delay. There's at least another whole release cycle
before 3.0, and this feature doesn't seem all that big. So it seemed
like something that could be implemented in that time-frame. I may or may
not work on it at some point; I just don't want to preclude anybody
(like Scott) who is interested and wanted to run with it.

> > Those parts seem outside of the scope of Git, or at least its protocol.
> > But yeah, I'd expect a forge like GitHub to let you say "do not allow
> > the creation of sha1 repos in this account/org", and the object-format
> > selector for a new repo (at the forge UI) should be a tri-state: sha1,
> > sha256, or limbo. How that translates into Git commands is TBD: whether
> > via config, or more likely, that you have to select the limbo state
> > explicitly with a command-line option to git-init.
> 
> I disagree that they're outside the scope of Git, but I do agree that we
> should add support for this either in the config or via a command-line
> option.  I think config would be better here because we also have to
> deal with the fact that someone might use commands other than push to
> write into the repository (on a forge, that might be the API) and we
> need to specify _some_ hash algorithm for that case.

Sorry, I just meant that policy decisions like "this account should not
be able to create sha1 repos" was outside of Git. We definitely need
some config flag to mark the limbo state (since it's set by "git init"
and ultimately respected by receive-pack and elsewhere). I would say
that any limbo-state feature should _not_ be on by default, but could be
a useful building block for forges that want to reduce friction. There'd
perhaps be some forge-specific work to do on top, too.

-Peff

```
