Subject: How do I "git fetch" with a custom <refspec> but a default remote?

From: Ævar Arnfjörð Bjarmason <[email-masked]>
Date: Thu, 12 Nov 2020 15:19:19 +0100

On Wed, Nov 11 2020, Ævar Arnfjörð Bjarmason wrote:

> In any case, this is one thing that came out of that
> investigation. The code we're keeping by moving it to git-submodule.sh
> can also be replaced by some C code we have, but I wanted to leave
> that to another submission (if I'll get to it), and make this simply a
> code removal.

I may have missed a way to do $subject, but I don't think it's
possible. The reason I want it is because git-submodule.sh does this:

    git fetch $(get_default_remote) "$@" ;;

Where that shellscript function gets the name of the remote configured
for the current branch. If you do just a:

    git fetch

Then it will do the right thing, per its documentation:

     When no remote is specified, by default the origin remote will be
     used, unless there’s an upstream branch configured for the current
     branch.

But git-submodule.sh wants to do:

    git fetch <default-remote> <some-sha1>

So the caller is forced to find out what that is.

I came up with this patch:
    
    diff --git a/builtin/fetch.c b/builtin/fetch.c
    index f9c3c49f14..f110ac8d08 100644
    --- a/builtin/fetch.c
    +++ b/builtin/fetch.c
    @@ -56,6 +56,7 @@ static int prune_tags = -1; /* unspecified */
     #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
     
     static int all, append, dry_run, force, keep, multiple, update_head_ok;
    +static int default_remote;
     static int write_fetch_head = 1;
     static int verbosity, deepen_relative, set_upstream;
     static int progress = -1;
    @@ -140,6 +141,8 @@ static struct option builtin_fetch_options[] = {
            OPT__VERBOSITY(&verbosity),
            OPT_BOOL(0, "all", &all,
                     N_("fetch from all remotes")),
    +       OPT_BOOL(0, "default-remote", &default_remote,
    +                N_("fetch from default remote")),
            OPT_BOOL(0, "set-upstream", &set_upstream,
                     N_("set upstream for git pull/fetch")),
            OPT_BOOL('a', "append", &append,
    @@ -1852,7 +1855,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                    else if (argc > 1)
                            die(_("fetch --all does not make sense with refspecs"));
                    (void) for_each_remote(get_one_remote_for_fetch, &list);
    -       } else if (argc == 0) {
    +       } else if (argc == 0 || default_remote) {
                    /* No arguments -- use default remote */
                    remote = remote_get(NULL);
            } else if (multiple) {

Which allows me to do:

    -               git fetch $(get_default_remote) "$@" ;;
    +               git fetch --default-remote "$@" ;;

So it works, but what do we think about this calling convention? Do we
have any prior art for commands that take positional arguments like
<remote> and <refspec> where you'd like to use a default for an earlier
argument to provide a subsequent one?

To make it more general and consistent we'de probably like a --remote=*
and --refspec arguments, so the invocation would be:

    git fetch ([--remote=]<name> | --default-remote) [([--refspec=]<refspec> | --default-refspec)]

But maybe I'm overthinking it...