threads / bug / 64161

[Bug] git fetch --dry-run --filter makes changes to .git/config

Subject: [Bug] git fetch --dry-run --filter makes changes to .git/config

## tl;dr

10 messages between Sep 17, 2025 and Sep 19, 2025.

replies: 9people: 5as markdown or json

Kevin Puetz· Sep 17, 2025, 14:44 UTC · lore
What did you do before the bug happened? (Steps to reproduce your issue)
    `git fetch origin --refetch --dry-run {commit} --depth=1 --filter=tree:0 --no-auto-gc`
What did you expect to happen? (Expected behavior)
    I expected it to fetch just the one commit object (no blobs, no trees, no history),
    as a means of checking whether that commit is actually known to the remote.
What happened instead? (Actual behavior)
    the .git/config file was modified, adding
    [remote "origin"]
        promisor = true
        partialclonefilter = tree:0
What's different between what you expected and what actually happened?
    I did not expect any changes to the local clone (due to the use of --dry-run)
Anything else you want to add:
    Context is https://github.com/conan-io/conan/issues/18949
    trying to avoid a full-re-download in the process of checking
    whether the HEAD commit hash exists in a remote.
    The command was expected to either be a no-op success, or fail
    > fatal: remote error: upload-pack: not our ref {commit}"
[System Info]
git version:
git version 2.51.0.windows.1
cpu: x86_64
built from commit: 4d21a77b98af5cf479d8b6f863c2aa94257cd4e1
sizeof-long: 4
sizeof-size_t: 8
shell-path: D:/git-sdk-64-build-installers/usr/bin/sh
feature: fsmonitor--daemon
libcurl: 8.15.0
OpenSSL: OpenSSL 3.2.4 11 Feb 2025
zlib: 1.3.1
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-format: files
default-hash: sha1
uname: Windows 10.0 26100
compiler info: gnuc: 15.2
libc info: no libc information available
$SHELL (typically, interactive shell): C:\Program Files\Git\usr\bin\bash.exe
[Enabled Hooks]
Public
brian m. carlson· Sep 17, 2025, 21:21 UTC · re: Kevin Puetz · lore

Re: [Bug] git fetch --dry-run --filter makes changes to .git/config

On 2025-09-17 at 14:44:00, Kevin Puetz wrote:
Show 16 quoted lines
> What did you do before the bug happened? (Steps to reproduce your issue)
> 
>     `git fetch origin --refetch --dry-run {commit} --depth=1 --filter=tree:0 --no-auto-gc`
> 
> What did you expect to happen? (Expected behavior)
> 
>     I expected it to fetch just the one commit object (no blobs, no trees, no history),
>     as a means of checking whether that commit is actually known to the remote.
> 
> What happened instead? (Actual behavior)
> 
>     the .git/config file was modified, adding
> 
>     [remote "origin"]
>         promisor = true
>         partialclonefilter = tree:0

I will note that if this command actually downloads any data, this is required. That's because your repository is incomplete: you want to download exactly one commit and without marking the promisor remote, you will lack the ability to acquire trees or blobs and your repository will then be corrupt.

> What's different between what you expected and what actually happened?
> 
>     I did not expect any changes to the local clone (due to the use of --dry-run)

I agree --dry-run should not change your repository. However, I would also say that it should not contact the server, either, so it may not do what you want. If that's not what it was intended to do, perhaps someone can clarify the documentation as to its functionality.

Show 8 quoted lines
> Anything else you want to add:
> 
>     Context is https://github.com/conan-io/conan/issues/18949
> 
> 
>     trying to avoid a full-re-download in the process of checking
>     whether the HEAD commit hash exists in a remote.
>     The command was expected to either be a no-op success, or fail

I don't think that the command you've provided is a good or efficient way of doing what you want, but I'm also not sure that there's a good or efficient way to do what you want using command line Git (you might need to write a small portion of the protocol, for instance).

-- 
brian m. carlson (they/them)
Toronto, Ontario, CA
Kevin Puetz· Sep 17, 2025, 23:23 UTC · re: brian m. carlson · lore

RE: [Bug] git fetch --dry-run --filter makes changes to .git/config

Public On 2025-09-17 at 14:44:00, Kevin Puetz wrote:

Show 5 quoted lines
> >     the .git/config file was modified, adding
> >
> >     [remote "origin"]
> >         promisor = true
> >         partialclonefilter = tree:0
Show 5 quoted lines
> I will note that if this command actually downloads any data, this is
> required.  That's because your repository is incomplete: you want to
> download exactly one commit and without marking the promisor remote, you
> will lack the ability to acquire trees or blobs and your repository will
> then be corrupt.

