Git development
 help / color / mirror / Atom feed
* [PATCH v6] checkout: extend --track with a "fetch" mode to refresh start-point
From: Harald Nordgren via GitGitGadget @ 2026-05-03 22:31 UTC (permalink / raw)
  To: git
  Cc: Ramsay Jones, D. Ben Knoble, Kristoffer Haugsbakk, Marc Branchaud,
	Harald Nordgren, Harald Nordgren
In-Reply-To: <pull.2281.v5.git.git.1777367012441.gitgitgadget@gmail.com>

From: Harald Nordgren <haraldnordgren@gmail.com>

If you want to fork your topic branch from the very latest of the
tip of a branch your remote has, you would do:

    git fetch origin some-branch
    git checkout -b new_branch --track origin/some-branch

Extend the "--track" option of "git checkout" and allow users to
write

    git checkout -b new_branch --track=fetch origin/some-branch

to (1) fetch 'some-branch' from the remote 'origin', updating the
remote-tracking branch 'origin/some-branch', (2) arrange subsequent
'git pull' on 'new_branch' to interact with 'origin/some-branch' and
(3) fork 'new_branch' from it.

In the value of the '--track' option, 'fetch' can be combined with
the existing 'direct' (default) and 'inherit' modes via a
comma-separated list. Examples:

    git checkout -b new_branch --track=fetch,inherit some_local_branch
    git switch -c new_branch --track=fetch origin/some-branch

