From: Jeff King Date: Tue, 03 Oct 2023 20:00:18 GMT Subject: Re: Possible to update-ref remote repository? Message-ID: <20231003200018.GB1562@coredump.intra.peff.net> In-Reply-To: On Sun, Oct 01, 2023 at 04:03:29PM -0600, Jesse Hopkins wrote: > Thanks for the reply. Would you be able to point me to some > breadcrumbs for the "required protocol messages"? I might try to > tinker in some spare time. Try "git help protocol-pack" in a recent version of Git (this used to be in Documentation/technical/ of the repository, but much of that content was moved into manpages around the v2.38 timeframe). For a local or ssh connection, I think it is as simple as: # you somehow happen to know this commit exists on the server, # and what the current value of the ref is. If you don't know the # current value, you can pull it from receive-pack's ref # advertisement (I'll leave that as an exercise for the reader). old=1234abcd... new=5678cdef... ref=refs/heads/main # we'll use a local repository here, but you can replace receive-pack # invocation below with with "ssh $host git receive-pack $repo" repo=/path/to/repo.git { # git's pkt-line format is a 4-byte header with the ascii hex size of # the packet, followed by N-4 bytes of data. Each ref update is # in its own pkt, but we have just one. cmd="$old $new $ref" printf "%04x%s" $((${#cmd} + 4)) "$cmd" # An all-zero flush packet indicates the end of the list of updates. printf "0000" # the server insists that we send a valid packfile, even if it is # empty. This is from "git help format-pack" (the section on .pack # files), though you could also generate it with "git pack-objects # --stdout nr; i++) - feed_object(&advertised->oid[i], po_in, 1); - for (i = 0; i < negotiated->nr; i++) - feed_object(&negotiated->oid[i], po_in, 1); - - while (refs) { - if (!is_null_oid(&refs->old_oid)) - feed_object(&refs->old_oid, po_in, 1); - if (!is_null_oid(&refs->new_oid)) - feed_object(&refs->new_oid, po_in, 0); - refs = refs->next; + if (!SPECIAL_EMPTY_PACK_OPTION) { + for (i = 0; i < advertised->nr; i++) + feed_object(&advertised->oid[i], po_in, 1); + for (i = 0; i < negotiated->nr; i++) + feed_object(&negotiated->oid[i], po_in, 1); + + while (refs) { + if (!is_null_oid(&refs->old_oid)) + feed_object(&refs->old_oid, po_in, 1); + if (!is_null_oid(&refs->new_oid)) + feed_object(&refs->new_oid, po_in, 0); + refs = refs->next; + } } fflush(po_in); Come to think of it, you could probably fake it by wrapping git-pack-objects with a script that throws away its input. Maybe hard to do because its a builtin (and we run it as "git pack-objects", which executes it directly in-process). -Peff