I agree - had I actually stored the fetch, this would be correct behavior. It was surprising/wrong *only* because --dry-run threw away the resulting objects

> > I did not expect any changes to the local clone (due to the use of --dry-run)
> I agree --dry-run should not change your repository.  However, I would
> also say that it should not contact the server, either

Hmm. I'm not sure I agree there. Usually --dry-run is intended as a way to find out of the command is going to give any errors, and that's the sense in which conan is using it. I could see it not actually downloading the pack from the server, but I'd of expect it to at least negotiate which refs are needed (and thus fail if the server doesn't have them). Which it currently does.

But I wasn't expecting it to make any lasting changes to the local clone, So that seemed like a bug I ought to report (though it's admittedly quite a corner-case)

Show 9 quoted lines
> > Context is https://github.com/conan-io/conan/issues/18949
> > trying to avoid a full-re-download in the process of checking
> > whether the HEAD commit hash exists in a remote.
> > The command was expected to either be a no-op success, or fail
>
> I don't think that the command you've provided is a good or efficient
> way of doing what you want, but I'm also not sure that there's a good or
> efficient way to do what you want using command line Git (you might need
> to write a small portion of the protocol, for instance).

I certainly agree that the `fetch --refetch` conan 2.0 is currently doing is a very inefficient way to check if a remote has a certain commit or not - which is why I was experimenting with blobless/treeless to minimize the useless transfer.

Today I also found `git fetch $REMOTE --negotiate-only --negotiation-tip=$COMMIT`. That supposedly (and seemingly in practice) replies with the list of ancestors, we have in common, i.e. it will print the same $COMMIT if the server has it, or some list of ancestor(s) we share if it does not. That seems like a much more sensible command to check whether the remote has a commit, so I'd also appreciate any feedback if I'm there's something wrong with using it this way.

I did find one odd quirk. When the remote and the requested commit are unrelated e.g. I'm taking to the wrong remote, or have done `git checkout --orphan`), I get

$ git fetch https://github.com/git/git --negotiate-only --negotiation-tip=$COMMIT fatal: expected 'acknowledgments', received 'packfile'

This still works for conan's purpose (exiting with an error means it didn't print a matching commit hash), but I expected something more like the "fatal: remote error: upload-pack: not our ref: ..." error that you get from git fetch {remote} --refetch $COMMIT. Of course, unexpectly sending a packfile could be a problem with github's server implementation, rather than the git client.

-- brian m. carlson (they/them) Toronto, Ontario, CA

Jeff King· Sep 18, 2025, 19:20 UTC · re: Kevin Puetz · lore

Re: [Bug] git fetch --dry-run --filter makes changes to .git/config

On Wed, Sep 17, 2025 at 11:23:21PM +0000, Kevin Puetz wrote:
Show 16 quoted lines
> On 2025-09-17 at 14:44:00, Kevin Puetz wrote:
> 
> > >     the .git/config file was modified, adding
> > >
> > >     [remote "origin"]
> > >         promisor = true
> > >         partialclonefilter = tree:0
> 
> > I will note that if this command actually downloads any data, this is
> > required.  That's because your repository is incomplete: you want to
> > download exactly one commit and without marking the promisor remote, you
> > will lack the ability to acquire trees or blobs and your repository will
> > then be corrupt.
> 
> I agree - had I actually stored the fetch, this would be correct behavior.
> It was surprising/wrong *only* because --dry-run threw away the resulting objects

Unfortunately it does not throw them away. They're still in your object database! The dry-run mode of git-fetch is not very dry. It just skips the final ref update.

It would probably be better if it established a separate tmp-objdir area (like we do for pushes before we commit to storing them), fetched the objects into that, and then threw away the result. That technique did not exist back when "fetch --dry-run" was added, but it probably wouldn't be too hard to do now.