When "fetch" is requested and <start-point> is in <remote>/<branch>
form, run "git fetch <remote> <branch>" before resolving the ref, so
that other remote-tracking branches are left untouched. If
<start-point> is a bare remote name like "origin" (which resolves to
that remote's default branch), "git fetch <remote>" is run instead,
since the target branch is not known up front. Abort the checkout if
the fetch fails.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
---
    checkout: add --fetch to fetch remote before resolving start-point
    
    Commit message only, no code/doc/test changes. Restructured the opening
    around the user-visible workflow before introducing '--track=fetch',
    reordered all example invocations to ' -b/-c --track[=...] ', dropped
    the "wrong/stale start-point" and "arbitrary commit" framings, and
    trimmed the over-explanation of the narrowed fetch.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2281%2FHaraldNordgren%2Fcheckout-fetch-start-point-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2281/HaraldNordgren/checkout-fetch-start-point-v6
Pull-Request: https://github.com/git/git/pull/2281

Range-diff vs v5:

 1:  8ebc2f94b9 ! 1:  1b42c648b9 checkout: extend --track with a "fetch" mode to refresh start-point
     @@ Metadata
       ## Commit message ##
          checkout: extend --track with a "fetch" mode to refresh start-point
      
     -    A common workflow is:
     +    If you want to fork your topic branch from the very latest of the
     +    tip of a branch your remote has, you would do:
      
     -        git fetch origin
     +        git fetch origin some-branch
              git checkout -b new_branch --track origin/some-branch
      
     -    The first command exists so the second sees an up-to-date view of the
     -    remote. If it is forgotten, origin/some-branch points at a stale
     -    commit and the new local branch is created from the wrong start
     -    point. This only matters when the user is setting up tracking and
     -    expects the new branch to start at the freshest tip; for a one-off
     -    checkout of an arbitrary commit there is no reason to "freshen" the
     -    start-point.
     +    Extend the "--track" option of "git checkout" and allow users to
     +    write
      
     -    Tie the new behavior to --track for that reason: extend its argument
     -    to take a comma-separated list, where "fetch" can be combined with the
     -    existing "direct" (default) and "inherit" modes. Examples:
     +        git checkout -b new_branch --track=fetch origin/some-branch
      
     -        git checkout --track=fetch -b new_branch origin/some-branch
     -        git checkout --track=fetch,inherit -b new_branch some_local_branch
     -        git switch --track=fetch -c new_branch origin/some-branch
     +    to (1) fetch 'some-branch' from the remote 'origin', updating the
     +    remote-tracking branch 'origin/some-branch', (2) arrange subsequent
     +    'git pull' on 'new_branch' to interact with 'origin/some-branch' and
     +    (3) fork 'new_branch' from it.
     +
     +    In the value of the '--track' option, 'fetch' can be combined with
     +    the existing 'direct' (default) and 'inherit' modes via a
     +    comma-separated list. Examples:
     +
     +        git checkout -b new_branch --track=fetch,inherit some_local_branch
     +        git switch -c new_branch --track=fetch origin/some-branch
      
          When "fetch" is requested and <start-point> is in <remote>/<branch>
     -    form, run "git fetch <remote> <branch>" before resolving the ref. This
     -    narrows the fetch to the requested branch so that other
     -    remote-tracking branches are left untouched -- many tools rely on the
     -    stability of remote-tracking refs between explicit fetches. If
     +    form, run "git fetch <remote> <branch>" before resolving the ref, so
     +    that other remote-tracking branches are left untouched. If
          <start-point> is a bare remote name like "origin" (which resolves to
          that remote's default branch), "git fetch <remote>" is run instead,
          since the target branch is not known up front. Abort the checkout if


 Documentation/git-checkout.adoc | 10 +++-
 Documentation/git-switch.adoc   | 10 +++-
 builtin/checkout.c              | 85 +++++++++++++++++++++++++++++++--
 t/t7201-co.sh                   | 81 +++++++++++++++++++++++++++++++
 4 files changed, 179 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-checkout.adoc b/Documentation/git-checkout.adoc
index 43ccf47cf6..3b8292612d 100644
--- a/Documentation/git-checkout.adoc
+++ b/Documentation/git-checkout.adoc
@@ -158,11 +158,19 @@ of it").
 	resets _<branch>_ to the start point instead of failing.
 
 `-t`::
-`--track[=(direct|inherit)]`::
+`--track[=(direct|inherit|fetch)[,...]]`::
 	When creating a new branch, set up "upstream" configuration. See
 	`--track` in linkgit:git-branch[1] for details. As a convenience,
 	--track without -b implies branch creation.
 +
+The argument is a comma-separated list. `direct` (the default) and
+`inherit` select the tracking mode. Adding `fetch` requests that the
+remote be fetched before _<start-point>_ is resolved, so the new branch
+starts from a fresh tip: when _<start-point>_ is in
+_<remote>/<branch>_ form, only that branch is updated; when it is a
+bare remote name (e.g. `origin`), the whole remote is fetched. If the
+fetch fails, the checkout is aborted.
++
 If no `-b` option is given, the name of the new branch will be
 derived from the remote-tracking branch, by looking at the local part of
 the refspec configured for the corresponding remote, and then stripping
diff --git a/Documentation/git-switch.adoc b/Documentation/git-switch.adoc
index 87707e9265..35a03e8a52 100644
--- a/Documentation/git-switch.adoc
+++ b/Documentation/git-switch.adoc
@@ -154,11 +154,19 @@ should result in deletion of the path).
 	attached to a terminal, regardless of `--quiet`.
 
 `-t`::
-`--track[ (direct|inherit)]`::
+`--track[=(direct|inherit|fetch)[,...]]`::
 	When creating a new branch, set up "upstream" configuration.
 	`-c` is implied. See `--track` in linkgit:git-branch[1] for
 	details.
 +
+The argument is a comma-separated list. `direct` (the default) and
+`inherit` select the tracking mode. Adding `fetch` requests that the
+remote be fetched before _<start-point>_ is resolved, so the new branch
+starts from a fresh tip: when _<start-point>_ is in
+_<remote>/<branch>_ form, only that branch is updated; when it is a
+bare remote name (e.g. `origin`), the whole remote is fetched. If the
+fetch fails, the switch is aborted.
++
 If no `-c` option is given, the name of the new branch will be derived
 from the remote-tracking branch, by looking at the local part of the
 refspec configured for the corresponding remote, and then stripping
diff --git a/builtin/checkout.c b/builtin/checkout.c
index e031e61886..de4d7c00c7 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -30,7 +30,9 @@
 #include "repo-settings.h"
 #include "resolve-undo.h"
 #include "revision.h"
+#include "run-command.h"
 #include "setup.h"
+#include "strvec.h"
 #include "submodule.h"
 #include "symlinks.h"
 #include "trace2.h"
@@ -61,6 +63,7 @@ struct checkout_opts {
 	int count_checkout_paths;
 	int overlay_mode;
 	int dwim_new_local_branch;
+	int fetch;
 	int discard_changes;
 	int accept_ref;
 	int accept_pathspec;
@@ -112,6 +115,74 @@ struct branch_info {
 	char *checkout;
 };
 
+static void fetch_remote_for_start_point(const char *arg)
+{
+	const char *slash;
+	char *remote_name;
+	struct remote *remote;
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	if (!arg || !*arg)
+		return;
+
+	slash = strchr(arg, '/');
+	if (slash == arg)
+		return;
+	remote_name = slash ? xstrndup(arg, slash - arg) : xstrdup(arg);
+
+	remote = remote_get(remote_name);
+	if (!remote || !remote_is_configured(remote, 1)) {
+		free(remote_name);
+		return;
+	}
+
+	strvec_pushl(&cmd.args, "fetch", remote_name, NULL);
+	if (slash && slash[1])
+		strvec_push(&cmd.args, slash + 1);
+	cmd.git_cmd = 1;
+	free(remote_name);
+	if (run_command(&cmd))
+		die(_("failed to fetch start-point '%s'"), arg);
+}
+
+static int parse_opt_checkout_track(const struct option *opt,
+				    const char *arg, int unset)
+{
+	struct checkout_opts *opts = opt->value;
+	struct string_list tokens = STRING_LIST_INIT_DUP;
+	struct string_list_item *item;
+	int ret = 0;
+
+	if (unset) {
+		opts->track = BRANCH_TRACK_NEVER;
+		opts->fetch = 0;
+		return 0;
+	}
+
+	opts->track = BRANCH_TRACK_EXPLICIT;
+	if (!arg)
+		return 0;
+
+	string_list_split(&tokens, arg, ",", -1);
+	for_each_string_list_item(item, &tokens) {
+		if (!strcmp(item->string, "fetch")) {
+			opts->fetch = 1;
+		} else if (!strcmp(item->string, "direct")) {
+			opts->track = BRANCH_TRACK_EXPLICIT;
+		} else if (!strcmp(item->string, "inherit")) {
+			opts->track = BRANCH_TRACK_INHERIT;
+		} else {
+			ret = error(_("option `%s' expects \"%s\", \"%s\", "
+				      "or \"%s\""),
+				    "--track", "direct", "inherit", "fetch");
+			break;
+		}
+	}
+
+	string_list_clear(&tokens, 0);
+	return ret;
+}
+
 static void branch_info_release(struct branch_info *info)
 {
 	free(info->name);
@@ -1237,7 +1308,6 @@ static int git_checkout_config(const char *var, const char *value,
 		opts->dwim_new_local_branch = git_config_bool(var, value);
 		return 0;
 	}
-
 	if (starts_with(var, "submodule."))
 		return git_default_submodule_config(var, value, NULL);
 
@@ -1734,10 +1804,10 @@ static struct option *add_common_switch_branch_options(
 {
 	struct option options[] = {
 		OPT_BOOL('d', "detach", &opts->force_detach, N_("detach HEAD at named commit")),
-		OPT_CALLBACK_F('t', "track",  &opts->track, "(direct|inherit)",
+		OPT_CALLBACK_F('t', "track",  opts, "(direct|inherit|fetch)[,...]",
 			N_("set branch tracking configuration"),
 			PARSE_OPT_OPTARG,
-			parse_opt_tracking_mode),
+			parse_opt_checkout_track),
 		OPT__FORCE(&opts->force, N_("force checkout (throw away local modifications)"),
 			   PARSE_OPT_NOCOMPLETE),
 		OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unborn branch")),
@@ -1942,8 +2012,13 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
 			opts->dwim_new_local_branch &&
 			opts->track == BRANCH_TRACK_UNSPECIFIED &&
 			!opts->new_branch;
-		int n = parse_branchname_arg(argc, argv, dwim_ok, which_command,
-					     &new_branch_info, opts, &rev);
+		int n;
+
+		if (opts->fetch)
+			fetch_remote_for_start_point(argv[0]);
+
+		n = parse_branchname_arg(argc, argv, dwim_ok, which_command,
+					 &new_branch_info, opts, &rev);
 		argv += n;
 		argc -= n;
 	} else if (!opts->accept_ref && opts->from_treeish) {
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 9bcf7c0b40..39236dca12 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -801,4 +801,85 @@ test_expect_success 'tracking info copied with autoSetupMerge=inherit' '
 	test_cmp_config "" --default "" branch.main2.merge
 '
 
+test_expect_success 'setup upstream for --track=fetch tests' '
+	git checkout main &&
+	git init fetch_upstream &&
+	test_commit -C fetch_upstream u_main &&
+	git remote add fetch_upstream fetch_upstream &&
+	git fetch fetch_upstream &&
+	git -C fetch_upstream checkout -b fetch_new &&
+	test_commit -C fetch_upstream u_new
+'
+
+test_expect_success 'checkout --track=fetch -b picks up branch created upstream after clone' '
+	git checkout main &&
+	test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_new &&
+	git checkout --track=fetch -b local_new fetch_upstream/fetch_new &&
+	test_cmp_rev refs/remotes/fetch_upstream/fetch_new HEAD &&
+	test_cmp_config fetch_upstream branch.local_new.remote &&
+	test_cmp_config refs/heads/fetch_new branch.local_new.merge
+'
+
+test_expect_success 'checkout --track=fetch <remote>/<branch> leaves other tracking branches untouched' '
+	git checkout main &&
+	git -C fetch_upstream checkout -b fetch_target &&
+	test_commit -C fetch_upstream u_target_pre &&
+	git -C fetch_upstream checkout -b fetch_other &&
+	test_commit -C fetch_upstream u_other_pre &&
+	git fetch fetch_upstream &&
+	other_before=$(git rev-parse refs/remotes/fetch_upstream/fetch_other) &&
+	git -C fetch_upstream checkout fetch_target &&
+	test_commit -C fetch_upstream u_target_post &&
+	git -C fetch_upstream checkout fetch_other &&
+	test_commit -C fetch_upstream u_other_post &&
+	git checkout --track=fetch -b local_target fetch_upstream/fetch_target &&
+	test_cmp_rev refs/remotes/fetch_upstream/fetch_target HEAD &&
+	test "$(git rev-parse refs/remotes/fetch_upstream/fetch_other)" = "$other_before"
+'
+
+test_expect_success 'checkout --track=fetch with bare remote name fetches the remote' '
+	git checkout main &&
+	git -C fetch_upstream checkout -b fetch_new2 &&
+	test_commit -C fetch_upstream u_new2 &&
+	test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_new2 &&
+	git checkout --track=fetch -b local_from_remote fetch_upstream &&
+	git rev-parse --verify refs/remotes/fetch_upstream/fetch_new2
+'
+
+test_expect_success 'checkout --track=fetch aborts and does not create branch on fetch failure' '
+	git checkout main &&
+	test_might_fail git branch -D bogus &&
+	test_must_fail git checkout --track=fetch -b bogus fetch_upstream/does_not_exist &&
+	test_must_fail git rev-parse --verify refs/heads/bogus
+'
+
+test_expect_success 'checkout --track=fetch,inherit fetches and inherits' '
+	git checkout main &&
+	git -C fetch_upstream checkout -b fetch_inherit &&
+	test_commit -C fetch_upstream u_inherit &&
+	git fetch fetch_upstream fetch_inherit &&
+	git checkout -b base_inherit fetch_upstream/fetch_inherit &&
+	test_commit -C fetch_upstream u_inherit2 &&
+	git checkout main &&
+	git checkout --track=fetch,inherit -b local_inherit base_inherit &&
+	test_cmp_rev refs/remotes/fetch_upstream/fetch_inherit HEAD &&
+	test_cmp_config fetch_upstream branch.local_inherit.remote &&
+	test_cmp_config refs/heads/fetch_inherit branch.local_inherit.merge
+'
+
+test_expect_success 'checkout --track=bogus reports an error' '
+	git checkout main &&
+	test_must_fail git checkout --track=bogus -b bogus_branch fetch_upstream/fetch_new 2>err &&
+	test_grep "expects" err
+'
+
+test_expect_success 'switch --track=fetch -c picks up branch created upstream after clone' '
+	git checkout main &&
+	git -C fetch_upstream checkout -b fetch_switch &&
+	test_commit -C fetch_upstream u_switch &&
+	test_must_fail git rev-parse --verify refs/remotes/fetch_upstream/fetch_switch &&
+	git switch --track=fetch -c local_switch fetch_upstream/fetch_switch &&
+	test_cmp_rev refs/remotes/fetch_upstream/fetch_switch HEAD
+'
+
 test_done

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH 1/1] http: reject unsupported proxy URL schemes
From: Junio C Hamano @ 2026-05-03 22:19 UTC (permalink / raw)
  To: aminnimaj; +Cc: git, peff, ryan.hendrickson
In-Reply-To: <20260501190401.1580-2-aminnimaj@gmail.com>

aminnimaj@gmail.com writes:

> +static int is_socks_proxy_protocol(const char *protocol)
> +{
> +	return protocol &&
> +		(!strcmp(protocol, "socks") ||
> +		 !strcmp(protocol, "socks4") ||
> +		 !strcmp(protocol, "socks4a") ||
> +		 !strcmp(protocol, "socks5") ||
> +		 !strcmp(protocol, "socks5h"));
> +}
> +
> +static int set_curl_proxy_type(CURL *result, const char *protocol)
> +{
> +	if (!protocol || !strcmp(protocol, "http"))
> +		return 0;
> +
> +	if (!strcmp(protocol, "socks5h"))
> +		curl_easy_setopt(result, CURLOPT_PROXYTYPE,
> +				 (long)CURLPROXY_SOCKS5_HOSTNAME);
> +	else if (!strcmp(protocol, "socks5"))
> +		curl_easy_setopt(result, CURLOPT_PROXYTYPE,
> +				 (long)CURLPROXY_SOCKS5);
> +	else if (!strcmp(protocol, "socks4a"))
> +		curl_easy_setopt(result, CURLOPT_PROXYTYPE,
> +				 (long)CURLPROXY_SOCKS4A);
> +	else if (!strcmp(protocol, "socks") ||
> +		 !strcmp(protocol, "socks4"))
> +		curl_easy_setopt(result, CURLOPT_PROXYTYPE,
> +				 (long)CURLPROXY_SOCKS4);
> +	else if (!strcmp(protocol, "https")) {
> +		curl_easy_setopt(result, CURLOPT_PROXYTYPE, (long)CURLPROXY_HTTPS);
> +
> +		if (http_proxy_ssl_cert)
> +			curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT,
> +					 http_proxy_ssl_cert);
> +
> +		if (http_proxy_ssl_key)
> +			curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY,
> +					 http_proxy_ssl_key);
> +
> +		if (has_proxy_cert_password())
> +			curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD,
> +					 proxy_cert_auth.password);
> +	} else {
> +		return -1;
> +	}
> +
> +	return 0;
> +}

Can these two be rewritten to be more table driven?  I.e.,

static struct socks_proxy_type {
	const char *name;
	long curlsym;
} socks_proxy_type[] = {
	{ "socks", CURLPROXY_SOCKS4_HOSTNAME },
	...
	{ "socks5h", CURLPROXY_SOCKS5_HOSTNAME },
};

static bool is_socks_proxy_protocol(const char *protocol)
{
	if (!protocol)
		return false;
	for (int i = 0; i < ARRAY_SIZE(socks_proxy_type); i++)
        	if (!strcmp(socks_proxy_type[i].name, protocol))
                	return true;
	return false;
}

static int set_curl_proxy_type(...)
{
	for (int i = 0; i < ARRAY_SIZE(socks_proxy_type); i++) {
        	if (!strcmp(socks_proxy_type[i].name, protocol)) {
			curl_easy_setopt(result, CURLOPT_PROXYTYPE, 
					socks_proxy_type[i].curlsym);
			return 0;
		}
	}
	/* otherwise ... */
        if (!strcmp(protocol, "https")) {
		...
	}
}

> diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh
> index 3bcbdef409..db69aa2295 100755
> --- a/t/t5564-http-proxy.sh
> +++ b/t/t5564-http-proxy.sh
> @@ -95,4 +95,9 @@ test_expect_success 'Unix socket requires localhost' - <<\EOT
>  	}
>  EOT
>  
> +test_expect_success 'unknown proxy scheme is rejected' '
> +	! git clone -c http.proxy=htpp://127.0.0.1 https://example.com/repo.git 2>err &&

Use test_must_fail to tell between uncontrolled failures like
crashes and controlled die()s.

> +	grep -Fx "fatal: Invalid proxy URL '\''htpp://127.0.0.1'\'': unsupported proxy scheme '\''htpp'\''" err
> +'

Avoid insisting the exact match with such a long line and stick to
the essential part, like "unsupported proxy scheme '...'".

Also use test_grep for better debuggability.


^ permalink raw reply

* Re: git rename/moved status unreliable in ruby
From: Junio C Hamano @ 2026-05-03 21:59 UTC (permalink / raw)
  To: Phillip Wood; +Cc: sebastien.stettler, git@vger.kernel.org
In-Reply-To: <026b84f4-7052-4d5b-a9ae-c2487569d1ee@gmail.com>

Phillip Wood <phillip.wood123@gmail.com> writes:

> Hi Sebastien
>
> On 01/05/2026 06:05, sebastien.stettler wrote:
>> 1. What did you do before the bug happened? (Steps to reproduce your issue)
>> 
>> when moving ruby classes between namespaces they are marked as new files and the old
>> ones are marked as deleted
>> 
>> if i only change the class name it will mark it as renamed
>
> Rename detection is based on how similar the two files are. Looking at 
> the example you linked to below you're changing a file that looks like
> ...
> Which means that git sees that every line has changed because the 
> indentation has changed. If you want git to realize that the file has 
> been renamed you could move it in one commit and then add modify it in 
> the next commit.

I've seen this repeated many times, but it is misleading to give it
without qualifying when that "works" and when it does not.  Such a
"stick to pure rename and make huge changes elsewhere" strategy
would help your "git log -M [--follow]" and possibly "git rebase",
but it would not help all that much if you are doing "git diff" or
"git merge".


    

^ permalink raw reply

* Re: [PATCH v5] checkout: extend --track with a "fetch" mode to refresh start-point
From: Junio C Hamano @ 2026-05-03 20:59 UTC (permalink / raw)
  To: Harald Nordgren via GitGitGadget
  Cc: git, Ramsay Jones, D. Ben Knoble, Kristoffer Haugsbakk,
	Marc Branchaud, Harald Nordgren
In-Reply-To: <pull.2281.v5.git.git.1777367012441.gitgitgadget@gmail.com>

"Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Harald Nordgren <haraldnordgren@gmail.com>
>
> A common workflow is:
>
>     git fetch origin
>     git checkout -b new_branch --track origin/some-branch
>
> The first command exists so the second sees an up-to-date view of the
> remote. If it is forgotten, origin/some-branch points at a stale
> commit and the new local branch is created from the wrong start
> point.

As I pointed out multiple times, I prefer not to see this called
"wrong".  Even if you did not "forget", somebody may be pushing
after you fetched and you may end up forking from a "stale" commit.
So not fetching is not inherently "wrong", simply because that is
how real world works.  Multiple people working in a distributed
environment does not give you absolute garantee that you will be "up
to date", ever, which makes it wrong to call anything that is not
"up to date" a "wrong starting point".

> This only matters when the user is setting up tracking and
> expects the new branch to start at the freshest tip; for a one-off
> checkout of an arbitrary commit there is no reason to "freshen" the
> start-point.

I do not think "arbitrary" fits in this workflow description.

If anything, "I'd take anything that the remote repository happens
to have at the tip, even without having a chance to sanity checke if
that is a good starting point" is more appropriate workflow to be
described with a word "arbitrary commit".

If you are checking out without forking from there, you'd more
likely be checking out the "latest" you have fetched from the other
side, often knowing exactly what it is after checking it with "git
show origin/$topic".

> Tie the new behavior to --track for that reason:

Notice that the reader hasn't heard what "the new behaviour" is up
to this point yet?

How about rewriting everything up to and including this "Tie the new
..." line perhaps like so:

    If you want to fork your topic branch from the very latest of
    the tip of a branch your remote has, you would do:

	git fetch origin some-branch
	git checkout -b new_branch --track origin/some-branch

    Extend the "--track" option of "git checkout" and allow users to
    write

	git checkout --track=fetch -b new_branch origin/some_branch

    to (1) fetch 'some-branch' from the remote 'origin', updating
    the remote-tracking branch 'origin/some-branch', (2) arrange
    subsequent 'git pull' on 'new_branch' to interact with
    'origin/some_branch' and (3) fork 'new_branch' from it.
   
    In the value of the '--track' option, 'fetch' can be combined
    with ...

^ permalink raw reply

* git 2.54 fails to build for rhel 6 (2.53 builds fine)
From: Азат Усманов @ 2026-05-03 19:50 UTC (permalink / raw)
  To: git

Hi everyone! I have noticed a problem when trying to build latest git 2.54 in rhel 6,(2.53 builds fine ) nothing has changed on this machine  since I successfully installed 2.53 . My openssl version is 3.5.6. Any Ideas? Below is the log 
~# wget --no-check-certificate https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.54.0.tar.gz
--2026-05-03 22:19:32--  https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.54.0.tar.gz
Connecting to 192.168.1.2:3128... connected.
Proxy request sent, awaiting response... 200 OK
Length: 12102611 (12M) [application/x-gzip]
Saving to: “git-2.54.0.tar.gz”

100%[======================================>] 12,102,611  1.88M/s   in 6.5s

2026-05-03 22:19:39 (1.78 MB/s) - “git-2.54.0.tar.gz” saved [12102611/12102611]

[sun] ~# tar -xf git-2.54.0.tar.gz
[sun] ~# cd git-2.54.0
[sun] git-2.54.0#  ./configure && make -j $(nproc)  CSPRNG_METHOD= &&  make -j $(nproc) install  CSPRNG_METHOD= && make -j $(nproc) clean
configure: Setting lib to 'lib' (the default)
configure: Will try -pthread then -lpthread to enable POSIX Threads.
configure: CHECKS for site configuration
checking for gcc... /usr/local/gcc-13.4.0/bin/gcc-13.4
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether /usr/local/gcc-13.4.0/bin/gcc-13.4 accepts -g... yes
checking for /usr/local/gcc-13.4.0/bin/gcc-13.4 option to enable C11 features... none needed
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for strings.h... yes
checking for sys/stat.h... yes
checking for sys/types.h... yes
checking for unistd.h... yes
checking for size_t... yes
checking for working alloca.h... yes
checking for alloca... yes
configure: CHECKS for programs
checking whether the compiler supports GNU C... (cached) yes
checking whether /usr/local/gcc-13.4.0/bin/gcc-13.4 accepts -g... (cached) yes
checking for /usr/local/gcc-13.4.0/bin/gcc-13.4 option to enable C11 features...(cached) none needed
checking for inline... inline
checking if linker supports -R... no
checking if linker supports -Wl,-rpath,... yes
checking for gar... no
checking for ar... ar
checking for gtar... gtar
checking for gnudiff... no
checking for gdiff... no
checking for diff... diff
checking for asciidoc... no
configure: CHECKS for libraries
checking for SHA1_Init in -lcrypto... yes
checking for curl_global_init in -lcurl... yes
checking for curl-config... curl-config
configure: Setting CURL_LDFLAGS to '-L/usr/local/lib -lcurl'
checking for XML_ParserCreate in -lexpat... yes
checking for iconv in -lc... yes
checking for deflateBound in -lz... yes
checking for socket in -lc... yes
checking for inet_ntop... yes
checking for inet_pton... yes
checking for hstrerror... yes
checking for basename in -lc... yes
checking if libc contains libintl... yes
checking for libintl.h... yes
configure: CHECKS for header files
checking for sys/select.h... yes
checking for poll.h... yes
checking for sys/poll.h... yes
checking for inttypes.h... (cached) yes
checking for old iconv()... no
checking whether iconv omits bom for utf-16 and utf-32... no
configure: CHECKS for typedefs, structures, and compiler characteristics
checking for socklen_t... yes
checking for struct itimerval... yes
checking for struct stat.st_mtimespec.tv_nsec... no
checking for struct stat.st_mtim.tv_nsec... yes
checking for struct dirent.d_type... yes
checking for struct passwd.pw_gecos... yes
checking for struct sockaddr_storage... yes
checking for struct addrinfo... yes
checking for getaddrinfo... yes
checking for library containing getaddrinfo... none required
checking how to run the C preprocessor... /usr/local/gcc-13.4.0/bin/gcc-13.4 -E
checking for egrep -e... /bin/grep -E
checking whether the platform regex supports REG_STARTEND... yes
checking whether system succeeds to read fopen'ed directory... yes
checking whether snprintf() and/or vsnprintf() return bogus value... no
checking whether the platform uses typical file type bits... yes
configure: CHECKS for library functions
checking for libgen.h... yes
checking for paths.h... yes
checking for libcharset.h... no
checking for strings.h... (cached) yes
checking for locale_charset in -liconv... no
checking for locale_charset in -lcharset... no
checking for clock_gettime... no
checking for CLOCK_MONOTONIC... yes
checking for sync_file_range... yes
checking for library containing sync_file_range... none required
checking for setitimer... yes
checking for library containing setitimer... none required
checking for strcasestr... yes
checking for library containing strcasestr... none required
checking for memmem... yes
checking for library containing memmem... none required
checking for strlcpy... no
checking for strtoumax... yes
checking for library containing strtoumax... none required
checking for setenv... yes
checking for library containing setenv... none required
checking for unsetenv... yes
checking for library containing unsetenv... none required
checking for mkdtemp... yes
checking for library containing mkdtemp... none required
checking for initgroups... yes
checking for library containing initgroups... none required
checking for getdelim... yes
checking for library containing getdelim... none required
checking for BSD sysctl... no
checking for sysinfo... yes
checking for POSIX Threads with ''... no
checking for POSIX Threads with '-mt'... no
checking for POSIX Threads with '-pthread'... yes
configure: creating ./config.status
config.status: creating config.mak.autogen
config.status: executing config.mak.autogen commands
GIT_VERSION=2.54.0
    * new build flags
    * new link flags
    CC base85.o
    * new prefix flags
    CC bisect.o
    CC blame.o
    CC blob.o
    CC bloom.o
    CC branch.o
    CC bundle-uri.o
    CC bundle.o
    CC cache-tree.o
    CC cbtree.o
    CC chdir-notify.o
    CC checkout.o
    CC chunk-format.o
    CC color.o
    CC column.o
    CC combine-diff.o
    CC commit-graph.o
    CC commit-reach.o
    CC commit.o
    CC common-exit.o
    CC common-init.o
    CC compat/nonblock.o
    CC compat/obstack.o
    CC compat/open.o
    CC compat/terminal.o
    CC compiler-tricks/not-constant.o
    CC config.o
    CC connect.o
    CC connected.o
    CC convert.o
    CC copy.o
    CC credential.o
    CC csum-file.o
    CC ctype.o
    CC date.o
    CC decorate.o
    CC delta-islands.o
    CC diagnose.o
    CC diff-delta.o
    CC diff-merges.o
    CC diff-lib.o
    CC diff-no-index.o
    CC diff.o
    CC diffcore-break.o
    CC diffcore-delta.o
    CC diffcore-order.o
    CC diffcore-pickaxe.o
    CC diffcore-rename.o
    CC diffcore-rotate.o
    CC dir-iterator.o
    CC dir.o
    CC editor.o
    CC entry.o
    CC environment.o
    CC ewah/bitmap.o
    CC ewah/ewah_bitmap.o
    CC ewah/ewah_io.o
    CC ewah/ewah_rlw.o
    CC exec-cmd.o
    CC fetch-negotiator.o
    CC fetch-pack.o
    CC fmt-merge-msg.o
    CC fsck.o
    CC fsmonitor.o
    CC fsmonitor-ipc.o
    CC fsmonitor-settings.o
    CC gettext.o
    CC git-zlib.o
    CC gpg-interface.o
    CC graph.o
    CC grep.o
    CC hash-lookup.o
    CC hash.o
    CC hashmap.o
    GEN command-list.h
    CC hex.o
    CC hex-ll.o
    CC hook.o
    CC ident.o
    CC json-writer.o
    CC kwset.o
    CC levenshtein.o
    CC line-log.o
    CC line-range.o
    CC linear-assignment.o
    CC list-objects-filter-options.o
    CC list-objects-filter.o
    CC list-objects.o
    CC lockfile.o
    CC log-tree.o
    CC loose.o
    CC ls-refs.o
    CC mailinfo.o
    CC mailmap.o
    CC match-trees.o
    CC mem-pool.o
    CC merge-blobs.o
    CC merge-ll.o
    CC merge-ort.o
    CC merge-ort-wrappers.o
    CC merge.o
    CC midx.o
    CC midx-write.o
    CC name-hash.o
    CC negotiator/default.o
    CC negotiator/noop.o
    CC negotiator/skipping.o
    CC notes-cache.o
    CC notes-merge.o
    CC notes-utils.o
    CC notes.o
    CC object-file-convert.o
    CC object-file.o
    CC object-name.o
    CC object.o
    CC odb.o
    CC odb/source.o
    CC odb/source-files.o
    CC odb/streaming.o
    CC oid-array.o
    CC oidmap.o
    CC oidset.o
    CC oidtree.o
    CC pack-bitmap-write.o
    CC pack-bitmap.o
    CC pack-check.o
    CC pack-mtimes.o
    CC pack-objects.o
    CC pack-refs.o
    CC pack-revindex.o
    CC pack-write.o
    CC packfile.o
    CC pager.o
    CC parallel-checkout.o
    CC parse.o
    CC parse-options-cb.o
    CC parse-options.o
    CC patch-delta.o
    CC patch-ids.o
    CC path.o
    CC path-walk.o
    CC pathspec.o
    CC pkt-line.o
    CC preload-index.o
    CC pretty.o
    CC prio-queue.o
    CC progress.o
    CC promisor-remote.o
    CC prompt.o
    CC protocol.o
    CC protocol-caps.o
    CC prune-packed.o
    CC pseudo-merge.o
    CC quote.o
    CC range-diff.o
    CC reachable.o
    CC read-cache.o
    CC rebase-interactive.o
    CC rebase.o
    CC ref-filter.o
    CC reflog-walk.o
    CC reflog.o
    CC refs.o
    CC refs/debug.o
    CC refs/files-backend.o
    CC refs/reftable-backend.o
    CC refs/iterator.o
    CC refs/packed-backend.o
    CC refs/ref-cache.o
    CC refspec.o
    CC reftable/basics.o
    CC reftable/block.o
    CC reftable/blocksource.o
    CC reftable/error.o
    CC reftable/fsck.o
    CC reftable/iter.o
    CC reftable/merged.o
    CC reftable/pq.o
    CC reftable/record.o
    CC reftable/stack.o
    CC reftable/system.o
    CC reftable/table.o
    CC reftable/tree.o
    CC reftable/writer.o
    CC remote.o
    CC repack.o
    CC repack-cruft.o
    CC repack-filtered.o
    CC repack-geometry.o
    CC repack-midx.o
    CC repack-promisor.o
    CC replace-object.o
    CC repo-settings.o
    CC replay.o
    CC repository.o
    CC rerere.o
    CC reset.o
    CC resolve-undo.o
    CC revision.o
    CC run-command.o
    CC send-pack.o
    CC sequencer.o
    CC serve.o
    CC server-info.o
    CC setup.o
    CC shallow.o
    CC sideband.o
    CC sigchain.o
    CC sparse-index.o
    CC split-index.o
    CC stable-qsort.o
    CC statinfo.o
    CC strbuf.o
    CC string-list.o
    CC strmap.o
    CC strvec.o
    CC sub-process.o
    CC submodule-config.o
    CC submodule.o
    CC symlinks.o
    CC tag.o
    CC tempfile.o
    CC thread-utils.o
    CC tmp-objdir.o
    CC trace.o
    CC trace2.o
    CC trace2/tr2_cfg.o
    CC trace2/tr2_cmd_name.o
    CC trace2/tr2_ctr.o
    CC trace2/tr2_dst.o
    CC trace2/tr2_sid.o
    CC trace2/tr2_sysenv.o
    CC trace2/tr2_tbuf.o
    CC trace2/tr2_tgt_event.o
    CC trace2/tr2_tgt_normal.o
    CC trace2/tr2_tgt_perf.o
    CC trace2/tr2_tls.o
    CC trace2/tr2_tmr.o
    CC trailer.o
    CC transport-helper.o
    CC transport.o
    CC tree-diff.o
    CC tree-walk.o
    CC tree.o
    CC unpack-trees.o
    CC upload-pack.o
    CC url.o
    CC urlmatch.o
    CC usage.o
    CC userdiff.o
    CC utf8.o
    CC varint.o
    CC versioncmp.o
    CC walker.o
    CC wildmatch.o
    CC worktree.o
    CC wrapper.o
    CC write-or-die.o
    CC ws.o
    CC wt-status.o
    CC xdiff-interface.o
    CC xdiff/xdiffi.o
    CC xdiff/xemit.o
    CC xdiff/xhistogram.o
    CC xdiff/xmerge.o
    CC xdiff/xpatience.o
    CC xdiff/xprepare.o
    CC xdiff/xutils.o
    CC unix-socket.o
    CC unix-stream-server.o
    CC compat/simple-ipc/ipc-shared.o
    CC compat/simple-ipc/ipc-unix-socket.o
    CC sha1dc_git.o
    CC sha1dc/sha1.o
    CC sha1dc/ubc_check.o
    CC sha256/block/sha256.o
    CC compat/linux/procinfo.o
    CC compat/fopen.o
    CC compat/strlcpy.o
    CC compat/qsort_s.o
    CC http-backend.o
    CC imap-send.o
imap-send.c: In function ‘host_matches’:
imap-send.c:224:45: warning: implicit declaration of function ‘ASN1_STRING_get0_data’; did you mean ‘ASN1_STRING_data’? [-Wimplicit-function-declaration]
  224 |         const char *pattern = (const char *)ASN1_STRING_get0_data(asn1_str);
      |                                             ^~~~~~~~~~~~~~~~~~~~~
      |                                             ASN1_STRING_data
imap-send.c:224:31: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
  224 |         const char *pattern = (const char *)ASN1_STRING_get0_data(asn1_str);
      |                               ^
imap-send.c: In function ‘verify_hostname’:
imap-send.c:274:47: warning: passing argument 1 of ‘X509_NAME_ENTRY_get_data’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
  274 |             (cname = X509_NAME_ENTRY_get_data(cname_entry)) == NULL)
      |                                               ^~~~~~~~~~~
