Subject: Re: How to mirror and augment a git repository

From: Sebastian Tennant <[email-masked]>
Date: Sat, 11 Mar 2023 10:47:40 +0000

Hello Jeff,

Alas, I thought I understood fetch refspecs, but it appears not.

Quoth Jeff King <[email-masked]>
on Wed, 8 Mar 2023 22:12:29 -0500:
> On Wed, Mar 08, 2023 at 04:54:39PM +0000, Sebastian Tennant wrote:
> […]
>> Indeed.  To fetch a known ref, a client (also with the normal fetch
>> refspec) would have to do something like this, for example:
>>
>>  $ git fetch origin\
>>        refs/remotes/origin/<ref>:refs/remotes/upstream/<ref>
>>
>> Alternatively, they could add an additional fetch refspec to their
>> config:
>>
>> [remote="origin"]
>>  ...
>>  fetch = +refs/heads/*:refs/remotes/origin/*             # normal
>>  fetch = +refs/remotes/origin/*:refs/remotes/upstream/*  # additional
>>
>> This would have the advantage of fetching all the upstream refs on
>> the next update giving them a better idea of what's happening
>> upstream.
>>
>> Is my understanding more or less correct?
>
> Yes, that's exactly correct. In some ways it is cleaner than using
> "refs/heads/upstream" because it leaves the whole "refs/heads/"
> namespace intact for local client branches. It depends on how much
> of a pain it is to configure the extra refspec in each client. :)

I decided to go with the cleaner approach.

Here are the actions I'm taking to configure the mirror:

 $ git clone --bare https://url.of/project.git
 $ cd project.git
 $ git remote rename origin upstream
 $ git config remote.upstream.fetch\
       '+refs/heads/*:refs/remotes/upstream/*'
 $ git fetch upstream --prune

At this point there are no refs under refs/heads (and very many under
refs/remotes/upstream).

Here are the actions I'm then taking on a client:

 $ git clone --bare mirror:path/to/project.git
 $ cd project.git
 $ git remote rename origin mirror
 $ git config remote.mirror.fetch\
       '+refs/heads/*:refs/remotes/mirror/*'

At this point, both mirror and client have a normal fetch refspec,
i.e. no additional refspec has been added to the client, yet when I
run:

 $ git fetch mirror --prune

on the client, all the refs on mirror under refs/remotes/upstream are
fetched and placed under refs/remotes/mirror on the client.

My understanding of refspec:

 +refs/heads/*:refs/remotes/mirror/*

is "fetch only those refs under refs/heads and place them under
refs/remotes/mirror", which in this case should mean that no refs are
fetched (since there are none on mirror under refs/heads).

What's going on here that I'm just not getting?

If I add the additional refspec to the client:

 $ git config --add remote.mirror.fetch\
   '+refs/remotes/upstream/*:refs/remotes/upstream/*'

and fetch once more, I end up with all the refs already under
refs/remotes/mirror duplicated under refs/remotes/upstream.

Sebastian