Show 21 quoted lines
> I certainly agree that the `fetch --refetch` conan 2.0 is currently doing is a very inefficient
> way to check if a remote has a certain commit or not - which is why I was
> experimenting with blobless/treeless to minimize the useless transfer.
> 
> Today I also found `git fetch $REMOTE --negotiate-only --negotiation-tip=$COMMIT`.
> That supposedly (and seemingly in practice) replies with the list of ancestors,
> we have in common, i.e. it will print the same $COMMIT if the server has it,
> or some list of ancestor(s) we share if it does not. That seems like a much more
> sensible command to check whether the remote has a commit,
> so I'd also appreciate any feedback if I'm there's something wrong with using it this way.
> 
> I did find one odd quirk. When the remote and the requested commit are unrelated
> e.g. I'm taking to the wrong remote, or have done `git checkout --orphan`), I get
> 
> $ git fetch https://github.com/git/git --negotiate-only --negotiation-tip=$COMMIT
> fatal: expected 'acknowledgments', received 'packfile'
> 
> This still works for conan's purpose (exiting with an error means it didn't print a matching commit hash),
> but I expected something more like the "fatal: remote error: upload-pack: not our ref: ..."
> error that you get from git fetch {remote} --refetch $COMMIT. Of course, unexpectly sending a packfile
> could be a problem with github's server implementation, rather than the git client.

I had never used --negotiate-only before, and did a simple test which ended up with the exact same problem. I agree it's probably a bug, but it's present in git.git itself (my fetch was to a local test repo).

I'm not sure if the bug is in the server or client, though. If I understand correctly, the server does not know anything about this "negotiate-only" mode, but is just responding to the client. The client is supposed to say "done" to tell the server that it is not sending any more "have" negotiation, at which point the server sends the packfile. But in this case the packfile comes anyway. Running with GIT_TRACE_PACKET in the environment shows the client making an extra request with no "have" lines at all, which the server then takes as an indication it can send the packfile.

So I think there is at least one client bug, which is making that extra request. There might _also_ be a server bug, because it is sending the packfile without a "done" line, even though it was told the client wants the wait-for-done option (and the client does not even send a "want" line at all, so what does it think it is sending?).

I can't comment beyond that on the wisdom of using --negotiate-only.

One other option is to use the "object-info" protocol extension which I think would do exactly what you want. But the server has to enable it explicitly. And I'm not sure where client support is (I think there were patches for a "remote-object-info" directive in git-cat-file a few months ago, but it looks like it is in limbo now?). So probably a non-starter.

My other instinct would be to try to fetch the single object, which is what you're trying to do with the --dry-run invocation. I wondered if we might find some wisdom in how partial clones do one-off fetches to lazy-load objects we are missing. It looks like they do (this is from promisor-remote.c's fetch_objects() function):

  git -c fetch.negotiationAlgorithm=noop fetch --no-tags \
    --no-write-fetch-head --recurse-submodules=no --filter=blob:none

which is not so far off of what you're doing (and actually I wonder if it even does the right thing when doing a fill-in fetch of a non-blob; shouldn't we be using the same filter that we originally cloned with? And possibly --depth=1?).

But I don't think it helps your problem. It still writes the promisor config (which, in a real partial clone, would already exist anyway).

We could sneak around the odb issue by setting up our own tmp-objdir, like:

  mkdir tmp-objdir
  GIT_ALTERNATE_OBJECT_DIRECTORIES=$PWD/.git/objects \
  GIT_OBJECT_DIRECTORY=$PWD/tmp-objdir \
  git fetch --dry-run ...

but that would still modify the config. So I think you'd really have to set up your own fake little repo, like:

  mkdir fake-repo
  (
	cd fake-repo
	# this alternate might even be optional; do we even care about
	# seeing our own objects here, since we are just trying to grab
	# the one from the server? I guess if we have the object in
	# question it prevents the server from sending it to us.
	GIT_ALTERNATE_OBJECT_DIRECTORIES=$PWD/../.git/objects \
	git fetch --dry-run ...
  )
  rm -rf fake-repo

I dunno. That is pretty ugly, but I couldn't come up with anything better.

-Peff
Junio C Hamano· Sep 18, 2025, 20:28 UTC · re: Jeff King · lore

Re: [Bug] git fetch --dry-run --filter makes changes to .git/config

Jeff King <peff@peff.net> writes:
Show 5 quoted lines
> It would probably be better if it established a separate tmp-objdir area
> (like we do for pushes before we commit to storing them), fetched the
> objects into that, and then threw away the result. That technique did
> not exist back when "fetch --dry-run" was added, but it probably
> wouldn't be too hard to do now.

It is true that the quarantine mechanism did not exist. But I am not sure if a true dryness is actually better. We do verify that the incoming objects thrown at us by the other side are healthy, so the only difference is that our object database will have extra unreachable objects that are known to be healthy between the time you run a dry fetch and the time you then run a real one. And these extra objects that are healthy will help your real fetch go faster if the dry fetch and real fetch are run back to back thanks to "do we have all the necessary objects already, just that they may not be connected to the refs yet?" check.