In file included from /usr/include/openssl/ssl.h:156,
                 from git-compat-util.h:193,
                 from imap-send.c:27:
/usr/include/openssl/x509.h:1040:59: note: expected ‘X509_NAME_ENTRY *’ {aka ‘struct X509_name_entry_st *’} but argument is of type ‘const X509_NAME_ENTRY *’ {aka ‘const struct X509_name_entry_st *’}
 1040 | ASN1_STRING *   X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne);
      |                                          ~~~~~~~~~~~~~~~~~^~
    CC http.o
    CC sh-i18n--envsubst.o
    CC shell.o
    CC http-walker.o
    CC http-fetch.o
    CC http-push.o
    CC remote-curl.o
    * new script parameters
    * new perl-specific parameters
    GEN git-p4
    GEN git-instaweb
    CC git.o
    CC builtin/add.o
    CC builtin/am.o
    CC builtin/annotate.o
    CC builtin/apply.o
    CC builtin/archive.o
    CC builtin/backfill.o
    CC builtin/bisect.o
    CC builtin/blame.o
    CC builtin/branch.o
    GEN hook-list.h
    CC builtin/bundle.o
    CC builtin/cat-file.o
    CC builtin/check-attr.o
    CC builtin/check-mailmap.o
    CC builtin/check-ignore.o
    CC builtin/check-ref-format.o
    CC builtin/checkout--worker.o
    CC builtin/checkout-index.o
    CC builtin/checkout.o
    CC builtin/clean.o
    CC builtin/clone.o
    CC builtin/column.o
    CC builtin/commit-graph.o
    CC builtin/commit-tree.o
    CC builtin/commit.o
    CC builtin/config.o
    CC builtin/count-objects.o
    CC builtin/credential-cache--daemon.o
    CC builtin/credential-cache.o
    CC builtin/credential-store.o
    CC builtin/credential.o
    CC builtin/describe.o
    CC builtin/diagnose.o
    CC builtin/diff-files.o
    CC builtin/diff-index.o
    CC builtin/diff-pairs.o
    CC builtin/diff-tree.o
    CC builtin/diff.o
    CC builtin/difftool.o
    CC builtin/fast-export.o
    CC builtin/fast-import.o
    CC builtin/fetch-pack.o
    CC builtin/fetch.o
    CC builtin/fmt-merge-msg.o
    CC builtin/for-each-ref.o
    CC builtin/for-each-repo.o
    CC builtin/fsck.o
    CC builtin/fsmonitor--daemon.o
    CC builtin/gc.o
    CC builtin/get-tar-commit-id.o
    CC builtin/grep.o
    CC builtin/hash-object.o
    GEN config-list.h
    CC builtin/history.o
    CC builtin/hook.o
    CC builtin/index-pack.o
    CC builtin/init-db.o
    CC builtin/interpret-trailers.o
    CC builtin/last-modified.o
    CC builtin/log.o
    CC builtin/ls-files.o
    CC builtin/ls-remote.o
    CC builtin/ls-tree.o
    CC builtin/mailinfo.o
    CC builtin/mailsplit.o
    CC builtin/merge-base.o
    CC builtin/merge-file.o
    CC builtin/merge-index.o
    CC builtin/merge-ours.o
    CC builtin/merge-recursive.o
    CC builtin/merge.o
    CC builtin/merge-tree.o
    CC builtin/mktag.o
    CC builtin/mktree.o
    CC builtin/multi-pack-index.o
    CC builtin/mv.o
    CC builtin/name-rev.o
    CC builtin/notes.o
    CC builtin/pack-objects.o
    CC builtin/pack-redundant.o
    CC builtin/pack-refs.o
    CC builtin/patch-id.o
    CC builtin/prune-packed.o
    CC builtin/prune.o
    CC builtin/pull.o
    CC builtin/push.o
    CC builtin/range-diff.o
    CC builtin/read-tree.o
    CC builtin/rebase.o
    CC builtin/receive-pack.o
    CC builtin/reflog.o
    CC builtin/refs.o
    CC builtin/remote-ext.o
    CC builtin/remote-fd.o
    CC builtin/remote.o
    CC builtin/repack.o
    CC builtin/replace.o
    CC builtin/replay.o
    CC builtin/repo.o
    CC builtin/rerere.o
    CC builtin/reset.o
    CC builtin/rev-list.o
    CC builtin/rev-parse.o
    CC builtin/revert.o
    CC builtin/rm.o
    CC builtin/send-pack.o
    CC builtin/shortlog.o
    CC builtin/show-branch.o
    CC builtin/show-index.o
    CC builtin/show-ref.o
    CC builtin/sparse-checkout.o
    CC builtin/stash.o
    CC builtin/stripspace.o
    CC builtin/submodule--helper.o
    CC builtin/symbolic-ref.o
    CC builtin/tag.o
    CC builtin/unpack-file.o
    CC builtin/unpack-objects.o
    CC builtin/update-index.o
    CC builtin/update-ref.o
    CC builtin/update-server-info.o
    CC builtin/upload-archive.o
    CC builtin/upload-pack.o
    CC builtin/var.o
    CC builtin/verify-commit.o
    CC builtin/verify-pack.o
    CC builtin/verify-tag.o
    CC builtin/worktree.o
    CC builtin/write-tree.o
    GEN git-mergetool--lib
    GEN git-sh-i18n
    GEN git-sh-setup
    CC scalar.o
    CC daemon.o
    CC common-main.o
    CC abspath.o
    CC add-interactive.o
    CC add-patch.o
    CC advice.o
    CC alias.o
    CC alloc.o
    CC apply.o
    CC archive-tar.o
    CC archive-zip.o
    CC archive.o
    CC attr.o
    CC help.o
    GEN version-def.h
    GEN git-difftool--helper
    GEN git-filter-branch
    GEN git-merge-octopus
    GEN git-merge-one-file
    GEN git-merge-resolve
    GEN git-mergetool
    GEN git-quiltimport
    GEN git-request-pull
    GEN git-submodule
    GEN git-web--browse
    GEN GIT-PERL-HEADER
    CC builtin/bugreport.o
    CC builtin/help.o
    CC version.o
    GEN git-cvsexportcommit
    GEN git-archimport
    GEN git-cvsimport
    GEN git-cvsserver
    GEN git-send-email
    GEN git-svn
    AR libgit.a
    LINK git-daemon
    LINK git-http-backend
    LINK git-imap-send
    LINK git-sh-i18n--envsubst
    LINK git-shell
