git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] send-pack: avoid sending the whole tree when pushing from a shallow clone

From
Elijah Newren <newren@gmail.com>
Date
Aug 25, 2026, 05:00 UTC
Message-ID
<CABPp-BHwa7QM=XDuO=9xqm-OL8dn8uGf1=rv+sgBRQ9hHKMFuQ@mail.gmail.com>
In-Reply-To
<aovW5bxu1F8jYKYl@pks.im>
On Sun, Aug 23, 2026 at 10:30 PM Patrick Steinhardt <ps@pks.im> wrote:
>
[...]
Show 7 quoted lines
> TIL, thanks. I don't think I was even aware of "push.negotiate", and I
> mostly went by the folklore of "just clone with --depth=2" that I saw
> repeated on many sites.
>
> But this and all of your other answers make me lean strongly into the
> direction that the fix is at the wrong level, and the proper fix really
> is to enable "push.negotiate" by default.
I don't think that fixes the problem, though:
  a) Users can do a shallow clone of a specific branch for a specific
pull-request/merge-request.  Then the pull-request/merge-request is
rebased, and sensitive data removed due to a leaked secret.  The
shallow graft is no longer common.  Pushing from the shallow clone
should fail, but it shouldn't have to send several gigabytes of data
in order to get the failure message.
  b) (Very similar to a) Users can do a shallow clone of one repo (a
local repository cache?) and then push to another; the shallow graft
thus may not be common.  An error is expected, but sending gigabytes
of data to get the error isn't.
  c) Users set push.negotiate=false explicitly.  In my opinion, they
shouldn't get this bug just for opting out of that kind-of-related
feature.
  d) push.negotiate=true silently fails for some setups
I think case (d) is particularly interesting: For push.negotiate to
work, fetch v2 must be working.  For http, that's not a big deal.
When using ssh, it requires the client to send GIT_PROTOCOL=version=2
environment variable and for the server to accept it:
  * Server side:
    * Some self-hosting forges may not automatically support receiving
the environment variable.  My searches suggest BitBucket always uses
v0 for ssh, and GitLab depends on the installation method -- either
the Linux package or self-compile installs requiring manual action
(only Helm and the all-in-one Docker image are preconfigured)
    * Some corporate setups may specifically want to disallow sending
any environment variables over ssh (perhaps through an "upstream stock
configuration only" policy?)
  * Client side:
    * git only requests v2 when it decides the client is OpenSSH (I
think that maps to the command being named ssh/ssh.exe, or an
auto-probe succeeds)
    * plink / putty / tortoiseplink appear to not allow sending this
environment variable, so many Windows users may be cut out
    * Some corporate setups might restrict sending environment
variables over ssh on the client side as well

When it's not supported, it falls back to v0 with a simple warning, does no negotiation, and runs into the old bug.

So, while I support the idea of moving towards push.negotiate=true or even adding push.negotiate=shallow, because they would provide other benefits, I don't think they fix the problem at hand and thus believe that this patch is still important.

[...]
Show 5 quoted lines
> > Since we've got another place where commit --amend can serve as a
> > foot-gun that I've long meant to fix up, I'll submit a separate series
> > that'll make it throw errors for both cases.
>
> That makes sense.

Turns out there's a bunch of additional stuff on the shallow side, so I think I'm going to split it into two series; a single patch for rebase/revert/am, and five or so patches for shallow graft handling across a variety of commands.

Show 10 quoted lines
> That's all fair, but it does dramatically help in the case of shallow
> clones. And the number of times I've seen this question come up hints
> that this is a very common scenario.
>
> We could be clever about it: if "push.negotiate" is very likely to help
> in shallow clones but mostly just adds latency in full clones, then why
> don't we introduce a new "push.negotiate=shallow" option that enables
> this feature automatically for shallow clones and make it the default?
> That to me sounds like a low-hanging fruit, and I would prefer such a
> fix compared to introducing new logic.

I kind of like the idea of somehow making push.negotiate default on for big repos in general (not just shallow), but while push.negotiate has lots of other benefits and has the side effect of solving most cases of this problem for some users, it falls short of actually fully solving the problem. This patch, or something like it, is still needed.

Previous: Patrick SteinhardtNext: Derrick Stolee
Message 6 of 18 in “send-pack: avoid sending the whole tree when pushing from a shallow clone”
  1. send-pack: avoid sending the whole tree when pushing from a shallow cloneElijah Newren via GitGitGadget, Aug 21, 2026
  2. Patrick SteinhardtAug 21, 2026
  3. Elijah NewrenAug 21, 2026
  4. Elijah NewrenAug 21, 2026
  5. Patrick SteinhardtAug 24, 2026
  6. Elijah NewrenAug 25, 2026
  7. Derrick StoleeSep 2, 2026
  8. Elijah NewrenSep 2, 2026
  9. send-pack: avoid sending the whole tree when pushing from a shallow cloneElijah Newren via GitGitGadget, Aug 25, 2026
  10. Derrick StoleeSep 2, 2026
  11. Elijah NewrenSep 3, 2026
  12. 0/6 send-pack: avoid sending the whole tree when pushing from a shallow cloneElijah Newren via GitGitGadget, Sep 6, 2026
  13. 1/6 unpack-objects: distinguish missing objects from type mismatchesElijah Newren via GitGitGadget, Sep 6, 2026
  14. 2/6 receive-pack: avoid repeating connectivity errorsElijah Newren via GitGitGadget, Sep 6, 2026
  15. 3/6 shallow: reject missing boundaries without disconnectingElijah Newren via GitGitGadget, Sep 6, 2026
  16. 4/6 send-pack: optionally omit shallow boundariesElijah Newren via GitGitGadget, Sep 6, 2026
  17. 5/6 send-pack: default to excluding shallow boundariesElijah Newren via GitGitGadget, Sep 6, 2026
  18. 6/6 send-pack: advise splitting incomplete shallow pushesElijah Newren via GitGitGadget, Sep 6, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.