So it may not be hard with the building blocks, but I am not sure if it is a good idea to do so in the first place.

Thanks.
Jeff King· Sep 18, 2025, 20:39 UTC · re: Junio C Hamano · lore

Re: [Bug] git fetch --dry-run --filter makes changes to .git/config

On Thu, Sep 18, 2025 at 01:28:28PM -0700, Junio C Hamano wrote:
Show 21 quoted lines
> Jeff King <peff@peff.net> writes:
> 
> > It would probably be better if it established a separate tmp-objdir area
> > (like we do for pushes before we commit to storing them), fetched the
> > objects into that, and then threw away the result. That technique did
> > not exist back when "fetch --dry-run" was added, but it probably
> > wouldn't be too hard to do now.
> 
> It is true that the quarantine mechanism did not exist.  But I am
> not sure if a true dryness is actually better.  We do verify that
> the incoming objects thrown at us by the other side are healthy, so
> the only difference is that our object database will have extra
> unreachable objects that are known to be healthy between the time
> you run a dry fetch and the time you then run a real one.  And these
> extra objects that are healthy will help your real fetch go faster
> if the dry fetch and real fetch are run back to back thanks to "do
> we have all the necessary objects already, just that they may not be
> connected to the refs yet?" check.
> 
> So it may not be hard with the building blocks, but I am not sure if
> it is a good idea to do so in the first place.

Yeah, I see how the current behavior could be useful. In this particular case the objects _aren't_ really healthy. They are promisor cruft that violates all the usual everything_local() rules (but at least we set up the config to mark them as such). But I take your point that we probably shouldn't change anything here.

You _can_ do the tmp-objdir thing yourself with GIT_OBJECT_DIRECTORY, as I showed earlier. It is unfortunate that doing so updates the repo config, though. That may show a mismatch in how the promisor information is stored (it is really a property of the packfile in the object directory, but the config mechanism stores it in the main repo). But it is probably not worth trying to revisit at this point. It is only when you start to play weird games like "this repo's object directory is not $GIT_DIR/objects" that you run into these distinctions.

-Peff
Junio C Hamano· Sep 18, 2025, 20:46 UTC · re: Jeff King · lore

Re: [Bug] git fetch --dry-run --filter makes changes to .git/config

Jeff King <peff@peff.net> writes:
Show 7 quoted lines
> ... It is unfortunate that doing so updates the repo
> config, though. That may show a mismatch in how the promisor information
> is stored (it is really a property of the packfile in the object
> directory, but the config mechanism stores it in the main repo). But it
> is probably not worth trying to revisit at this point. It is only when
> you start to play weird games like "this repo's object directory is not
> $GIT_DIR/objects" that you run into these distinctions.

Hmph, but watching from the sidelines Patrick's topics that revolve around (re)defining the boundary and relationship among repository, object store, and on-disk packfiles with a more clearly defined abstractions like object_source, I am hoping that we somehow can find a good place to move this information out of the per-repo configuration to somewhere close to individual packs. I dunno.

Kevin Puetz· Sep 18, 2025, 21:55 UTC · re: Jeff King · lore

RE: [Bug] git fetch --dry-run --filter makes changes to .git/config

> > I did find one odd quirk. When the remote and the requested commit are unrelated
> > e.g. I'm taking to the wrong remote, or have done `git checkout --orphan`), I get
> >
> > $ git fetch https://github.com/git/git
 --negotiate-only --negotiation-tip=$COMMIT
Show 20 quoted lines
> > fatal: expected 'acknowledgments', received 'packfile'
> >
> > This still works for conan's purpose (exiting with an error means it didn't print a matching commit hash),
> > but I expected something more like the "fatal: remote error: upload-pack: not our ref: ..."
> > error that you get from git fetch {remote} --refetch $COMMIT. Of course, unexpectly sending a packfile
> > could be a problem with github's server implementation, rather than the git client.
>
> I had never used --negotiate-only before, and did a simple test which
> ended up with the exact same problem. I agree it's probably a bug, but
> it's present in git.git itself (my fetch was to a local test repo).
>
> I'm not sure if the bug is in the server or client, though. If I
> understand correctly, the server does not know anything about this
> "negotiate-only" mode, but is just responding to the client. The client
> is supposed to say "done" to tell the server that it is not sending any
> more "have" negotiation, at which point the server sends the packfile.
> But in this case the packfile comes anyway. Running with GIT_TRACE_PACKET
> in the environment shows the client making an extra request with no
> "have" lines at all, which the server then takes as an indication it can
> send the packfile.

Yep. In the cases where things work as expected, the client sends various `have` lines for ancestors of the negotiation-tips, and then the server sends "ACK ..." with the one it knows.

When they are unrelated (none of the have lines are comits known to the remote), it replies with NAK (which is sensible enough). But then the client doesn't just error out after the NAK it keeps going. I guess because if this really was a fetch, rather than negotiate-only, and we have nothing in common with the server, we'd still need to fetch the wanted ref (and receive everything). But it *is* --negotiate-only, so we don't actually want anything either. Which leads to this weird empty request-for-nothing. Seems like the client Really should have just exited early after the NAK, given that it doesn't want anything.

Show 5 quoted lines
> So I think there is at least one client bug, which is making that extra
> request. There might _also_ be a server bug, because it is sending the
> packfile without a "done" line, even though it was told the client wants
> the wait-for-done option (and the client does not even send a "want"
> line at all, so what does it think it is sending?).
Looking closer, I think the server bug is at
    https://github.com/git/git/blob/ca2559c1d630eb4f04cdee2328aaf1c768907a9e/upload-pack.c#L1805-L1813

There's an early exit to UPLOAD_DONE (without sending any packfile) if you didn't want anything, But it's skipped over if you use wait-for-done, because that's the negotiate-only case, which still wants the acknowledgements. But then (during the weird empty client request) seen_haves isn't true either, So it skips the UPLOAD_SEND_ACKS case too. And it ends up just falling through into the final else { state = UPLOAD_SEND_PACK; }

I think here the client was expecting the server to go into UPLOAD_SEND_ACKS, and just send an empty set of acknowledgements, which seems legal. https://git-scm.com/docs/gitprotocol-v2 says

- If the server has found a suitable cut point and has decided to send a "ready" line,
  then the server can decide to (as an optimization) omit any "ACK" lines it would have sent