/usr/local/bin/ld: warning: libssl.so.3, needed by /usr/local/lib/libcurl.so, may conflict with libssl.so.10
    LINK git-http-fetch
/usr/local/bin/ld: warning: libcrypto.so.3, needed by /usr/local/lib/libcurl.so,may conflict with libcrypto.so.10
/usr/local/bin/ld: imap-send.o: undefined reference to symbol 'ASN1_STRING_get0_data@@OPENSSL_3.0.0'
/usr/local/bin/ld: /usr/local/openssl/lib/libcrypto.so.3: error adding symbols:DSO missing from command line
collect2: error: ld returned 1 exit status
make: *** [Makefile:3003: git-imap-send] Error 1
make: *** Waiting for unfinished jobs....
 cd ~
[sun] ~# git --version
git version 2.53.0
[sun] ~# git --version^C
[sun] ~# ^C
[sun] ~# openssl version
OpenSSL 3.5.6 7 Apr 2026 (Library: OpenSSL 3.5.6 7 Apr 2026)


^ permalink raw reply

* Re: [PATCH v3 0/8] builtin: implement, document and test url-parse
From: Matheus Afonso Martins Moreira @ 2026-05-03 19:36 UTC (permalink / raw)
  To: Torsten Bögershausen
  Cc: Matheus Moreira via GitGitGadget, git, Ghanshyam Thakkar
In-Reply-To: <20260503172838.GA22957@tb-raspi4>

> Reviewers comment: Nicely done.

Thank you!

> More a question to myself, may be, about t9904 (and may be other parts)
> I have in mind that the parser learned to handle
>
> file://server/share/repo
> correctly under Windows.
> I don't know if this needs to be addressed here or in a follow-up commit ?

I'd be happy to revisit this in a follow-up. It's been a while
since I used MSYS but I do remember the fact it rewrites paths
internally. I wasn't sure how to handle it properly in the tests.

The problematic test case is:

    test_must_fail git url-parse "/abs/path" 2>err &&
      test_grep "is not a URL" err &&
      test_grep "file:///abs/path" err

MSYS bash rewrites /abs/path to C:/Program Files/Git/abs/path
before git even runs. This edge case caused the error message:

    fatal: 'C:/Program Files/Git/abs/path' is not a URL;
    if you meant a local repository, use a 'file://' URL
    with an absolute path

The test_grep "is not a URL" passed but test_grep "file:///abs/path"
failed because the suggestion did not contain the literal string
"file:///abs/path". The drive letter broke the tool's absolute
path recognition: it was printing the generic error message.

The fix was to use has_dos_drive_prefix() to recognize the edge case.
However, that led to the generation of error messages containing paths
that I wasn't sure if I could depend on in the test suite, such as:

    file:///C:/Program Files/Git/abs/path

So I decided to relax the test case just a little:

    test_must_fail git url-parse "/abs/path" 2>err &&
      test_grep "is not a URL" err &&
      test_grep "file:///" err

The "file:///" checks that the path was properly recognized
and that the friendlier error message was printed, all while
avoiding the hard coding of a "C:/Program Files/Git" prefix
that may or may not vary depending on testing environment.

In any case, the parser already handles it correctly.

It decomposes:

    file://server/share/repo

As:

  - scheme: file
  - host:   server
  - path:   /share/repo

Which is the correct interpretation.

On Windows, connect.c then takes that data and reconstructs
the UNC path \\server\share\repo for the filesystem.
So the UNC reconstruction happens downstream in connect.c,
not directly in the url-parse builtin or url_parse logic.

    Matheus

^ permalink raw reply

* Re: [PATCH v3 5/5] format-rev: introduce builtin for on-demand pretty formatting
From: Junio C Hamano @ 2026-05-03 19:19 UTC (permalink / raw)
  To: kristofferhaugsbakk; +Cc: git, Kristoffer Haugsbakk, ben.knoble
In-Reply-To: <V3_format-rev_new_builtin.66f@msgid.xyz>

