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

Re: [PATCH v2] builtin/push: call set_refspecs after validating remote

From
Junio C Hamano <gitster@pobox.com>
Date
Jul 9, 2024, 18:44 UTC
Message-ID
<xmqq4j8yflrq.fsf@gitster.g>
In-Reply-To
<20240709144931.1146528-1-karthik.188@gmail.com>
Karthik Nayak <karthik.188@gmail.com> writes:
> - Added more details to the commit message to clarify the issue at hand.
Show 9 quoted lines
> Since 9badf97c42 (remote: allow resetting url list, 2024-06-14), we
> reset the remote URL if the provided URL is empty. When a user of
> 'remotes_remote_get' tries to fetch a remote with an empty repo name,
> the function initializes the remote via 'make_remote'. But the remote is
> still not a valid remote, since the URL is empty, so it tries to add the
> URL alias using 'add_url_alias'. This in-turn will call 'add_url', but
> since the URL is empty we call 'strvec_clear' on the `remote->url`. Back
> in 'remotes_remote_get', we again check if the remote is valid, which
> fails, so we return 'NULL' for the 'struct remote *' value

That's better, but it still talks only about the implementation and control flow description without mentioning what end-user action it breaks. We see in the new test this:

    $ git push "" main

but is that something we even want to support? Before 9badf97c (remote: allow resetting url list, 2024-06-14), the command would have failed with different way [*1*].

Is it merely "this is a nonsense request and must fail, but we do not want to hit BUG in general"? I think it is the latter, but leaving it unsaid is confusing. How about starting it more like...

    When an end-user runs "git push" with an empty string for the
    remote repository name, e.g.
        $ git push '' main
    "git push" fails with a BUG().  This is because ...
or something.

cmd_push() calls set_refspecs() on a repo (whose name is ""), which then calls remote.c:remote_get() on it, which calls remote.c:make_remote() to obtain a remote structure.

But during this calling sequence especially down from remote_get(), there are inconsistent decisions made for an empty string as a name. It is not a NULL pointer, so it does not benefit from the default refspecs by calling get_default=remotes_remote_for_branch, valid_remote_nick() considers it is not a valid nick so we do not read remotes or branches configuration file, but we still think a name was given (even though it is an empty string) and try to do something useful by calling add_url_alias().

It is a mess and whoever designed this should be shot [*2*] ;-).

In any case, an obvious additional fix on top of your change might be to do something like this:

        diff --git i/remote.c w/remote.c
        index 5fa046c8f8..d7f9ba3571 100644
        --- i/remote.c
        +++ w/remote.c
        @@ -682,7 +682,7 @@ remotes_remote_get_1(
                struct remote *ret;
                int name_given = 0;
        -	if (name)
        +	if (name && *name)
                        name_given = 1;
                else
                        name = get_default(remote_state, remote_state->current_branch,

which would give us the default remote name, and we would not call add_url_alias() with a bogus empty string to nuke the list.

> - Cleaned up 'set_refspecs' by now accepting a remote instead of trying
>   to obtain one. 

The last one, which does make sense, is not mentioned in the proposed log message. Lazy remote creation does not help the updated caller because it already has one.

Show 12 quoted lines
> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
> +
>  TEST_PASSES_SANITIZE_LEAK=true
>  . ./test-lib.sh
>  
> @@ -38,6 +41,13 @@ test_expect_success 'detect missing sha1 expressions early' '
>  	test_cmp expect rp-ran
>  '
>  
> +# We need to use an existing local_ref so that the remote is mapped to
> +# it in 'builtin/push.c:set_refspecs()'.

Hmph, it is OK to force 'main' like the above as a workaround, but wouldn't it be sufficient to do

    $ git push "" HEAD:refs/heads/main
or something to avoid having to know what our current branch is?
Thanks.
[Footnote }
 *1* For example, before Peff's series, here is what I got:
         $ git push "" HEAD:master
         fatal: no path specified; see 'git help pull' for valid url syntax
     It comes from transport_push() -> get_refs_via_connect() ->
     parse_connect_url() code path.
 *2* It probably is me writing in the original in shell script, so I
     can safely say this without offending anybody.
Previous: Karthik NayakNext: Junio C Hamano
Message 9 of 20 in “builtin/push: call set_refspecs after validating remote”
  1. builtin/push: call set_refspecs after validating remoteKarthik Nayak, Jul 8, 2024
  2. Junio C HamanoJul 8, 2024
  3. Jeff KingJul 8, 2024
  4. Karthik NayakJul 9, 2024
  5. Jeff KingJul 8, 2024
  6. Karthik NayakJul 9, 2024
  7. Jeff KingJul 9, 2024
  8. builtin/push: call set_refspecs after validating remoteKarthik Nayak, Jul 9, 2024
  9. Junio C HamanoJul 9, 2024
  10. Junio C HamanoJul 9, 2024
  11. Jeff KingJul 9, 2024
  12. Junio C HamanoJul 10, 2024
  13. Karthik NayakJul 10, 2024
  14. Junio C HamanoJul 10, 2024
  15. Jeff KingJul 10, 2024
  16. Karthik NayakJul 11, 2024
  17. Jeff KingJul 11, 2024
  18. builtin/push: call set_refspecs after validating remoteKarthik Nayak, Jul 11, 2024
  19. Junio C HamanoJul 11, 2024
  20. Jeff KingJul 11, 2024

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.