So I think the server could/should just reply with no "ACK" lines and "ready" (i.e. you don't want anything, but sure, I can send you an empty pack file). But it's definitely a corner case. And right now it wouldn't work, because https://github.com/git/git/blob/master/upload-pack.c#L1712-L1713

would send NAK instead (which also seems legal, depending on how one interprets
- The server will respond with "NAK" if none of the object ids sent as have lines were common.
I think the client could deal with either "ready" or "NAK", it's just the empty pack it's not expecting.
Public
rsbecker@nexbridge.com· Sep 18, 2025, 22:21 UTC · re: Kevin Puetz · lore

RE: [Bug] git fetch --dry-run --filter makes changes to .git/config

On September 18, 2025 5:55 PM, Kevin Puetz wrote:
Show 83 quoted lines
>> > I did find one odd quirk. When the remote and the requested commit
>> > are unrelated e.g. I'm taking to the wrong remote, or have done `git
>> > checkout --orphan`), I get
>> >
>> > $ git fetch https://github.com/git/git
>
> --negotiate-only --negotiation-tip=$COMMIT
>> > fatal: expected 'acknowledgments', received 'packfile'
>> >
>> > This still works for conan's purpose (exiting with an error means it
>> > didn't print a matching commit hash), but I expected something more like the
>"fatal: remote error: upload-pack: not our ref: ..."
>> > error that you get from git fetch {remote} --refetch $COMMIT. Of
>> > course, unexpectly sending a packfile could be a problem with github's server
>implementation, rather than the git client.
>>
>> I had never used --negotiate-only before, and did a simple test which
>> ended up with the exact same problem. I agree it's probably a bug, but
>> it's present in git.git itself (my fetch was to a local test repo).
>>
>> I'm not sure if the bug is in the server or client, though. If I
>> understand correctly, the server does not know anything about this
>> "negotiate-only" mode, but is just responding to the client. The
>> client is supposed to say "done" to tell the server that it is not
>> sending any more "have" negotiation, at which point the server sends the
>packfile.
>> But in this case the packfile comes anyway. Running with
>> GIT_TRACE_PACKET in the environment shows the client making an extra
>> request with no "have" lines at all, which the server then takes as an
>> indication it can send the packfile.
>
>Yep. In the cases where things work as expected, the client sends various `have`
>lines for ancestors of the negotiation-tips, and then the server sends "ACK ..." with
>the one it knows.
>
>When they are unrelated (none of the have lines are comits known to the remote),
>it replies with NAK (which is sensible enough). But then the client doesn't just error
>out after the NAK it keeps going. I guess because if this really was a fetch, rather
>than negotiate-only, and we have nothing in common with the server, we'd still
>need to fetch the wanted ref (and receive everything).
>But it *is* --negotiate-only, so we don't actually want anything either.
>Which leads to this weird empty request-for-nothing. Seems like the client Really
>should have just exited early after the NAK, given that it doesn't want anything.
>
>> So I think there is at least one client bug, which is making that
>> extra request. There might _also_ be a server bug, because it is
>> sending the packfile without a "done" line, even though it was told
>> the client wants the wait-for-done option (and the client does not even send a
>"want"
>> line at all, so what does it think it is sending?).
>
>Looking closer, I think the server bug is at
>
>https://github.com/git/git/blob/ca2559c1d630eb4f04cdee2328aaf1c768907a9e/
>upload-pack.c#L1805-L1813
>
>There's an early exit to UPLOAD_DONE (without sending any packfile) if you didn't
>want anything, But it's skipped over if you use wait-for-done, because that's the
>negotiate-only case, which still wants the acknowledgements.
>But then (during the weird empty client request) seen_haves isn't true either, So it
>skips the UPLOAD_SEND_ACKS case too. And it ends up just falling through into the
>final else { state = UPLOAD_SEND_PACK; }
>
>I think here the client was expecting the server to go into UPLOAD_SEND_ACKS, and
>just send an empty set of acknowledgements, which seems legal.
>https://git-scm.com/docs/gitprotocol-v2 says
>
>- If the server has found a suitable cut point and has decided to send a "ready" line,
>  then the server can decide to (as an optimization) omit any "ACK" lines it would
>have sent
>
>So I think the server could/should just reply with no "ACK" lines and "ready"
>(i.e. you don't want anything, but sure, I can send you an empty pack file).
>But it's definitely a corner case. And right now it wouldn't work, because
>https://github.com/git/git/blob/master/upload-pack.c#L1712-L1713
>
>would send NAK instead (which also seems legal, depending on how one interprets
>
>- The server will respond with "NAK" if none of the object ids sent as have lines
>were common.
>
>I think the client could deal with either "ready" or "NAK", it's just the empty pack it's
>not expecting.

If I might ask, and I realize this is an edge-condition, but what is the intent when the clone has been done with a --depth=1 or similar? The single commit may not be known locally but may be in the history as far as the remote is concerned. I am just curious.

--Randall
Kevin Puetz· Sep 19, 2025, 15:31 UTC · re: rsbecker@nexbridge.com · lore

RE: [Bug] git fetch --dry-run --filter makes changes to .git/config

> If I might ask, and I realize this is an edge-condition, but what is the intent when
> the clone has been done with a --depth=1 or similar? The single commit may not
> be known locally but may be in the history as far as the remote is concerned. I am
> just curious.

Definitely in scope, and likely a common scenario for conan. If you have a full clone with remote-tracking branches and such, then `git branch --remote --contains ...` is enough to think the remote has this commit. The case where it has to go online is when something like CI did a `git clone --single-branch` or `git clone ----revision=` and there's not necessarily any tracking branches.

If the remote has the commit in question, shallow or not, we'd still want conan.tools.Git.commit_in_remote to return true. And it looks like --negotiate-only should work fine for that. It looks like, in a shallow clone, the main difference is that the client only sends "have ..." lines for the commits back to the shallow boundary, and then the "0000" flush. Which is correct - it *doesn't* have the earlier parents. The server then responds with ACK or NAK as appropriate to the "have ..." it saw.

Now, that increases the odds that there are no commits in common (if the remote in question has a more-distant ancestor, below the shallow cutoff, the negotiation won't figure that out. But that doesn't cause any harm - the negotiation result is NAK (correct, we don't have anything in common), and if the client does proceed with a fetch it gets everything (which it does need, since it didn't have that early history).

So it seems fine, other than --negotiate-only perhaps triggering the same "fatal: expected 'acknowledgments', received 'packfile'" bug we were discussing for actually-unrelated histories.

Or, if we reverse the roles and make the shallow copy the remote, e.g.
 `git fetch shallow --negotiate-only --negotiation-tips=HEAD~1` (pretty weird).
we get a different error "fatal: expected 'acknowledgments', received 'shallow-info'"
But it's still the same bug - the client sends the weird empty fetch
("wait-for-done", no "have", no "want", no "done"), the server falls through into
`case UPLOAD_SEND_PACK` the same way, but now send_shallow_info writes
that before the packile.
Public

← back to recent threads