builtin/name-rev.c:883:8: error: variable 'commit' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
  883 |                         if (peeled && peeled->type == OBJ_COMMIT)
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
builtin/name-rev.c:885:9: note: uninitialized use occurs here
  885 |                         if (!commit) {
      |                              ^~~~~~
builtin/name-rev.c:883:4: note: remove the 'if' if its condition is always true
  883 |                         if (peeled && peeled->type == OBJ_COMMIT)
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  884 |                                 commit = (struct commit *)peeled;
builtin/name-rev.c:883:8: error: variable 'commit' is used uninitialized whenever '&&' condition is false [-Werror,-Wsometimes-uninitialized]
  883 |                         if (peeled && peeled->type == OBJ_COMMIT)
      |                             ^~~~~~
builtin/name-rev.c:885:9: note: uninitialized use occurs here
  885 |                         if (!commit) {
      |                              ^~~~~~
builtin/name-rev.c:883:8: note: remove the '&&' if its condition is always true
  883 |                         if (peeled && peeled->type == OBJ_COMMIT)
      |                             ^~~~~~~~~
builtin/name-rev.c:867:25: note: initialize the variable 'commit' to silence this warning
  867 |                         struct commit *commit;
      |                                              ^
      |                                               = NULL
2 errors generated.
 

^ permalink raw reply

* Re: [PATCH] name-rev: fix an 'may be used uninitialized' error
From: Kristoffer Haugsbakk @ 2026-05-03 18:52 UTC (permalink / raw)
  To: Ramsay Jones; +Cc: GIT Mailing-list, Junio C Hamano
In-Reply-To: <e74a8fd8-0617-46a8-8bef-a454d51a99c1@ramsayjones.plus.com>

On Sun, May 3, 2026, at 17:16, Ramsay Jones wrote:
> Today's seen branch fails to build (with DEVELOPER=1), like so:
>
>       CC builtin/name-rev.o
>   builtin/name-rev.c: In function ‘cmd_format_rev’:
>   builtin/name-rev.c:885:28: error: ‘commit’ may be used uninitialized
> [-Werror=maybe-uninitialized]
>     885 |                         if (!commit) {
>         |                            ^
>   builtin/name-rev.c:867:40: note: ‘commit’ was declared here
>     867 |                         struct commit *commit;
>         |                                        ^~~~~~
>   cc1: all warnings being treated as errors
>   make: *** [Makefile:2932: builtin/name-rev.o] Error 1
>
> This can be fixed in several ways; initialise the 'commit' variable to
> NULL (on line 867), initialise 'commit' to NULL on the line before the
> conditional on line 883, or (as I chose here) initialise the 'commit'
> variable in an else arm of the conditional.
>
> Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
> ---
>
> Hi Kristoffer,
>
> I wrote this patch yesterday, just before I had to go out, and didn't
> get around to sending it to the list. Today, the problem has gone
> away ... (along with the 'kh/name-rev-custom-format' branch)!
>
> Assuming you will be sending a new version soon, ... could you please
> squash this (or similar) into the patch corresponding to commit 5903855b1c
> ("format-rev: introduce builtin for on-demand pretty formatting", 2026-04-29).
>
> Note that I don't think this particular fix is better than any other, it
> was just that my cursor was on that line in vim ... :)
>
> ATB,
> Ramsay Jones

I’ll incorporate it. Thank you!

>
>  builtin/name-rev.c | 2 ++
>  1 file changed, 2 insertions(+)
>
>[snip]

^ permalink raw reply

* Re: [PATCH v3 0/8] builtin: implement, document and test url-parse
From: Torsten Bögershausen @ 2026-05-03 17:28 UTC (permalink / raw)
  To: Matheus Moreira via GitGitGadget; +Cc: git, Ghanshyam Thakkar, Matheus Moreira
In-Reply-To: <pull.1715.v3.git.git.1777699722.gitgitgadget@gmail.com>

> 
> The series consists of eight commits.

Reviewers comment: Nicely done.

> Changes since v2:
> 
>  * Fix Windows CI failure: handle DOS drive prefix in the helpful local-path
>    error. With this, the message for a drive-letter input like C:/repo (or
>    an MSYS-mangled /abs/path that bash rewrites to D:/.../abs/path before
>    git sees it) gets the specific file:///<input> suggestion rather than the
>    generic fallback. No effect on Linux or macOS, since has_dos_drive_prefix
>    is a no-op on non-Windows builds.
> 
>  * t9904: relax the grep on the absolute-path test from the literal
>    file:///abs/path to the structural file:/// (three slashes). The original
>    assertion depended on the input being preserved verbatim, which MSYS does
>    not do. The relaxed grep verifies the structurally meaningful property
>    (specific URL suggestion was produced, not the generic fallback) and runs
>    cross-platform.

More a question to myself, may be, about t9904 (and may be other parts)
I have in mind that the parser learned to handle

file://server/share/repo
correctly under Windows.
I don't know if this needs to be addressed here or in a follow-up commit ?
The \\server\share\repo is an UNC name, which is handled by the
Windows file system, backslashes towards windows must be used (which we do)
and '/' may be used outside Git.


commit ebb8d2c90fb0840a0803935804e37e2205505f23
Author: Torsten Bögershausen <tboegi@web.de>
Date:   Sat Aug 24 15:07:59 2019 -0700

    mingw: support UNC in git clone file://server/share/repo
    
    Extend the parser to accept file://server/share/repo in the way that
    Windows users expect it to be parsed who are used to referring to file
    shares by UNC paths of the form \\server\share\folder.
    
    [jes: tightened check to avoid handling file://C:/some/path as a UNC
    path.]
    
    This closes https://github.com/git-for-windows/git/issues/1264.

^ permalink raw reply

* [RFC PATCH v5 3/3] push: support pushing to a remote group
From: Usman Akinyemi @ 2026-05-03 15:34 UTC (permalink / raw)
  To: usmanakinyemi202; +Cc: christian.couder, git, gitster, me, phillip.wood123, ps
In-Reply-To: <20260503153402.1333220-1-usmanakinyemi202@gmail.com>

`git fetch` accepts a remote group name (configured via `remotes.<name>`
in config) and fetches from each member remote. `git push` has no
equivalent — it only accepts a single remote name.

Teach `git push` to resolve its repository argument through
`add_remote_or_group()`, which was made public in the previous patch,
so that a user can push to all remotes in a group with:

    git push <group>

When the argument resolves to a single remote, the behaviour is
identical to before. When it resolves to a group, each member remote
is pushed in sequence.

The group push path rebuilds the refspec list (`rs`) from scratch for
each member remote so that per-remote push mappings configured via
`remote.<name>.push` are resolved correctly against each specific
remote. Without this, refspec entries would accumulate across iterations
and each subsequent remote would receive a growing list of duplicated
entries.

Mirror detection (`remote->mirror`) is also evaluated per remote using
a copy of the flags, so that a mirror remote in the group cannot set
TRANSPORT_PUSH_FORCE on subsequent non-mirror remotes in the same group.

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
---
 Documentation/git-push.adoc |  80 ++++++++++--
 builtin/push.c              | 251 +++++++++++++++++++++++++++++++-----
 t/meson.build               |   1 +
 t/t5566-push-group.sh       | 160 +++++++++++++++++++++++
 4 files changed, 451 insertions(+), 41 deletions(-)
 create mode 100755 t/t5566-push-group.sh

diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index e5ba3a6742..aa221c3909 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -18,17 +18,28 @@ git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n
 
 DESCRIPTION
 -----------
-
-Updates one or more branches, tags, or other references in a remote
-repository from your local repository, and sends all necessary data
-that isn't already on the remote.
+Updates one or more branches, tags, or other references in one or more
+remote repositories from your local repository, and sends all necessary
+data that isn't already on the remote.
 
 The simplest way to push is `git push <remote> <branch>`.
 `git push origin main` will push the local `main` branch to the `main`
 branch on the remote named `origin`.
 
-The `<repository>` argument defaults to the upstream for the current branch,
-or `origin` if there's no configured upstream.
+You can also push to multiple remotes at once by using a remote group.
+A remote group is a named list of remotes configured via `remotes.<name>`
+in your git config:
+
+	$ git config remotes.all-remotes "origin gitlab backup"
+
+Then `git push all-remotes` will push to `origin`, `gitlab`, and
+`backup` in turn, as if you had run `git push` against each one
+individually.  Each remote is pushed independently using its own
+push mapping configuration. There is a `remotes.<group>` entry in
+the configuration file. (See linkgit:git-config[1]).
+
+The `<repository>` argument defaults to the upstream for the current
+branch, or `origin` if there's no configured upstream.
 
 To decide which branches, tags, or other refs to push, Git uses
 (in order of precedence):
@@ -55,8 +66,10 @@ OPTIONS
 _<repository>_::
 	The "remote" repository that is the destination of a push
 	operation.  This parameter can be either a URL
-	(see the section <<URLS,GIT URLS>> below) or the name
-	of a remote (see the section <<REMOTES,REMOTES>> below).
+	(see the section <<URLS,GIT URLS>> below), the name
+	of a remote (see the section <<REMOTES,REMOTES>> below),
+	or the name of a remote group
+	(see the section <<REMOTE-GROUPS,REMOTE GROUPS>> below).
 
 `<refspec>...`::
 	Specify what destination ref to update with what source object.
@@ -430,6 +443,57 @@ further recursion will occur. In this case, `only` is treated as `on-demand`.
 
 include::urls-remotes.adoc[]
 
+[[REMOTE-GROUPS]]
+REMOTE GROUPS
+-------------
+
+A remote group is a named list of remotes configured via `remotes.<name>`
+in your git config:
+
+	$ git config remotes.all-remotes "r1 r2 r3"
+
+When a group name is given as the `<repository>` argument, the push is
+performed to each member remote in turn.  The defining principle is:
+
+	git push <options> all-remotes <args>
+
+is exactly equivalent to:
+
+	git push <options> r1 <args>
+	git push <options> r2 <args>
+	...
+	git push <options> rN <args>
+
+where r1, r2, ..., rN are the members of `all-remotes`.  No special
+behaviour is added or removed — the group is purely a shorthand for
+running the same push command against each member remote individually.
+
+When pushing to a group of more than one remote, Git spawns a separate
+`git push` subprocess for each member remote in sequence.  Each subprocess
+receives the same flags and refspecs as the original invocation.  This
+means that per-remote push mappings configured via `remote.<name>.push`
+and mirror mode (`remote.<name>.mirror`) are evaluated independently for
+each remote, and a mirror remote in the group cannot affect the push
+behaviour of other non-mirror remotes in the same group.
+
+The `--atomic` option is not supported for group pushes, because atomicity
+can only be guaranteed within a single transport connection to a single
+remote.  Git will refuse the invocation with an error if `--atomic` is
+combined with a group name.
+
+If any member remote fails whether due to a push rejection (e.g. a
+non-fast-forward update, a server-side hook refusing a ref) or a connection
+error (e.g. the repository does not exist, authentication fails, or the
+network is unreachable), Git reports the error and continues pushing to
+the remaining remotes in the group.  The overall exit code is non-zero if
+any member push fails.
+
+This means the user is responsible for ensuring that the sequence of
+individual pushes makes sense. If `git push r1`` would fail for a given
+set of options and arguments, then `git push all-remotes` will fail in
+the same way when it reaches r1. The group push does not do anything
+special to make a failing individual push succeed.
+
 OUTPUT
 ------
 
diff --git a/builtin/push.c b/builtin/push.c
index 7100ffba5d..6021b71d66 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -10,6 +10,7 @@
 #include "config.h"
 #include "environment.h"
 #include "gettext.h"
+#include "hex.h"
 #include "refspec.h"
 #include "run-command.h"
 #include "remote.h"
@@ -544,6 +545,123 @@ static int git_push_config(const char *k, const char *v,
 	return git_default_config(k, v, ctx, NULL);
 }
 
+static int push_multiple(struct string_list *list,
+			 const struct string_list *push_options,
+			 int flags,
+			 int tags,
+			 const char **refspecs,
+			 int refspec_nr)
+{
+	int result = 0;
+	size_t i;
+	struct strvec argv = STRVEC_INIT;
+
+	strvec_push(&argv, "push");
+
+	if (flags & TRANSPORT_PUSH_FORCE)
+		strvec_push(&argv, "--force");
+	if (flags & TRANSPORT_PUSH_DRY_RUN)
+		strvec_push(&argv, "--dry-run");
+	if (flags & TRANSPORT_PUSH_PORCELAIN)
+		strvec_push(&argv, "--porcelain");
+	if (flags & TRANSPORT_PUSH_PRUNE)
+		strvec_push(&argv, "--prune");
+	if (flags & TRANSPORT_PUSH_NO_HOOK)
+		strvec_push(&argv, "--no-verify");
+	if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
+		strvec_push(&argv, "--follow-tags");
+	if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
+		strvec_push(&argv, "--set-upstream");
+	if (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES)
+		strvec_push(&argv, "--force-if-includes");
+	if (flags & TRANSPORT_PUSH_ALL)
+		strvec_push(&argv, "--all");
+	if (flags & TRANSPORT_PUSH_MIRROR)
+		strvec_push(&argv, "--mirror");
+
+	if (flags & TRANSPORT_PUSH_CERT_ALWAYS)
+		strvec_push(&argv, "--signed=yes");
+	else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED)
+		strvec_push(&argv, "--signed=if-asked");
+	if (!thin)
+		strvec_push(&argv, "--no-thin");
+
+	if (deleterefs)
+		strvec_push(&argv, "--delete");
+
+	if (receivepack)
+		strvec_pushf(&argv, "--receive-pack=%s", receivepack);
+	if (verbosity >= 2)
+		strvec_push(&argv, "-v");
+	if (verbosity >= 1)
+		strvec_push(&argv, "-v");
+	else if (verbosity < 0)
+		strvec_push(&argv, "-q");
+	if (progress > 0)
+		strvec_push(&argv, "--progress");
+	else if (progress == 0)
+		strvec_push(&argv, "--no-progress");
+
+	if (family == TRANSPORT_FAMILY_IPV4)
+		strvec_push(&argv, "--ipv4");
+	else if (family == TRANSPORT_FAMILY_IPV6)
+		strvec_push(&argv, "--ipv6");
+
+	if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
+		strvec_push(&argv, "--recurse-submodules=check");
+	else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+		strvec_push(&argv, "--recurse-submodules=on-demand");
+	else if (recurse_submodules == RECURSE_SUBMODULES_ONLY)
+		strvec_push(&argv, "--recurse-submodules=only");
+	else if (recurse_submodules == RECURSE_SUBMODULES_OFF)
+		strvec_push(&argv, "--recurse-submodules=no");
+
+
+	if (tags)
+		strvec_push(&argv, "--tags");
+
+	for (i = 0; i < push_options->nr; i++)
+		strvec_pushf(&argv, "--push-option=%s",
+			     push_options->items[i].string);
+
+	for (i = 0; i < cas.nr; i++) {
+		if (cas.entry[i].use_tracking) {
+			strvec_pushf(&argv, "--force-with-lease=%s",
+				     cas.entry[i].refname);
+		} else if (!is_null_oid(&cas.entry[i].expect)) {
+			strvec_pushf(&argv, "--force-with-lease=%s:%s",
+				     cas.entry[i].refname,
+				     oid_to_hex(&cas.entry[i].expect));
+		} else {
+			strvec_push(&argv, "--force-with-lease");
+		}
+	}
+
+	for (i = 0; i < list->nr; i++) {
+		const char *name = list->items[i].string;
+		struct child_process cmd = CHILD_PROCESS_INIT;
+		int j;
+
+		strvec_pushv(&cmd.args, argv.v);
+		strvec_push(&cmd.args, name);
+
+		for (j = 0; j < refspec_nr; j++)
+			strvec_push(&cmd.args, refspecs[j]);
+
+		if (verbosity >= 0)
+			printf(_("Pushing to %s\n"), name);
+
+		cmd.git_cmd = 1;
+		if (run_command(&cmd)) {
+			error(_("could not push to %s"), name);
+			result = 1;
+		}
+	}
+
+	strvec_clear(&argv);
+	return result;
+}
+
 int cmd_push(int argc,
 	     const char **argv,
 	     const char *prefix,
@@ -552,12 +670,13 @@ int cmd_push(int argc,
 	int flags = 0;
 	int tags = 0;
 	int push_cert = -1;
-	int rc;
+	int rc = 0;
+	int base_flags;
 	const char *repo = NULL;	/* default repository */
 	struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
+	struct string_list remote_group = STRING_LIST_INIT_DUP;
 	struct string_list *push_options;
 	const struct string_list_item *item;
-	struct remote *remote;
 
 	struct option options[] = {
 		OPT__VERBOSITY(&verbosity),
@@ -620,39 +739,45 @@ int cmd_push(int argc,
 	else if (recurse_submodules == RECURSE_SUBMODULES_ONLY)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
 
-	if (tags)
-		refspec_append(&rs, "refs/tags/*");
-
 	if (argc > 0)
 		repo = argv[0];
 
-	remote = pushremote_get(repo);
-	if (!remote) {
-		if (repo)
-			die(_("bad repository '%s'"), repo);
-		die(_("No configured push destination.\n"
-		    "Either specify the URL from the command-line or configure a remote repository using\n"
-		    "\n"
-		    "    git remote add <name> <url>\n"
-		    "\n"
-		    "and then push using the remote name\n"
-		    "\n"
-		    "    git push <name>\n"));
-	}
-
-	if (argc > 0)
-		set_refspecs(argv + 1, argc - 1, remote);
-
-	if (remote->mirror)
-		flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
-
-	if (flags & TRANSPORT_PUSH_ALL) {
-		if (argc >= 2)
-			die(_("--all can't be combined with refspecs"));
-	}
-	if (flags & TRANSPORT_PUSH_MIRROR) {
-		if (argc >= 2)
-			die(_("--mirror can't be combined with refspecs"));
+	if (repo) {
+		if (!add_remote_or_group(repo, &remote_group)) {
+			/*
+			 * Not a configured remote name or group name.
+			 * Try treating it as a direct URL or path, e.g.
+			 *   git push /tmp/foo.git
+			 *   git push https://github.com/user/repo.git
+			 * pushremote_get() creates an anonymous remote
+			 * from the URL so the loop below can handle it
+			 * identically to a named remote.
+			 */
+			struct remote *r = pushremote_get(repo);
+			if (!r)
+				die(_("bad repository '%s'"), repo);
+			string_list_append(&remote_group, r->name);
+		}
+	} else {
+		struct remote *r = pushremote_get(NULL);
+		if (!r)
+			die(_("No configured push destination.\n"
+			    "Either specify the URL from the command-line or configure a remote repository using\n"
+			    "\n"
+			    "    git remote add <name> <url>\n"
+			    "\n"
+			    "and then push using the remote name\n"
+			    "\n"
+			    "    git push <name>\n"
+			    "\n"
+			    "To push to multiple remotes at once, configure a remote group using\n"
+			    "\n"
+			    "    git config remotes.<groupname> \"<remote1> <remote2>\"\n"
+			    "\n"
+			    "and then push using the group name\n"
+			    "\n"
+			    "    git push <groupname>\n"));
+		string_list_append(&remote_group, r->name);
 	}
 
 	if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
@@ -662,10 +787,70 @@ int cmd_push(int argc,
 		if (strchr(item->string, '\n'))
 			die(_("push options must not have new line characters"));
 
-	rc = do_push(flags, push_options, remote);
+	if (remote_group.nr == 1) {
+		/*
+		 * Single remote (the common case): run do_push() directly
+		 * in this process.  The loop runs exactly once.
+		 *
+		 * Mirror detection and the --mirror/--all + refspec conflict
+		 * checks are done here.  rs is rebuilt so that per-remote push
+		 * mappings (remote.NAME.push config) are resolved against the
+		 * correct remote.  inner_flags is a snapshot of flags so that a
+		 * mirror remote cannot bleed TRANSPORT_PUSH_FORCE into any
+		 * subsequent call.
+		 */
+		base_flags = flags;
+		{
+			int inner_flags = base_flags;
+			struct remote *r = pushremote_get(remote_group.items[0].string);
+			if (!r)
+				die(_("no such remote or remote group: %s"),
+				    remote_group.items[0].string);
+
+			if (r->mirror)
+				inner_flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
+
+			if (inner_flags & TRANSPORT_PUSH_ALL) {
+				if (argc >= 2)
+					die(_("--all can't be combined with refspecs"));
+			}
+			if (inner_flags & TRANSPORT_PUSH_MIRROR) {
+				if (argc >= 2)
+					die(_("--mirror can't be combined with refspecs"));
+			}
+
+			refspec_clear(&rs);
+			rs = (struct refspec) REFSPEC_INIT_PUSH;
+
+			if (tags)
+				refspec_append(&rs, "refs/tags/*");
+			if (argc > 0)
+				set_refspecs(argv + 1, argc - 1, r);
+
+			rc = do_push(inner_flags, push_options, r);
+		}
+	} else {
+		/*
+		 * Multiple remotes: spawn one "git push <remote> [<refspecs>]"
+		 * subprocess per remote, sequentially.
+		 *
+		 * Options that only make sense for a single transport connection
+		 * are rejected here.
+		 */
+		if (flags & TRANSPORT_PUSH_ATOMIC)
+			die(_("--atomic can only be used when pushing to one remote"));
+
+		rc = push_multiple(&remote_group, push_options, flags,
+				   tags,
+				   argc > 1 ? argv + 1 : NULL,
+				   argc > 1 ? argc - 1 : 0);
+	}
+
 	string_list_clear(&push_options_cmdline, 0);
 	string_list_clear(&push_options_config, 0);
+	string_list_clear(&remote_group, 0);
 	clear_cas_option(&cas);
+
 	if (rc == -1)
 		usage_with_options(push_usage, options);
 	else
diff --git a/t/meson.build b/t/meson.build
index 7528e5cda5..bd090627e9 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -704,6 +704,7 @@ integration_tests = [
   't5563-simple-http-auth.sh',
   't5564-http-proxy.sh',
   't5565-push-multiple.sh',
+  't5566-push-group.sh',
   't5570-git-daemon.sh',
   't5571-pre-push-hook.sh',
   't5572-pull-submodule.sh',
diff --git a/t/t5566-push-group.sh b/t/t5566-push-group.sh
new file mode 100755
index 0000000000..a7d59352b1
--- /dev/null
+++ b/t/t5566-push-group.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+test_description='push to remote group'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=default
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	for i in 1 2 3
+	do
+		git init --bare dest-$i.git &&
+		git -C dest-$i.git symbolic-ref HEAD refs/heads/not-a-branch ||
+		return 1
+	done &&
+	test_tick &&
+	git commit --allow-empty -m "initial" &&
+	git config set remote.remote-1.url "file://$(pwd)/dest-1.git" &&
+	git config set remote.remote-1.fetch "+refs/heads/*:refs/remotes/remote-1/*" &&
+	git config set remote.remote-2.url "file://$(pwd)/dest-2.git" &&
+	git config set remote.remote-2.fetch "+refs/heads/*:refs/remotes/remote-2/*" &&
+	git config set remote.remote-3.url "file://$(pwd)/dest-3.git" &&
+	git config set remote.remote-3.fetch "+refs/heads/*:refs/remotes/remote-3/*" &&
+	git config set remotes.all-remotes "remote-1 remote-2 remote-3"
+'
+
+test_expect_success 'push to remote group updates all members correctly' '
+	git push all-remotes HEAD:refs/heads/main &&
+	git rev-parse HEAD >expect &&
+	for i in 1 2 3
+	do
+		git -C dest-$i.git rev-parse refs/heads/main >actual ||
+		return 1
+		test_cmp expect actual || return 1
+	done
+'
+
+test_expect_success 'push second commit to group updates all members' '
+	test_tick &&
+	git commit --allow-empty -m "second" &&
+	git push all-remotes HEAD:refs/heads/main &&
+	git rev-parse HEAD >expect &&
+	for i in 1 2 3
+	do
+		git -C dest-$i.git rev-parse refs/heads/main >actual ||
+		return 1
+		test_cmp expect actual || return 1
+	done
+'
+
+test_expect_success 'push to single remote in group does not affect others' '
+	test_tick &&
+	git commit --allow-empty -m "third" &&
+	git push remote-1 HEAD:refs/heads/main &&
+	git -C dest-1.git rev-parse refs/heads/main >hash-after-1 &&
+	git -C dest-2.git rev-parse refs/heads/main >hash-after-2 &&
+	! test_cmp hash-after-1 hash-after-2
+'
+
+test_expect_success 'mirror remote in group with refspec fails' '
+	git config set remote.remote-1.mirror true &&
+	test_must_fail git push all-remotes HEAD:refs/heads/main 2>err &&
+	test_grep "mirror" err &&
+	git config unset remote.remote-1.mirror
+'
+
+test_expect_success 'push.default=current works with group push' '
+	git config set push.default current &&
+	test_tick &&
+	git commit --allow-empty -m "fifth" &&
+	git push all-remotes &&
+	git config unset push.default
+'
+
+test_expect_success '--atomic is rejected for group push' '
+	test_must_fail git push --atomic all-remotes HEAD:refs/heads/main 2>err &&
+	test_grep "atomic" err
+'
+
+test_expect_success 'push continues past rejection to remaining remotes' '
+	for i in c1 c2 c3
+	do
+		git init --bare dest-$i.git || return 1
+	done &&
+	git config set remote.c1.url "file://$(pwd)/dest-c1.git" &&
+	git config set remote.c2.url "file://$(pwd)/dest-c2.git" &&
+	git config set remote.c3.url "file://$(pwd)/dest-c3.git" &&
+	git config set remotes.continue-group "c1 c2 c3" &&
+
+	test_tick &&
+	git commit --allow-empty -m "base for continue test" &&
+
+	# initial sync
+	git push continue-group HEAD:refs/heads/main &&
+
+	# advance c2 independently
+	git clone dest-c2.git tmp-c2 &&
+	(
+		cd tmp-c2 &&
+		git checkout -b main origin/main &&
+		test_commit c2_independent &&
+		git push origin HEAD:refs/heads/main
+	) &&
+	rm -rf tmp-c2 &&
+
+	test_tick &&
+	git commit --allow-empty -m "local diverging commit" &&
+
+	# push: c2 rejects, others succeed
+	test_must_fail git push continue-group HEAD:refs/heads/main &&
+
+	git rev-parse HEAD >expect &&
+	git -C dest-c1.git rev-parse refs/heads/main >actual-c1 &&
+	git -C dest-c3.git rev-parse refs/heads/main >actual-c3 &&
+	test_cmp expect actual-c1 &&
+	test_cmp expect actual-c3 &&
+
+	# c2 should not have the new commit
+	git -C dest-c2.git rev-parse refs/heads/main >actual-c2 &&
+	! test_cmp expect actual-c2
+'
+
+test_expect_success 'fatal connection error does not stop remaining remotes' '
+	for i in f1 f2 f3
+	do
+		git init --bare dest-$i.git || return 1
+	done &&
+	git config set remote.f1.url "file://$(pwd)/dest-f1.git" &&
+	git config set remote.f2.url "file://$(pwd)/dest-f2.git" &&
+	git config set remote.f3.url "file://$(pwd)/dest-f3.git" &&
+	git config set remotes.fatal-group "f1 f2 f3" &&
+
+	test_tick &&
+	git commit --allow-empty -m "base for fatal test" &&
+
+	# initial sync
+	git push fatal-group HEAD:refs/heads/main &&
+
+	# break f2
+	git config set remote.f2.url "file:///tmp/does-not-exist-$$" &&
+
+	test_tick &&
+	git commit --allow-empty -m "after fatal setup" &&
+
+	# overall exit code is non-zero because f2 failed
+	test_must_fail git push fatal-group HEAD:refs/heads/main &&
+
+	git rev-parse HEAD >expect &&
+
+	# f1 and f3 should both have the new commit — subprocesses are independent
+	git -C dest-f1.git rev-parse refs/heads/main >actual-f1 &&
+	test_cmp expect actual-f1 &&
+	git -C dest-f3.git rev-parse refs/heads/main >actual-f3 &&
+	test_cmp expect actual-f3 &&
+
+	git config set remote.f2.url "file://$(pwd)/dest-f2.git"
+'
+
+test_done
-- 
2.53.0


^ permalink raw reply related

* [RFC PATCH v5 2/3] remote: move remote group resolution to remote.c
From: Usman Akinyemi @ 2026-05-03 15:34 UTC (permalink / raw)
  To: usmanakinyemi202; +Cc: christian.couder, git, gitster, me, phillip.wood123, ps
In-Reply-To: <20260503153402.1333220-1-usmanakinyemi202@gmail.com>

`get_remote_group`, `add_remote_or_group`, and the `remote_group_data`
struct are currently defined as static helpers inside builtin/fetch.c.
They implement generic remote group resolution that is not specific to
fetch — they parse `remotes.<name>` config entries and resolve a name
to either a list of group members or a single configured remote.

Move them to remote.c and declare them in remote.h so that other
builtins can use the same logic without duplication.

Useful for the next patch.

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
---
 builtin/fetch.c | 42 ------------------------------------------
 remote.c        | 37 +++++++++++++++++++++++++++++++++++++
 remote.h        | 12 ++++++++++++
 3 files changed, 49 insertions(+), 42 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index a22c319467..cfb26eb284 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -2138,48 +2138,6 @@ static int get_one_remote_for_fetch(struct remote *remote, void *priv)
 	return 0;
 }
 
-struct remote_group_data {
-	const char *name;
-	struct string_list *list;
-};
-
-static int get_remote_group(const char *key, const char *value,
-			    const struct config_context *ctx UNUSED,
-			    void *priv)
-{
-	struct remote_group_data *g = priv;
-
-	if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) {
-		/* split list by white space */
-		while (*value) {
-			size_t wordlen = strcspn(value, " \t\n");
-
-			if (wordlen >= 1)
-				string_list_append_nodup(g->list,
-						   xstrndup(value, wordlen));
-			value += wordlen + (value[wordlen] != '\0');
-		}
-	}
-
-	return 0;
-}
-
-static int add_remote_or_group(const char *name, struct string_list *list)
-{
-	int prev_nr = list->nr;
-	struct remote_group_data g;
-	g.name = name; g.list = list;
-
-	repo_config(the_repository, get_remote_group, &g);
-	if (list->nr == prev_nr) {
-		struct remote *remote = remote_get(name);
-		if (!remote_is_configured(remote, 0))
-			return 0;
-		string_list_append(list, remote->name);
-	}
-	return 1;
-}
-
 static void add_options_to_argv(struct strvec *argv,
 				const struct fetch_config *config)
 {
diff --git a/remote.c b/remote.c
index a664cd166a..7133d29332 100644
--- a/remote.c
+++ b/remote.c
@@ -2114,6 +2114,43 @@ int get_fetch_map(const struct ref *remote_refs,
 	return 0;
 }
 
+int get_remote_group(const char *key, const char *value,
+			    const struct config_context *ctx UNUSED,
+			    void *priv)
+{
+	struct remote_group_data *g = priv;
+
+	if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) {
+		/* split list by white space */
+		while (*value) {
+			size_t wordlen = strcspn(value, " \t\n");
+
+			if (wordlen >= 1)
+				string_list_append_nodup(g->list,
+						   xstrndup(value, wordlen));
+			value += wordlen + (value[wordlen] != '\0');
+		}
+	}
+
+	return 0;
+}
+
+int add_remote_or_group(const char *name, struct string_list *list)
+{
+	int prev_nr = list->nr;
+	struct remote_group_data g;
+	g.name = name; g.list = list;
+
+	repo_config(the_repository, get_remote_group, &g);
+	if (list->nr == prev_nr) {
+		struct remote *remote = remote_get(name);
+		if (!remote_is_configured(remote, 0))
+			return 0;
+		string_list_append(list, remote->name);
+	}
+	return 1;
+}
+
 int resolve_remote_symref(struct ref *ref, struct ref *list)
 {
 	if (!ref->symref)
diff --git a/remote.h b/remote.h
index 741d14a9fc..7915be3111 100644
--- a/remote.h
+++ b/remote.h
@@ -347,6 +347,18 @@ int branch_has_merge_config(struct branch *branch);
 
 int branch_merge_matches(struct branch *, int n, const char *);
 
+/* list of the remote in a group as configured */
+struct remote_group_data {
+	const char *name;
+	struct string_list *list;
+};
+
+int get_remote_group(const char *key, const char *value,
+                    const struct config_context *ctx,
+                    void *priv);
+
+int add_remote_or_group(const char *name, struct string_list *list);
+
 /**
  * Return the fully-qualified refname of the tracking branch for `branch`.
  * I.e., what "branch@{upstream}" would give you. Returns NULL if no
-- 
2.53.0


^ permalink raw reply related

* [RFC PATCH v5 1/3] remote: fix sign-compare warnings in push_cas_option
From: Usman Akinyemi @ 2026-05-03 15:34 UTC (permalink / raw)
  To: usmanakinyemi202; +Cc: christian.couder, git, gitster, me, phillip.wood123, ps
In-Reply-To: <20260503153402.1333220-1-usmanakinyemi202@gmail.com>

Replace `int` with `size_t` for `nr` and `alloc` in
`struct push_cas_option` to avoid -Werror=sign-compare
warnings when comparing against size-based values.

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
---
 remote.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/remote.h b/remote.h
index fc052945ee..741d14a9fc 100644
--- a/remote.h
+++ b/remote.h
@@ -418,8 +418,8 @@ struct push_cas_option {
 		unsigned use_tracking:1;
 		char *refname;
 	} *entry;
-	int nr;
-	int alloc;
+	size_t nr;
+	size_t alloc;
 };
 
 int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
-- 
2.53.0


^ permalink raw reply related

* [RFC PATCH v5 0/3] push: add support for pushing to remote groups
From: Usman Akinyemi @ 2026-05-03 15:33 UTC (permalink / raw)
  To: usmanakinyemi202; +Cc: christian.couder, git, gitster, me, phillip.wood123, ps
In-Reply-To: <20260427140530.856125-1-usmanakinyemi202@gmail.com>

This RFC series adds support for `git push` to accept a remote group
name (as configured via `remotes.<name>` in config) in addition to a
single remote name, mirroring the behaviour that `git fetch` has
supported for some time.

A user with multiple remotes configured as a group can now do:

    git push all-remotes

instead of pushing to each remote individually, in the same way that:

    git fetch all-remotes

already works.

The series is split into two patches:

  - Patch 1 moves `get_remote_group`, `add_remote_or_group`, and the
    `remote_group_data` struct out of builtin/fetch.c and into
    remote.c/remote.h, making them part of the public remote API.

  - Patch 2 extends builtin/push.c to use the newly public
    `add_remote_or_group()` to resolve the repository argument as
    either a single remote or a group, and pushes to each member of
    the group in turn.

Changes in v5:
- fixed the -Werror=sign-compare in builtin/push.c complaints and also added
  a new commit that fix the remote.h

Range-diff v4 -> v5:
-:  ---------- > 1:  e01126890c remote: fix sign-compare warnings in push_cas_option
1:  20ed79546f = 2:  adbce652e6 remote: move remote group resolution to remote.c
2:  964694e587 ! 3:  a8d5f4b7bd push: support pushing to a remote group
    @@ builtin/push.c: static int git_push_config(const char *k, const char *v,
     +			 const char **refspecs,
     +			 int refspec_nr)
     +{
    -+	int i, result = 0;
    ++	int result = 0;
    ++	size_t i;
     +	struct strvec argv = STRVEC_INIT;
     +
     +	strvec_push(&argv, "push");

Usman Akinyemi (3):
  remote: fix sign-compare warnings in push_cas_option
  remote: move remote group resolution to remote.c
  push: support pushing to a remote group

 Documentation/git-push.adoc |  80 ++++++++++--
 builtin/fetch.c             |  42 ------
 builtin/push.c              | 251 +++++++++++++++++++++++++++++++-----
 remote.c                    |  37 ++++++
 remote.h                    |  16 ++-
 t/meson.build               |   1 +
 t/t5566-push-group.sh       | 160 +++++++++++++++++++++++
 7 files changed, 502 insertions(+), 85 deletions(-)
 create mode 100755 t/t5566-push-group.sh

-- 
2.53.0


^ permalink raw reply

* [PATCH] compat/posix.h: enable UNUSED warning messages for Clang
From: Dominik Loidolt @ 2026-05-03 15:12 UTC (permalink / raw)
  To: git
  Cc: Dominik Loidolt, Alejandro R Sedeño,
	Alejandro R. Sedeño, Ævar Arnfjörð Bjarmason,
	Junio C Hamano

Treat Clang like GCC 4.5+ so using an UNUSED parameter emits the
intended warning message.

Commit 7c07f36ad2 (git-compat-util.h: GCC deprecated message arg only in
GCC 4.5+, 2022-10-05) restricted use of the deprecated attribute's
message argument in the UNUSED macro to GCC 4.5 or newer.

Clang identifies itself as GNUC 4.2.1 for compatibility, causing the
current check to use the deprecated attribute without a message, even
though Clang supports deprecated("...") since version 2.9 (2011).

Signed-off-by: Dominik Loidolt <dominik.loidolt@univie.ac.at>
---
I am not familiar with git's minimum compiler version but this patch
drops support for Clang < 2.9 from 2011.

Dominik
P.S. This is my first patch sent by email. Please let me know if I
missed something.

 compat/posix.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compat/posix.h b/compat/posix.h
index 245386fa4a..ed83a4d9d4 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -35,7 +35,7 @@
  * When a parameter may be used or unused, depending on conditional
  * compilation, consider using MAYBE_UNUSED instead.
  */
-#if GIT_GNUC_PREREQ(4, 5)
+#if GIT_GNUC_PREREQ(4, 5) || defined(__clang__)
 #define UNUSED __attribute__((unused)) \
 	__attribute__((deprecated ("parameter declared as UNUSED")))
 #elif defined(__GNUC__)

base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
--
2.54.0


^ permalink raw reply related

* [PATCH] name-rev: fix an 'may be used uninitialized' error
From: Ramsay Jones @ 2026-05-03 15:16 UTC (permalink / raw)
  To: Kristoffer Haugsbakk; +Cc: GIT Mailing-list, Junio C Hamano


Today's seen branch fails to build (with DEVELOPER=1), like so:

      CC builtin/name-rev.o
  builtin/name-rev.c: In function ‘cmd_format_rev’:
  builtin/name-rev.c:885:28: error: ‘commit’ may be used uninitialized [-Werror=maybe-uninitialized]
    885 |                         if (!commit) {
        |                            ^
  builtin/name-rev.c:867:40: note: ‘commit’ was declared here
    867 |                         struct commit *commit;
        |                                        ^~~~~~
  cc1: all warnings being treated as errors
  make: *** [Makefile:2932: builtin/name-rev.o] Error 1

This can be fixed in several ways; initialise the 'commit' variable to
NULL (on line 867), initialise 'commit' to NULL on the line before the
conditional on line 883, or (as I chose here) initialise the 'commit'
variable in an else arm of the conditional.

Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
---

Hi Kristoffer,

I wrote this patch yesterday, just before I had to go out, and didn't
get around to sending it to the list. Today, the problem has gone
away ... (along with the 'kh/name-rev-custom-format' branch)!

Assuming you will be sending a new version soon, ... could you please
squash this (or similar) into the patch corresponding to commit 5903855b1c
("format-rev: introduce builtin for on-demand pretty formatting", 2026-04-29).

Note that I don't think this particular fix is better than any other, it
was just that my cursor was on that line in vim ... :)

ATB,
Ramsay Jones

 builtin/name-rev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index b941e93834..5b7f7a00e5 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -882,6 +882,8 @@ int cmd_format_rev(int argc,
 			peeled = deref_tag(the_repository, object, scratch_buf.buf, 0);
 			if (peeled && peeled->type == OBJ_COMMIT)
 				commit = (struct commit *)peeled;
+			else
+				commit = NULL;
 			if (!commit) {
 				fprintf(stderr, "Could not get commit for %s. Skipping.\n",
 					*argv);
-- 
2.54.0

^ permalink raw reply related

* Re: [PATCH 4/6] delta, packfile: use size_t for delta header sizes
From: Johannes Schindelin @ 2026-05-03 14:49 UTC (permalink / raw)
  To: Derrick Stolee; +Cc: Johannes Schindelin via GitGitGadget, git
In-Reply-To: <1b2ce8fe-7c99-4dde-ae07-1443d03cf523@gmail.com>

Hi Stolee,

On Sun, 3 May 2026, Derrick Stolee wrote:

> On 4/28/26 12:26 PM, Johannes Schindelin via GitGitGadget wrote:
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> > 
> > The delta header decoding functions return unsigned long, which
> > truncates on Windows for objects larger than 4GB. Introduce size_t
> > variants get_delta_hdr_size_sz() and get_size_from_delta_sz() that
> > preserve the full 64-bit size, and use them in packed_object_info()
> > where the size is needed for streaming decisions.
> 
> > + * Size_t variant that doesn't truncate - use for >4GB objects on Windows.
> > + */
> > +static inline size_t get_delta_hdr_size_sz(const unsigned char **datap,
> > +					   const unsigned char *top)
> ...
> > +static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
> > +					       const unsigned char *top)
> > +{
> > +	size_t size = get_delta_hdr_size_sz(datap, top);
> >   	return cast_size_t_to_ulong(size);
> >   }
> 
> I like this trick to use the 64-bit implementation and only to
> down-cast for API compatibility. This allows a more gradual
> transition than if we replaced ulongs with size_ts everywhere
> at once.

Thank you! That was indeed the exact thing I wanted to achieve: To allow
for incremental, easy-to-review patch series.

Ciao,
Johannes

^ permalink raw reply

* Re: [PATCH 1/6] index-pack, unpack-objects: use size_t for object size
From: Johannes Schindelin @ 2026-05-03 14:46 UTC (permalink / raw)
  To: Torsten Bögershausen; +Cc: Johannes Schindelin via GitGitGadget, git
In-Reply-To: <20260430141320.GA6659@tb-raspi4>

[-- Attachment #1: Type: text/plain, Size: 2277 bytes --]

Hi Torsten,

On Sun, 3 May 2026, Torsten Bögershausen wrote:

> On Tue, Apr 28, 2026 at 04:26:15PM +0000, Johannes Schindelin via GitGitGadget wrote:
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> > 
> > When unpacking objects from a packfile, the object size is decoded
> > from a variable-length encoding. On platforms where unsigned long is
> > 32-bit (such as Windows, even in 64-bit builds), the shift operation
> > overflows when decoding sizes larger than 4GB. The result is a
> > truncated size value, causing the unpacked object to be corrupted or
> > rejected.
> > 
> > Fix this by changing the size variable to size_t, which is 64-bit on
> > 64-bit platforms, and ensuring the shift arithmetic occurs in 64-bit
> > space.
> > 
> > This was originally authored by LordKiRon
> > <https://github.com/LordKiRon>, who preferred not to reveal their real
> > name and therefore agreed that I take over authorship.
> 
> Good to see things moving forward.
> 
> See even
> https://github.com/git-for-windows/git/pull/2179
> which is probably obsolete soon.

The word "probably" is maybe a bit overwhelmed in this sentence by the
sheer extent of what still needs to be done.

There have been multiple contributors who despaired over the task [*1*] to
split this PR apart in ways that would stand a chance to be accepted (or
for that matter: reviewed) on the Git mailing list...

But yes, it is my hope that I can wittle down that PR into more
contributions along the lines of f9ba6acaa934 (Merge branch
'mc/clean-smudge-with-llp64', 2021-11-29). I still have to upstream
https://github.com/git-for-windows/git/pull/3533, which is another teeny
tiny step toward completing what the PR you mentioned set out to
accomplish.

And yes, the pattern that Stolee already recognized, to duplicate function
signatures into the ones that the 20th century kindly asked to be returned
and the ones using `size_t` instead, this is the pattern I specifically
wanted to use so that incremental patch series have a chance of getting
reviews and to trickle into git/git.

Ciao,
Johannes

Footnote *1*: I specifically asked for this kind of splitting-out:
https://github.com/git-for-windows/git/pull/2179#issuecomment-525926366

^ permalink raw reply

* [GSoC] Welcoming our 2026 contributors and thanking our applicants
From: Kaartic Sivaraam @ 2026-05-03 14:28 UTC (permalink / raw)
  To: Git Users
  Cc: JAYATHEERTH K, Pablo Sabater, Siddharth Shrimali, Tian Yuchen,
	Christian Couder, karthik nayak, Lucas Seiki Oshiro,
	Justin Tobler, Siddharth Asthana, Chandra Pratap, Ayush Chandekar,
	Patrick Steinhardt, Junio C Hamano

Hello all,

As you may be aware, the results for GSoC 2026 have been officially
announced[1]. We have 4 contributors contributing to Git this year[2].
They are as follows (in no particular order):

  - K Jayatheerth

    Project: Improve the new git repo command [3]
    Mentors: Justin Tobler, Lucas Oshiro

  - Pablo Sabater

    Project: Complete and extend the remote-object-info command for
git cat-file [4]
    Mentors: Karthik Nayak, Chandra Pratap

  - Siddharth Shrimali

    Project: Improve Disk Space Recovery for Partial Clones [5]
    Mentors: Christian Couder, Siddharth Asthana

  - Tian Yuchen

    Project: Refactoring in order to reduce Git’s global state [6]
    Mentors: Christian Couder, Ayush Chandekar

Let us welcome them and wish them a good summer of contributing to Git
via GSoC!

Thank you to all the contributors who applied to Git this year! It was
a bit tough to choose from multiple potential contributors who all were good
in their own respect. Hoping to see you around continuing your
contributions to the Git community in some way :-)

Also many thanks to all the mentors who were willing to spend their valuable
time mentoring the students this summer. Very much appreciated! Special
mention to Ayush, Lucas and Chandra who were GSoC participants in previous
years and have volunteered to mentor this year.

[[ References ]]

[1]: https://opensource.googleblog.com/2026/04/the-journey-begins-meet-the-2026-gsoc-contributors.html
[2]: https://summerofcode.withgoogle.com/programs/2026/organizations/git
[3]: https://summerofcode.withgoogle.com/organizations/git/projects/details/O1nF3zMT
[4]: https://summerofcode.withgoogle.com/organizations/git/projects/details/752yzmwm
[5]: https://summerofcode.withgoogle.com/organizations/git/projects/details/hs14IFAn
[6]: https://summerofcode.withgoogle.com/organizations/git/projects/details/Lx1PmL4k

--
Sivaraam

^ permalink raw reply

* [PATCH v3] submodule-config: fix reading submodule.fetchJobs
From: Saagar Jha via GitGitGadget @ 2026-05-03 13:52 UTC (permalink / raw)
  To: git; +Cc: Pablo, Saagar Jha, Saagar Jha
In-Reply-To: <pull.2287.v2.git.git.1777809430925.gitgitgadget@gmail.com>

From: Saagar Jha <saagar@saagarjha.com>

update_clone_config_from_gitmodules() passes &max_jobs to
config_from_gitmodules(), but max_jobs is already a pointer. This causes
the config value to be written to the wrong address and get dropped.

Pass max_jobs directly.

Signed-off-by: Saagar Jha <saagar@saagarjha.com>
---
    submodule-config: fix reading submodule.fetchJobs

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2287%2Fsaagarjha%2Fmaint-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2287/saagarjha/maint-v3
Pull-Request: https://github.com/git/git/pull/2287

Range-diff vs v2:

 1:  868901f1a6 ! 1:  70fb2ede0f submodule-config: fix reading submodule.fetchJobs
     @@ Metadata
       ## Commit message ##
          submodule-config: fix reading submodule.fetchJobs
      
     -    The old code accidentally passed &max_jobs rather than max_jobs into
     -    config_from_gitmodules, which caused the setting to be written to the
     -    wrong place and dropped.
     +    update_clone_config_from_gitmodules() passes &max_jobs to
     +    config_from_gitmodules(), but max_jobs is already a pointer. This causes
     +    the config value to be written to the wrong address and get dropped.
     +
     +    Pass max_jobs directly.
      
          Signed-off-by: Saagar Jha <saagar@saagarjha.com>
      


 submodule-config.c          |  2 +-
 t/t7406-submodule-update.sh | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/submodule-config.c b/submodule-config.c
index 1f19fe2077..57b190678e 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -1037,5 +1037,5 @@ static int gitmodules_update_clone_config(const char *var, const char *value,
 
 void update_clone_config_from_gitmodules(int *max_jobs)
 {
-	config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
+	config_from_gitmodules(gitmodules_update_clone_config, the_repository, max_jobs);
 }
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 3adab12091..234a021fb3 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -1055,6 +1055,16 @@ test_expect_success 'submodule update can be run in parallel' '
 	)
 '
 
+test_expect_success 'submodule update honors fetch jobs config from .gitmodules' '
+	test_when_finished "rm -rf super3" &&
+	git clone cloned super3 &&
+	(cd super3 &&
+	 git config -f .gitmodules submodule.fetchJobs 67 &&
+	 GIT_TRACE="$(pwd)/trace.out" git submodule update --init &&
+	 grep "67 tasks" trace.out
+	)
+'
+
 test_expect_success 'git clone passes the parallel jobs config on to submodules' '
 	test_when_finished "rm -rf super4" &&
 	GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 7 . super4 &&

base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH v2] submodule-config: fix reading submodule.fetchJobs
From: Pablo @ 2026-05-03 13:07 UTC (permalink / raw)
  To: Saagar Jha via GitGitGadget; +Cc: git, Saagar Jha
In-Reply-To: <pull.2287.v2.git.git.1777809430925.gitgitgadget@gmail.com>

El dom, 3 may 2026 a las 13:57, Saagar Jha via GitGitGadget
(<gitgitgadget@gmail.com>) escribió:
>
> From: Saagar Jha <saagar@saagarjha.com>
>
> The old code accidentally passed &max_jobs rather than max_jobs into
> config_from_gitmodules, which caused the setting to be written to the
> wrong place and dropped.

Better, but we can improve this, following
Documentation/SubmittingPatches [1], it is better to write in present
tense something like:

  update_clone_config_from_gitmodules() passes &max_jobs to
  config_from_gitmodules(), but max_jobs is already a pointer.
  This causes the config value to be written to the wrong address
  and dropped.

  Pass max_jobs directly.

I recommend reading Documentation/SubmittingPatches:
  [1]: https://github.com/git/git/blob/master/Documentation/SubmittingPatches

>
> Signed-off-by: Saagar Jha <saagar@saagarjha.com>
> ---
>     submodule-config: fix reading submodule.fetchJobs
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2287%2Fsaagarjha%2Fmaint-v2
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2287/saagarjha/maint-v2
> Pull-Request: https://github.com/git/git/pull/2287
>
> Range-diff vs v1:
>
>  1:  094c641227 ! 1:  868901f1a6 submodule-config: fix reading submodule.fetchJobs
>      @@ Metadata
>        ## Commit message ##
>           submodule-config: fix reading submodule.fetchJobs
>
>      +    The old code accidentally passed &max_jobs rather than max_jobs into
>      +    config_from_gitmodules, which caused the setting to be written to the
>      +    wrong place and dropped.
>      +
>           Signed-off-by: Saagar Jha <saagar@saagarjha.com>
>
>        ## submodule-config.c ##
>
>
>  submodule-config.c          |  2 +-
>  t/t7406-submodule-update.sh | 10 ++++++++++
>  2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/submodule-config.c b/submodule-config.c
> index 1f19fe2077..57b190678e 100644
> --- a/submodule-config.c
> +++ b/submodule-config.c
> @@ -1037,5 +1037,5 @@ static int gitmodules_update_clone_config(const char *var, const char *value,
>
>  void update_clone_config_from_gitmodules(int *max_jobs)
>  {
> -       config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
> +       config_from_gitmodules(gitmodules_update_clone_config, the_repository, max_jobs);
>  }
> diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
> index 3adab12091..234a021fb3 100755
> --- a/t/t7406-submodule-update.sh
> +++ b/t/t7406-submodule-update.sh
> @@ -1055,6 +1055,16 @@ test_expect_success 'submodule update can be run in parallel' '
>         )
>  '
>
> +test_expect_success 'submodule update honors fetch jobs config from .gitmodules' '
> +       test_when_finished "rm -rf super3" &&
> +       git clone cloned super3 &&
> +       (cd super3 &&
> +        git config -f .gitmodules submodule.fetchJobs 67 &&
> +        GIT_TRACE="$(pwd)/trace.out" git submodule update --init &&
> +        grep "67 tasks" trace.out
> +       )
> +'
> +
>  test_expect_success 'git clone passes the parallel jobs config on to submodules' '
>         test_when_finished "rm -rf super4" &&
>         GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 7 . super4 &&
>
> base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
> --
> gitgitgadget

^ permalink raw reply

* [PATCH] mingw: stop using nedmalloc
From: Johannes Schindelin via GitGitGadget @ 2026-05-03 12:29 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin, Johannes Schindelin

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The vendored nedmalloc allocator under compat/nedmalloc/ has been
unmaintained upstream for a very long time: the original repository at
https://github.com/ned14/nedmalloc received its last commit on July 5,
2014, and was archived (made read-only) by its owner on March 15, 2019.
Our copy has been carried forward unchanged ever since.

The Git for Windows commit that introduced mimalloc as a replacement
on Windows ("mingw: use mimalloc", 2019-06-24, present in the Git for
Windows branch thicket but not upstream) already observed at that time
that nedmalloc had ceased to see any updates for several years.

This came to a head when the Git for Windows SDK upgraded to GCC 16:
the `add_segment()` function in `compat/nedmalloc/malloc.c.h` declares
`int nfences = 0` and only references it inside an `assert()`, which
GCC 16 now flags as `-Wunused-but-set-variable`. Combined with the
`-Werror` enabled by `DEVELOPER=1`, this turns into a hard build
failure:

	compat/nedmalloc/malloc.c.h: In function 'add_segment':
	compat/nedmalloc/malloc.c.h:3897:7: error: variable 'nfences' set but not used [-Werror=unused-but-set-variable=]
	 3897 |   int nfences = 0;
	      |       ^~~~~~~
	cc1.exe: all warnings being treated as errors

The same source built without complaint under GCC 15.2.0; the
regression was bisected to the SDK package update at
https://github.com/git-for-windows/git-sdk-64/commit/188d93dd455
(`mingw-w64-x86_64-gcc 15.2.0-14 -> 16.1.0-1`), with the failing CI
run captured at
https://github.com/git-for-windows/git-sdk-64/actions/runs/25244795074.

Rather than patch the unmaintained vendored sources to silence the
warning, stop opting into nedmalloc altogether on MINGW. The platform
allocator is what every non-MINGW build already uses, and a fresh
build of git.git's master against a minimal Git for Windows SDK
upgraded to GCC 16, with `USE_NED_ALLOCATOR` removed from the MINGW
section, completes successfully.

The compat/nedmalloc/ subtree itself is left in place to keep this
change minimal; nothing in the build links against it any longer, so
it can be removed in a follow-up if desired.

Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
    mingw: stop using nedmalloc
    
    Git for Windows' SDK wants to update GCC to v16. Since it is used in the
    CI builds also of the git/git repository, it is crucial that GCC can
    compile even the latter all right, but currently it does not, see
    https://github.com/git-for-windows/git-sdk-64/actions/runs/25244795074.
    
    Git for Windows switched away from nedmalloc to mimalloc a long time
    ago, anyway. I plan on upstreaming this soon-ish, after this here patch
    lands.
    
    Note that with this patch, I reverse the order I indicated in
    https://lore.kernel.org/git/00fd3145-b3d2-ddab-466d-d06fd27298ec@gmx.de/:
    I first disable nedmalloc for MINGW builds (and possibly drop the
    vendored-in nedmalloc from Git's source code). The reason is that I am
    still trying to figure out the best way to integrate mimalloc:
    https://github.com/git-for-windows/git/commit/d67535b61dd (Import the
    source code of mimalloc v2.2.7, 2026-01-16) in patch form would weigh
    some ~700kB, which would not only be rejected by the Git mailing list,
    but which I myself would reject if I was the Git maintainer merely on
    the basis of the sheer size of the patch. Probably the best course of
    action is to add support for a non-vendored-in mimalloc first, then keep
    the vendored-in copy in Git for Windows (where no mailing list stands in
    the way of large patches). Whatever it will be, it's best to fast-track
    this here patch to disable nedmalloc for Windows builds, so that the CI
    builds can switch to using GCC 16 (and the current Git for Windows SDK)
    on Windows.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2104%2Fdscho%2Fstop-using-nedmalloc-with-mingw-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2104/dscho/stop-using-nedmalloc-with-mingw-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2104

 config.mak.uname | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/config.mak.uname b/config.mak.uname
index 5feb582558..3636b98238 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -758,9 +758,6 @@ ifeq ($(uname_S),MINGW)
 	HAVE_LIBCHARSET_H = YesPlease
 	USE_GETTEXT_SCHEME = fallthrough
 	USE_LIBPCRE = YesPlease
-        ifneq (CLANGARM64,$(MSYSTEM))
-		USE_NED_ALLOCATOR = YesPlease
-        endif
         ifeq (/mingw64,$(subst 32,64,$(subst clangarm,mingw,$(prefix))))
 		# Move system config into top-level /etc/
 		ETC_GITCONFIG = ../etc/gitconfig

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH] submodule-config: fix reading submodule.fetchJobs
From: Pablo @ 2026-05-03 12:19 UTC (permalink / raw)
  To: Saagar Jha; +Cc: Saagar Jha via GitGitGadget, git
In-Reply-To: <AAB01B60-F569-49C7-916D-A03549E6C210@saagarjha.com>

El dom, 3 may 2026 a las 13:24, Saagar Jha (<saagar@saagarjha.com>) escribió:
>
> Hi Pablo! I figured the change was simple enough to be self-explanatory, but I expanded the description to indicate what the bug was. Let me know if there’s anything else you’d like me to fix (I agree that the CI failure is probably not related to my change, but I can try my hand at looking at it after if nobody has?)

No, by doing a quick search you find:
https://lore.kernel.org/git/20260402041433.GA3501120@coredump.intra.peff.net/

I was noting it so other reviewers know that your patch has nothing to
do with the CI failing.
Nit: Try to have 80 columns at most per line so the lines doesn't get too long

--
Pablo

^ permalink raw reply

* [PATCH v2] submodule-config: fix reading submodule.fetchJobs
From: Saagar Jha via GitGitGadget @ 2026-05-03 11:57 UTC (permalink / raw)
  To: git; +Cc: Pablo, Saagar Jha, Saagar Jha
In-Reply-To: <pull.2287.git.git.1777803242592.gitgitgadget@gmail.com>

From: Saagar Jha <saagar@saagarjha.com>

The old code accidentally passed &max_jobs rather than max_jobs into
config_from_gitmodules, which caused the setting to be written to the
wrong place and dropped.

Signed-off-by: Saagar Jha <saagar@saagarjha.com>
---
    submodule-config: fix reading submodule.fetchJobs

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2287%2Fsaagarjha%2Fmaint-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2287/saagarjha/maint-v2
Pull-Request: https://github.com/git/git/pull/2287

Range-diff vs v1:

 1:  094c641227 ! 1:  868901f1a6 submodule-config: fix reading submodule.fetchJobs
     @@ Metadata
       ## Commit message ##
          submodule-config: fix reading submodule.fetchJobs
      
     +    The old code accidentally passed &max_jobs rather than max_jobs into
     +    config_from_gitmodules, which caused the setting to be written to the
     +    wrong place and dropped.
     +
          Signed-off-by: Saagar Jha <saagar@saagarjha.com>
      
       ## submodule-config.c ##


 submodule-config.c          |  2 +-
 t/t7406-submodule-update.sh | 10 ++++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/submodule-config.c b/submodule-config.c
index 1f19fe2077..57b190678e 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -1037,5 +1037,5 @@ static int gitmodules_update_clone_config(const char *var, const char *value,
 
 void update_clone_config_from_gitmodules(int *max_jobs)
 {
-	config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
+	config_from_gitmodules(gitmodules_update_clone_config, the_repository, max_jobs);
 }
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 3adab12091..234a021fb3 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -1055,6 +1055,16 @@ test_expect_success 'submodule update can be run in parallel' '
 	)
 '
 
+test_expect_success 'submodule update honors fetch jobs config from .gitmodules' '
+	test_when_finished "rm -rf super3" &&
+	git clone cloned super3 &&
+	(cd super3 &&
+	 git config -f .gitmodules submodule.fetchJobs 67 &&
+	 GIT_TRACE="$(pwd)/trace.out" git submodule update --init &&
+	 grep "67 tasks" trace.out
+	)
+'
+
 test_expect_success 'git clone passes the parallel jobs config on to submodules' '
 	test_when_finished "rm -rf super4" &&
 	GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 7 . super4 &&

base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
-- 
gitgitgadget

^ permalink raw reply related

* Re: [PATCH] submodule-config: fix reading submodule.fetchJobs
From: Saagar Jha @ 2026-05-03 11:24 UTC (permalink / raw)
  To: Pablo; +Cc: Saagar Jha via GitGitGadget, git
In-Reply-To: <CAN5EUNT27bYwjdXRQTffbtHFpkV68rAajqgXtbKHu6OjhzG_mA@mail.gmail.com>

Hi Pablo! I figured the change was simple enough to be self-explanatory, but I expanded the description to indicate what the bug was. Let me know if there’s anything else you’d like me to fix (I agree that the CI failure is probably not related to my change, but I can try my hand at looking at it after if nobody has?)

> On May 3, 2026, at 04:07, Pablo <pabloosabaterr@gmail.com> wrote:
> 
> El dom, 3 may 2026 a las 12:14, Saagar Jha via GitGitGadget
> (<gitgitgadget@gmail.com>) escribió:
>> 
>> From: Saagar Jha <saagar@saagarjha.com>
>> 
>> Signed-off-by: Saagar Jha <saagar@saagarjha.com>
>> ---
>>    submodule-config: fix reading submodule.fetchJobs
>> 
>> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2287%2Fsaagarjha%2Fmaint-v1
>> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2287/saagarjha/maint-v1
>> Pull-Request: https://github.com/git/git/pull/2287
>> 
>> submodule-config.c          |  2 +-
>> t/t7406-submodule-update.sh | 10 ++++++++++
>> 2 files changed, 11 insertions(+), 1 deletion(-)
>> 
>> diff --git a/submodule-config.c b/submodule-config.c
>> index 1f19fe2077..57b190678e 100644
>> --- a/submodule-config.c
>> +++ b/submodule-config.c
>> @@ -1037,5 +1037,5 @@ static int gitmodules_update_clone_config(const char *var, const char *value,
>> 
>> void update_clone_config_from_gitmodules(int *max_jobs)
>> {
>> -       config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
>> +       config_from_gitmodules(gitmodules_update_clone_config, the_repository, max_jobs);
>> }
>> diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
>> index 3adab12091..234a021fb3 100755
>> --- a/t/t7406-submodule-update.sh
>> +++ b/t/t7406-submodule-update.sh
>> @@ -1055,6 +1055,16 @@ test_expect_success 'submodule update can be run in parallel' '
>>        )
>> '
>> 
>> +test_expect_success 'submodule update honors fetch jobs config from .gitmodules' '
>> +       test_when_finished "rm -rf super3" &&
>> +       git clone cloned super3 &&
>> +       (cd super3 &&
>> +        git config -f .gitmodules submodule.fetchJobs 67 &&
>> +        GIT_TRACE="$(pwd)/trace.out" git submodule update --init &&
>> +        grep "67 tasks" trace.out
>> +       )
>> +'
>> +
>> test_expect_success 'git clone passes the parallel jobs config on to submodules' '
>>        test_when_finished "rm -rf super4" &&
>>        GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 7 . super4 &&
>> 
>> base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
>> --
>> gitgitgadget
>> 
> 
> Hi Saagar!
> 
> A few hints before this can be reviewable:
> - There is no commit body which, not only is a must, it makes it very
> hard reviewing because I cannot know what you wanted to do and I have
> to imagine it.
> - CI tests seem to be failing, but the file that reports fail doesn't
> seem to be related with your changes.
> 
> About the code, I can understand the 'why': the function above
> 'fetch_config_from_gitmodules' builds an struct inside and sends the
> address &config, 'update_clone_config_from_gitmodules' calls the same
> function with &max_jobs but the error would be that max_jobs is
> already a pointer so there would be no need to pass by reference
> max_jobs.
> 
> But this kind of explanation is what should be on the commit body.
> Maybe not this technical as the code can be easily seen, but a high
> level explanation about what this is.
> 
> Looking forward for a v2,
> --
> Pablo


^ permalink raw reply

* Re: [PATCH] submodule-config: fix reading submodule.fetchJobs
From: Pablo @ 2026-05-03 11:07 UTC (permalink / raw)
  To: Saagar Jha via GitGitGadget; +Cc: git, Saagar Jha
In-Reply-To: <pull.2287.git.git.1777803242592.gitgitgadget@gmail.com>

El dom, 3 may 2026 a las 12:14, Saagar Jha via GitGitGadget
(<gitgitgadget@gmail.com>) escribió:
>
> From: Saagar Jha <saagar@saagarjha.com>
>
> Signed-off-by: Saagar Jha <saagar@saagarjha.com>
> ---
>     submodule-config: fix reading submodule.fetchJobs
>
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2287%2Fsaagarjha%2Fmaint-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2287/saagarjha/maint-v1
> Pull-Request: https://github.com/git/git/pull/2287
>
>  submodule-config.c          |  2 +-
>  t/t7406-submodule-update.sh | 10 ++++++++++
>  2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/submodule-config.c b/submodule-config.c
> index 1f19fe2077..57b190678e 100644
> --- a/submodule-config.c
> +++ b/submodule-config.c
> @@ -1037,5 +1037,5 @@ static int gitmodules_update_clone_config(const char *var, const char *value,
>
>  void update_clone_config_from_gitmodules(int *max_jobs)
>  {
> -       config_from_gitmodules(gitmodules_update_clone_config, the_repository, &max_jobs);
> +       config_from_gitmodules(gitmodules_update_clone_config, the_repository, max_jobs);
>  }
> diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
> index 3adab12091..234a021fb3 100755
> --- a/t/t7406-submodule-update.sh
> +++ b/t/t7406-submodule-update.sh
> @@ -1055,6 +1055,16 @@ test_expect_success 'submodule update can be run in parallel' '
>         )
>  '
>
> +test_expect_success 'submodule update honors fetch jobs config from .gitmodules' '
> +       test_when_finished "rm -rf super3" &&
> +       git clone cloned super3 &&
> +       (cd super3 &&
> +        git config -f .gitmodules submodule.fetchJobs 67 &&
> +        GIT_TRACE="$(pwd)/trace.out" git submodule update --init &&
> +        grep "67 tasks" trace.out
> +       )
> +'
> +
>  test_expect_success 'git clone passes the parallel jobs config on to submodules' '
>         test_when_finished "rm -rf super4" &&
>         GIT_TRACE=$(pwd)/trace.out git clone --recurse-submodules --jobs 7 . super4 &&
>
> base-commit: 67ad42147a7acc2af6074753ebd03d904476118f
> --
> gitgitgadget
>

Hi Saagar!

A few hints before this can be reviewable:
- There is no commit body which, not only is a must, it makes it very
hard reviewing because I cannot know what you wanted to do and I have
to imagine it.
- CI tests seem to be failing, but the file that reports fail doesn't
seem to be related with your changes.

About the code, I can understand the 'why': the function above
'fetch_config_from_gitmodules' builds an struct inside and sends the
address &config, 'update_clone_config_from_gitmodules' calls the same
function with &max_jobs but the error would be that max_jobs is
already a pointer so there would be no need to pass by reference
max_jobs.

But this kind of explanation is what should be on the commit body.
Maybe not this technical as the code can be easily seen, but a high
level explanation about what this is.

Looking forward for a v2,
--
Pablo

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox