* [PATCH v2 1/3] doc: config: terminate runaway lists
From: Tuomas Ahola @ 2026-06-10 22:55 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Junio C Hamano, Tuomas Ahola
In-Reply-To: <20260610225513.6269-1-taahol@utu.fi>
There are many places in git-config(1) where paragraphs that should
logically come after a list are instead appended to the last item of
the list. This is a well-documented quirk of AsciiDoc, and can be
mitigated by enclosing the list in an open block:
--
* first item
* last item
--
+
New paragraph after the list.
Fix the issue accordingly.
Signed-off-by: Tuomas Ahola <taahol@utu.fi>
---
Documentation/config.adoc | 4 +++-
Documentation/config/promisor.adoc | 2 ++
Documentation/config/safe.adoc | 2 ++
Documentation/git-config.adoc | 2 ++
4 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/Documentation/config.adoc b/Documentation/config.adoc
index dcea3c0c15..fc48c1c461 100644
--- a/Documentation/config.adoc
+++ b/Documentation/config.adoc
@@ -276,13 +276,15 @@ boolean::
When a variable is said to take a boolean value, many
synonyms are accepted for 'true' and 'false'; these are all
case-insensitive.
-
++
+--
true;; Boolean true literals are `yes`, `on`, `true`,
and `1`. Also, a variable defined without `= <value>`
is taken as true.
false;; Boolean false literals are `no`, `off`, `false`,
`0` and the empty string.
+--
+
When converting a value to its canonical form using the `--type=bool` type
specifier, 'git config' will ensure that the output is "true" or
diff --git a/Documentation/config/promisor.adoc b/Documentation/config/promisor.adoc
index b0fa43b839..39af63dcb8 100644
--- a/Documentation/config/promisor.adoc
+++ b/Documentation/config/promisor.adoc
@@ -63,11 +63,13 @@ If one of these field names (e.g., "token") is being checked for an
advertised promisor remote (e.g., "foo"), three conditions must be met
for the check of this specific field to pass:
+
+--
1. The corresponding local configuration (e.g., `remote.foo.token`)
must be set.
2. The server must advertise the "token" field for remote "foo".
3. The value of the locally configured `remote.foo.token` must exactly
match the value advertised by the server for the "token" field.
+--
+
If any of these conditions is not met for any field name listed in
`promisor.checkFields`, the advertised remote "foo" is rejected.
diff --git a/Documentation/config/safe.adoc b/Documentation/config/safe.adoc
index 2d45c98b12..5ae4476b24 100644
--- a/Documentation/config/safe.adoc
+++ b/Documentation/config/safe.adoc
@@ -2,10 +2,12 @@ safe.bareRepository::
Specifies which bare repositories Git will work with. The currently
supported values are:
+
+--
* `all`: Git works with all bare repositories. This is the default.
* `explicit`: Git only works with bare repositories specified via
the top-level `--git-dir` command-line option, or the `GIT_DIR`
environment variable (see linkgit:git[1]).
+--
+
If you do not use bare repositories in your workflow, then it may be
beneficial to set `safe.bareRepository` to `explicit` in your global
diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc
index 00545b2054..8439ce97df 100644
--- a/Documentation/git-config.adoc
+++ b/Documentation/git-config.adoc
@@ -221,6 +221,7 @@ Use `--no-value` to unset _<pattern>_.
+
Valid `<type>`'s include:
+
+--
- 'bool': canonicalize values `true`, `yes`, `on`, and positive
numbers as "true", and values `false`, `no`, `off` and `0` as
"false".
@@ -239,6 +240,7 @@ Valid `<type>`'s include:
escape sequence. When setting a value, a sanity-check is performed to ensure
that the given value is canonicalize-able as an ANSI color, but it is written
as-is.
+--
+
If the command is in `list` mode, then the `--type <type>` argument will apply
to each listed config value. If the value does not successfully parse in that
--
2.30.2
^ permalink raw reply related
* [PATCH v2 2/3] doc: config/sideband: fix description list delimiter
From: Tuomas Ahola @ 2026-06-10 22:55 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Junio C Hamano, Tuomas Ahola
In-Reply-To: <20260610225513.6269-1-taahol@utu.fi>
Signed-off-by: Tuomas Ahola <taahol@utu.fi>
---
Documentation/config/sideband.adoc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/config/sideband.adoc b/Documentation/config/sideband.adoc
index 96fade7f5f..06de0d5c07 100644
--- a/Documentation/config/sideband.adoc
+++ b/Documentation/config/sideband.adoc
@@ -9,7 +9,7 @@ sideband.allowControlCharacters::
`color`::
Allow ANSI color sequences, line feeds and horizontal tabs,
but mask all other control characters. This is the default.
- `cursor:`:
+ `cursor`::
Allow control sequences that move the cursor. This is
disabled by default.
`erase`::
--
2.30.2
^ permalink raw reply related
* [PATCH v2 3/3] doc: git-config: escape erroneous highlight markup
From: Tuomas Ahola @ 2026-06-10 22:55 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Junio C Hamano, Tuomas Ahola
In-Reply-To: <20260610225513.6269-1-taahol@utu.fi>
Paired octothorpes are used in AsciiDoc to mark highlighted text,
<mark> being the equivalent HTML tag. To use the symbol as a literal
character, it can be escaped with a backslash.
Do so in git-config.adoc.
While at it, tweak the text slightly to make it scan better.
Signed-off-by: Tuomas Ahola <taahol@utu.fi>
---
Documentation/git-config.adoc | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc
index 8439ce97df..e4af6cac68 100644
--- a/Documentation/git-config.adoc
+++ b/Documentation/git-config.adoc
@@ -119,10 +119,10 @@ OPTIONS
Append a comment at the end of new or modified lines.
+
If _<message>_ begins with one or more whitespaces followed
-by "#", it is used as-is. If it begins with "#", a space is
+by "\#", it is used as-is. If it begins with "\#", a space is
prepended before it is used. Otherwise, a string " # " (a
space followed by a hash followed by a space) is prepended
-to it. And the resulting string is placed immediately after
+to it. The resulting string is placed immediately after
the value defined for the variable. The _<message>_ must
not contain linefeed characters (no multi-line comments are
permitted).
--
2.30.2
^ permalink raw reply related
* [PATCH v2 0/3] doc: config: fix AsciiDoc glitches
From: Tuomas Ahola @ 2026-06-10 22:55 UTC (permalink / raw)
To: git; +Cc: Kristoffer Haugsbakk, Junio C Hamano, Tuomas Ahola
In-Reply-To: <20260610185148.23920-1-taahol@utu.fi>
Fix various markup shortcomings in git-config(1).
Based on 29bd7ed512 (The second batch, 2026-05-12).
Tuomas Ahola (3):
doc: config: terminate runaway lists
doc: config/sideband: fix description list delimiter
doc: git-config: escape erroneous highlight markup
Documentation/config.adoc | 4 +++-
Documentation/config/promisor.adoc | 2 ++
Documentation/config/safe.adoc | 2 ++
Documentation/config/sideband.adoc | 2 +-
Documentation/git-config.adoc | 6 ++++--
5 files changed, 12 insertions(+), 4 deletions(-)
Intervall-diff mot v1:
1: 224303c555 = 1: c9131b23fd doc: config: terminate runaway lists
2: a7e6b82c97 ! 2: ca65211ea4 doc: config/sideband: fix typo in adoc markup
@@ Metadata
Author: Tuomas Ahola <taahol@utu.fi>
## Commit message ##
- doc: config/sideband: fix typo in adoc markup
-
- Fix a simple typo in AsciiDoc markup.
+ doc: config/sideband: fix description list delimiter
Signed-off-by: Tuomas Ahola <taahol@utu.fi>
3: 7d0916a874 ! 3: 0341a4bde9 doc: git-config: escape erroneous adoc markup
@@ Metadata
Author: Tuomas Ahola <taahol@utu.fi>
## Commit message ##
- doc: git-config: escape erroneous adoc markup
+ doc: git-config: escape erroneous highlight markup
Paired octothorpes are used in AsciiDoc to mark highlighted text,
<mark> being the equivalent HTML tag. To use the symbol as a literal
@@ Documentation/git-config.adoc: OPTIONS
+
If _<message>_ begins with one or more whitespaces followed
-by "#", it is used as-is. If it begins with "#", a space is
-+by "\#", it is used as-is. If it begins with "#", a space is
++by "\#", it is used as-is. If it begins with "\#", a space is
prepended before it is used. Otherwise, a string " # " (a
space followed by a hash followed by a space) is prepended
-to it. And the resulting string is placed immediately after
base-commit: 29bd7ed5127255713c1ac2f43b7c6f257d7b4594
--
2.30.2
^ permalink raw reply
* Re: [PATCH v2 3/3] environment: move trust_executable_bit into repo_config_values
From: Tian Yuchen @ 2026-06-11 2:58 UTC (permalink / raw)
To: git; +Cc: ps, Christian Couder, Ayush Chandekar, Olamide Caleb Bello
In-Reply-To: <20260610093635.139719-4-cat@malon.dev>
On 6/10/26 17:36, Tian Yuchen wrote:
> Move the global 'trust_executable_bit' configurations
> into the repository-specific 'repo_config_values'
> struct. To ensure code readability, the getter functions
> 'repo_trust_executable_bit()' has been introduced.
>
> For now, associated functions access this configuration by
> explicitly falling back to 'the_repository'.
>
> Mentored-by: Christian Couder <christian.couder@gmail.com>
> Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com>
> Mentored-by: Olamide Caleb Bello <belkid98@gmail.com>
> Signed-off-by: Tian Yuchen <cat@malon.dev>
> ---
> apply.c | 2 +-
> environment.c | 11 +++++++++--
> environment.h | 9 ++++++++-
> read-cache.c | 8 ++++----
> 4 files changed, 22 insertions(+), 8 deletions(-)
>
> diff --git a/apply.c b/apply.c
> index 249248d4f2..fbb907d3c0 100644
> --- a/apply.c
> +++ b/apply.c
> @@ -3893,7 +3893,7 @@ static int check_preimage(struct apply_state *state,
> if (*ce && !(*ce)->ce_mode)
> BUG("ce_mode == 0 for path '%s'", old_name);
>
> - if (trust_executable_bit || !S_ISREG(st->st_mode))
> + if (repo_trust_executable_bit(the_repository) || !S_ISREG(st->st_mode))
> st_mode = ce_mode_from_stat(*ce, st->st_mode);
> else if (*ce)
> st_mode = (*ce)->ce_mode;
> diff --git a/environment.c b/environment.c
> index fc3ed8bb1c..75069a884d 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -41,7 +41,6 @@
> static int pack_compression_seen;
> static int zlib_compression_seen;
>
> -int trust_executable_bit = 1;
> int trust_ctime = 1;
> int check_stat = 1;
> int has_symlinks = 1;
> @@ -142,6 +141,13 @@ int is_bare_repository(void)
> return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
> }
>
> +int repo_trust_executable_bit(struct repository *repo)
> +{
> + return repo->gitdir?
> + repo_config_values(repo)->trust_executable_bit :
> + 1;
> +}
> +
> int have_git_dir(void)
> {
> return startup_info->have_repository
> @@ -305,7 +311,7 @@ int git_default_core_config(const char *var, const char *value,
>
> /* This needs a better name */
> if (!strcmp(var, "core.filemode")) {
> - trust_executable_bit = git_config_bool(var, value);
> + cfg->trust_executable_bit = git_config_bool(var, value);
> return 0;
> }
> if (!strcmp(var, "core.trustctime")) {
> @@ -720,5 +726,6 @@ void repo_config_values_init(struct repo_config_values *cfg)
> {
> cfg->attributes_file = NULL;
> cfg->apply_sparse_checkout = 0;
> + cfg->trust_executable_bit = 1;
> cfg->branch_track = BRANCH_TRACK_REMOTE;
> }
> diff --git a/environment.h b/environment.h
> index 123a71cdc8..44b97be654 100644
> --- a/environment.h
> +++ b/environment.h
> @@ -91,6 +91,7 @@ struct repo_config_values {
> /* section "core" config values */
> char *attributes_file;
> int apply_sparse_checkout;
> + int trust_executable_bit;
>
> /* section "branch" config values */
> enum branch_track branch_track;
> @@ -123,6 +124,13 @@ int git_default_config(const char *, const char *,
> int git_default_core_config(const char *var, const char *value,
> const struct config_context *ctx, void *cb);
>
> +/*
> + * Getters for the `repo_trust_executable_bit` fields of `struct repo_config_values`.
> + * They check `repo->gitdir` to prevent calling repo_config_values()
> + * before the configuration is loaded or in bare environments.
> + */
> +int repo_trust_executable_bit(struct repository *repo);
> +
> void repo_config_values_init(struct repo_config_values *cfg);
>
> /*
> @@ -160,7 +168,6 @@ int is_bare_repository(void);
> extern char *git_work_tree_cfg;
>
> /* Environment bits from configuration mechanism */
> -extern int trust_executable_bit;
> extern int trust_ctime;
> extern int check_stat;
> extern int has_symlinks;
> diff --git a/read-cache.c b/read-cache.c
> index cb4f4878c8..89f5c88c58 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -214,7 +214,7 @@ unsigned int ce_mode_from_stat(const struct cache_entry *ce, unsigned int mode)
> if (!has_symlinks && S_ISREG(mode) &&
> ce && S_ISLNK(ce->ce_mode))
> return ce->ce_mode;
> - if (!trust_executable_bit && S_ISREG(mode)) {
> + if (!repo_trust_executable_bit(the_repository) && S_ISREG(mode)) {
> if (ce && S_ISREG(ce->ce_mode))
> return ce->ce_mode;
> return create_ce_mode(0666);
> @@ -228,7 +228,7 @@ static unsigned int st_mode_from_ce(const struct cache_entry *ce)
> case S_IFLNK:
> return has_symlinks ? S_IFLNK : (S_IFREG | 0644);
> case S_IFREG:
> - return (ce->ce_mode & (trust_executable_bit ? 0755 : 0644)) | S_IFREG;
> + return (ce->ce_mode & (repo_trust_executable_bit(the_repository) ? 0755 : 0644)) | S_IFREG;
> case S_IFGITLINK:
> return S_IFDIR | 0755;
> case S_IFDIR:
> @@ -338,7 +338,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> /* We consider only the owner x bit to be relevant for
> * "mode changes"
> */
> - if (trust_executable_bit &&
> + if (repo_trust_executable_bit(the_repository) &&
> (0100 & (ce->ce_mode ^ st->st_mode)))
> changed |= MODE_CHANGED;
> break;
> @@ -759,7 +759,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
> ce->ce_flags |= CE_INTENT_TO_ADD;
>
>
> - if (trust_executable_bit && has_symlinks) {
> + if (repo_trust_executable_bit(the_repository) && has_symlinks) {
> ce->ce_mode = create_ce_mode(st_mode);
> } else {
> /* If there is an existing entry, pick the mode bits and type
There seem to be typos everywhere here, will change in the next reroll.
Regards, yuchen
^ permalink raw reply
* Re: [PATCH v3 02/11] doc: interpret-trailers: replace “lines” with “metadata”
From: Matt Hunter @ 2026-06-11 3:10 UTC (permalink / raw)
To: kristofferhaugsbakk, git
Cc: Kristoffer Haugsbakk, christian.couder, jackmanb, Linus Arver,
D . Ben Knoble
In-Reply-To: <V3_metadata_not_lines.8a5@msgid.xyz>
On Wed Jun 10, 2026 at 5:21 PM EDT, kristofferhaugsbakk wrote:
>
> diff --git a/Documentation/git-interpret-trailers.adoc b/Documentation/git-interpret-trailers.adoc
> index 1878848ad2a..3f60fd9b720 100644
> --- a/Documentation/git-interpret-trailers.adoc
> +++ b/Documentation/git-interpret-trailers.adoc
> @@ -14,7 +14,7 @@ git interpret-trailers [--in-place] [--trim-empty]
>
> DESCRIPTION
> -----------
> -Add or parse _trailer_ lines at the end of the otherwise
> +Add or parse trailers metadata at the end of the otherwise
fwiw, I think "trailer metadata" reads more naturally.
^ permalink raw reply
* Re: followRemoteHEAD management question
From: Matt Hunter @ 2026-06-11 4:12 UTC (permalink / raw)
To: Jeff King; +Cc: git, Bence Ferdinandy
In-Reply-To: <20260608234946.GB358144@coredump.intra.peff.net>
On Mon Jun 8, 2026 at 7:49 PM EDT, Jeff King wrote:
>>
>> The topic mentioned above (merged in a1f34d595503) adds a new
>> configuration key 'remote.<name>.followRemoteHEAD'. I'm assuming that
>> the intended use for followRemoteHEAD is really only in local /
>> per-repository config, since trying to apply it to my personal
>> .gitconfig has some odd behavior.
>
> I think this is a gap in the new feature's implementation. It added
> per-remote config, but there is no global config to fall back to (e.g.,
> the way that remote.*.prune falls back to fetch.prune). There should be
> a fetch.followRemoteHEAD option (or perhaps remote.followRemoteHEAD).
Earlier on while working on this, I actually settled on
fetch.followRemoteHEAD instead, taking example from the prune setting.
Thanks for the confirmation.
>> The <name> in the key template does not accept a wildcard, so I must
>> list out each of the common remote names I use across different
>> repositories. Since many of my repos don't actually have remotes
>> established for all of these names, they pick up a kind of half-baked
>> definition for each of them as git performs its config parsing. For
>> instance, a name will appear under 'git remote -v', but it won't
>> have any actual properties configured.
>
> Yes, this is a common problem with the remote-config namespace. Defining
> _any_ key makes the remote "exist", even without a defined url, but that
> isn't usually the intent. But we can't distinguish that from the case
> where you really do want to define a remote without a url (in which case
> the url is the name of the remote).
I had no idea a remote like that was supported. Interesting.
>> Is there another solution in place I've missed? If not, would there be
>> any opposition to a new key like 'remote.followRemoteHEAD' which serves
>> to provide a default value for any remote that doesn't have its own
>> 'remote.<name>.followRemoteHEAD' key?
>>
>> I've started scouting out changes to make for such a patch. It's not
>> ready yet, but I figured I would throw this question out in case an easy
>> answer can save the effort.
>
> I think you are on the right track. I can see arguments for or against
> putting it in fetch.* or remote.*, so you'll have to pick one. ;)
As stated, I think putting it in fetch.* is more consistent. I'd be
curious to hear arguments the other way.
As for another design decision: I'm leaning toward omitting support for
the "warn-if-not-$branch" value in fetch.followRemoteHEAD.
My take on that option as-documented is that it serves more as an
acknowledgment from the user that "yes, I understand that origin has
pointed HEAD at foo, please only warn me if it changes" as opposed to the
user expressing that the branch "foo" is in some way special to them.
This interpretation feels very remote-dependent and doesn't make sense in
the context of a default catch-all value to me.
Thanks for the feedback!
^ permalink raw reply
* Re: [PATCH v4] git-gui: silence install recipes under "make -s"
From: Johannes Sixt @ 2026-06-11 5:37 UTC (permalink / raw)
To: Harald Nordgren; +Cc: git, Harald Nordgren via GitGitGadget
In-Reply-To: <CAHwyqnUpiWmXo0SVr=7L-+cwA+qhVyqodpV-O4C46w=kLqaLMg@mail.gmail.com>
Am 10.06.26 um 15:19 schrieb Harald Nordgren:
> What does it mean for it to be queued here, should I expect it to show
> up on seen or next?
It means that I'll arrange that it will appear in the next Git release.
Until then you can find the commit in
https://github.com/j6t/git-gui/tree/hn/silence-make-s .
-- Hannes
^ permalink raw reply
* Re: followRemoteHEAD management question
From: Jeff King @ 2026-06-11 6:01 UTC (permalink / raw)
To: Matt Hunter; +Cc: git, Bence Ferdinandy
In-Reply-To: <DJ5XE9HC5YNY.33U8AG1GX6ZP0@lfurio.us>
On Thu, Jun 11, 2026 at 12:12:54AM -0400, Matt Hunter wrote:
> > Yes, this is a common problem with the remote-config namespace. Defining
> > _any_ key makes the remote "exist", even without a defined url, but that
> > isn't usually the intent. But we can't distinguish that from the case
> > where you really do want to define a remote without a url (in which case
> > the url is the name of the remote).
>
> I had no idea a remote like that was supported. Interesting.
I suspect it is more of an emergent property than something that was
carefully designed, but after so many years I'd hesitate to change it
(at least without a big warning and deprecation period).
> > I think you are on the right track. I can see arguments for or against
> > putting it in fetch.* or remote.*, so you'll have to pick one. ;)
>
> As stated, I think putting it in fetch.* is more consistent. I'd be
> curious to hear arguments the other way.
My initial thought is that it might affect clone as well as fetch. But I
guess this feature does not kick in for clone, as it has its own logic
for handling the remote-tracking HEAD. Though arguably it should be
possible to configure it not to create one in the first place.
> As for another design decision: I'm leaning toward omitting support for
> the "warn-if-not-$branch" value in fetch.followRemoteHEAD.
>
> My take on that option as-documented is that it serves more as an
> acknowledgment from the user that "yes, I understand that origin has
> pointed HEAD at foo, please only warn me if it changes" as opposed to the
> user expressing that the branch "foo" is in some way special to them.
>
> This interpretation feels very remote-dependent and doesn't make sense in
> the context of a default catch-all value to me.
Agreed. I can't think of a reason you'd want it in the global option.
And if we're wrong, it is easy to add support later (versus adding it
now, finding out that it creates awkward corner cases, and then having
the backwards-incompatible change of ripping it out).
-Peff
^ permalink raw reply
* Re: [PATCH v2 1/3] doc: config: terminate runaway lists
From: Jeff King @ 2026-06-11 6:02 UTC (permalink / raw)
To: Tuomas Ahola; +Cc: git, Kristoffer Haugsbakk, Junio C Hamano
In-Reply-To: <20260610225513.6269-2-taahol@utu.fi>
On Thu, Jun 11, 2026 at 01:55:11AM +0300, Tuomas Ahola wrote:
> There are many places in git-config(1) where paragraphs that should
> logically come after a list are instead appended to the last item of
> the list. This is a well-documented quirk of AsciiDoc, and can be
> mitigated by enclosing the list in an open block:
>
> --
> * first item
> * last item
> --
> +
> New paragraph after the list.
>
> Fix the issue accordingly.
Makes sense. We've run into problems in the past where adding "--"
doesn't quite work, because we are already inside a "--" (and IIRC the
behavior is not always completely predictable). But I double-checked
these cases, and we are not already in a "--". So we should be good
here.
-Peff
^ permalink raw reply
* Re: [PATCH v2 3/3] doc: git-config: escape erroneous highlight markup
From: Jeff King @ 2026-06-11 6:11 UTC (permalink / raw)
To: Tuomas Ahola; +Cc: git, Kristoffer Haugsbakk, Junio C Hamano
In-Reply-To: <20260610225513.6269-4-taahol@utu.fi>
On Thu, Jun 11, 2026 at 01:55:13AM +0300, Tuomas Ahola wrote:
> Paired octothorpes are used in AsciiDoc to mark highlighted text,
> <mark> being the equivalent HTML tag. To use the symbol as a literal
> character, it can be escaped with a backslash.
>
> Do so in git-config.adoc.
I think this works OK, but in general I think most uses of backslash for
metacharacters should consider using literal backticks. That shields it
from the special meaning for asciidoc, but also will render it
differently for the user (usually with a typewriter font, which becomes
bold in roff output).
Though curiously the case of `#` in git-fast-import seems not to get
marked as <code> in the html output (even though the nearby `LF` does).
I wonder if there is some special treatment of `#` or something.
> If _<message>_ begins with one or more whitespaces followed
> -by "#", it is used as-is. If it begins with "#", a space is
> +by "\#", it is used as-is. If it begins with "\#", a space is
> prepended before it is used. Otherwise, a string " # " (a
> space followed by a hash followed by a space) is prepended
I saw the comment on round 1 about this second "#" on the line. But
while we are here, should we be doing the one in the context, too?
-Peff
^ permalink raw reply
* [PATCH v2] log: improve --follow following renames for non-linear history
From: Miklos Vajna @ 2026-06-11 6:18 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git
In-Reply-To: <xmqqpl21vzj2.fsf@gitster.g>
Have a repo with a subtree merge, do a 'git log --follow prefix/test.c',
the output only contains history in the outer repo, not commits that
were merged via a subtree merge.
What happens is that 'git log --follow' stores the followed path only in
opt->diffopt.pathspec, so in case the commit history is non-linear, and
multiple parents have renames to the followed path, then the end result
isn't really defined: the first commit that happens to be visited in one
of the parents update opt->diffopt.pathspec, and from that point, only
that updated path is visited.
Fix the problem by introducing a commit -> paths map
(follow_pathspec_slab) that stores what will be paths to follow when
visiting that parent. At the top of log_tree_commit(), if the slab has
an entry for this commit, we replace opt->diffopt.pathspec with paths
from this entry, so the correct paths are followed, even if an unrelated
sub-tree changed the paths to be followed to something else. After
log_tree_diff() runs, we record each parent's paths in the slab. As a
result, the walk order doesn't matter, which was exactly the source of
problems previously.
This helps with subtree merges (rename happens inside the merge commit),
but also fixes the general case when the rename happens in the history
of parents, not in the merge commit itself. This does not remove the
limitation that only a single path can be specified on the command-line,
but we now do follow multiple paths instead of a "last write wins"
situation when determining what path to follow for a specific commit
with multiple previously visited children.
---
Hi Junio,
On Mon, Jun 08, 2026 at 08:10:25AM -0700, Junio C Hamano <gitster@pobox.com> wrote:
> When describing a problematic symptom you are trying to improve, you
> should talk about the current state of the system in the present
> tense. "used to store" makes it sound like in ancient times back
> when Linus wrote the first version of this feature it was so, but a
> few years ago that changed, but that is not what you want to say, is
> it?
>
> The above may sound picky, but using the consistent style of
> description makes it easier to follow the thought process,
> especially when you need to read many commits to understand what is
> going on.
Makes sense, I now fixed this.
> Can a "map" cut it?
>
> If a history forked at commit A, with two children commit B and
> commit C, and you started traversing the history from a much later
> descendant M that merges these two lines of history (i.e., M^1
> contains B, M^2 contains C, and A==B^1==C^1), while traversing down
> from M to B you may find that you need to follow path1 and similarly
> somewhere between M down to C the path you are following may be
> path2. And the traversal meets at A. The slab records path1 for B
> and path2 for C. Wouldn't you need to be able to store both path1
> and path2 for commit A? What path do you need to pay attention to
> when traversing past A to its ancestors?
Indeed, I focused on merge commits and their parents and I did not
consider that slab[A] may be set to path1 when visiting one parent and
then slab[A] may be set to path2 when visiting an other parent -- even
if "A" itself is just a plain commit with no renames and is not a merge.
Here is an updated version, where I changed the value of
follow_pathspec_slab to be a string_list, and appended a new test that
shows we now handle this case.
Thanks,
Miklos
Documentation/config/log.adoc | 3 +-
log-tree.c | 133 ++++++++++++++++++++++++++++++++++
log-tree.h | 1 +
revision.c | 2 +
revision.h | 4 +
t/meson.build | 1 +
t/t4218-log-follow-merge.sh | 119 ++++++++++++++++++++++++++++++
7 files changed, 261 insertions(+), 2 deletions(-)
create mode 100755 t/t4218-log-follow-merge.sh
diff --git a/Documentation/config/log.adoc b/Documentation/config/log.adoc
index f20cc25cd7..757a7be196 100644
--- a/Documentation/config/log.adoc
+++ b/Documentation/config/log.adoc
@@ -53,8 +53,7 @@ This is the same as the `--decorate` option of the `git log`.
`log.follow`::
If `true`, `git log` will act as if the `--follow` option was used when
a single <path> is given. This has the same limitations as `--follow`,
- i.e. it cannot be used to follow multiple files and does not work well
- on non-linear history.
+ i.e. it cannot be used to follow multiple files.
`log.graphColors`::
A list of colors, separated by commas, that can be used to draw
diff --git a/log-tree.c b/log-tree.c
index 7e048701d0..f6f396be22 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -3,6 +3,7 @@
#include "git-compat-util.h"
#include "commit-reach.h"
+#include "commit-slab.h"
#include "config.h"
#include "diff.h"
#include "diffcore.h"
@@ -1089,6 +1090,104 @@ static int do_remerge_diff(struct rev_info *opt,
return !opt->loginfo;
}
+/* Per-commit paths storage for --follow across merges */
+define_commit_slab(follow_pathspec_slab, struct string_list);
+
+static const char *pathspec_single_path(const struct pathspec *ps)
+{
+ if (ps->nr != 1)
+ return NULL;
+ return ps->items[0].match;
+}
+
+static void set_pathspec_to_paths(struct pathspec *ps,
+ const struct string_list *paths)
+{
+ const char **argv;
+ struct string_list_item *item;
+ int i = 0;
+
+ clear_pathspec(ps);
+ if (!paths->nr)
+ return;
+ ALLOC_ARRAY(argv, paths->nr + 1);
+ for_each_string_list_item(item, paths)
+ argv[i++] = item->string;
+ argv[i] = NULL;
+ parse_pathspec(ps,
+ PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+ PATHSPEC_LITERAL_PATH, "", argv);
+ free(argv);
+}
+
+static struct string_list *get_follow_pathspec_at(struct rev_info *opt,
+ struct commit *c)
+{
+ struct string_list *list;
+
+ if (!opt->follow_pathspec_slab) {
+ opt->follow_pathspec_slab = xmalloc(sizeof(*opt->follow_pathspec_slab));
+ init_follow_pathspec_slab(opt->follow_pathspec_slab);
+ }
+ list = follow_pathspec_slab_at(opt->follow_pathspec_slab, c);
+ if (!list->strdup_strings)
+ list->strdup_strings = 1;
+ return list;
+}
+
+static void remember_follow_pathspec(struct rev_info *opt,
+ struct commit *c, const char *path)
+{
+ if (!path)
+ return;
+ string_list_insert(get_follow_pathspec_at(opt, c), path);
+}
+
+static void free_follow_pathspec_slot(struct string_list *slot)
+{
+ string_list_clear(slot, 0);
+}
+
+void release_follow_pathspec_slab(struct rev_info *opt)
+{
+ if (!opt->follow_pathspec_slab)
+ return;
+ deep_clear_follow_pathspec_slab(opt->follow_pathspec_slab,
+ free_follow_pathspec_slot);
+ FREE_AND_NULL(opt->follow_pathspec_slab);
+}
+
+/* Compute a path to follow in parent, if there is one */
+static void propagate_follow_pathspec_to_parent(struct rev_info *opt,
+ const char *path,
+ struct commit *commit,
+ struct commit *parent)
+{
+ struct diff_options diff_opts;
+ const char *paths[2] = { path, NULL };
+ const char *out_path;
+
+ parse_commit_or_die(parent);
+ repo_diff_setup(opt->diffopt.repo, &diff_opts);
+ parse_pathspec(&diff_opts.pathspec,
+ PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+ PATHSPEC_LITERAL_PATH, "", paths);
+ diff_opts.flags.recursive = 1;
+ diff_opts.flags.follow_renames = 1;
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_setup_done(&diff_opts);
+ diff_tree_oid(get_commit_tree_oid(parent),
+ get_commit_tree_oid(commit),
+ "", &diff_opts);
+
+ out_path = pathspec_single_path(&diff_opts.pathspec);
+ if (out_path)
+ remember_follow_pathspec(opt, parent, out_path);
+
+ diff_queue_clear(&diff_queued_diff);
+ diff_free(&diff_opts);
+}
+
/*
* Show the diff of a commit.
*
@@ -1173,12 +1272,30 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
int shown;
/* maybe called by e.g. cmd_log_walk(), maybe stand-alone */
int no_free = opt->diffopt.no_free;
+ int saved_follow_renames = 0;
+ struct string_list *paths = NULL;
log.commit = commit;
log.parent = NULL;
opt->loginfo = &log;
opt->diffopt.no_free = 1;
+ /* Any recorded paths for this commit? If so, restore it */
+ if (opt->diffopt.flags.follow_renames) {
+ paths = get_follow_pathspec_at(opt, commit);
+ if (!paths->nr) {
+ const char *path = pathspec_single_path(&opt->diffopt.pathspec);
+ if (path)
+ string_list_insert(paths, path);
+ }
+ set_pathspec_to_paths(&opt->diffopt.pathspec, paths);
+ if (paths->nr > 1) {
+ /* diff_check_follow_pathspec() doesn't handle multiple paths */
+ saved_follow_renames = opt->diffopt.flags.follow_renames;
+ opt->diffopt.flags.follow_renames = 0;
+ }
+ }
+
/* NEEDSWORK: no restoring of no_free? Why? */
if (opt->line_level_traverse)
return line_log_print(opt, commit);
@@ -1195,6 +1312,22 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
fprintf(opt->diffopt.file, "\n%s\n", opt->break_bar);
if (shown)
show_diff_of_diff(opt);
+
+ if (saved_follow_renames)
+ opt->diffopt.flags.follow_renames = saved_follow_renames;
+
+ /* Record what paths each parent of this commit should use */
+ if (opt->diffopt.flags.follow_renames && paths) {
+ struct commit_list *parents = get_saved_parents(opt, commit);
+ struct commit_list *p;
+ struct string_list_item *item;
+ for (p = parents; p; p = p->next) {
+ for_each_string_list_item(item, paths)
+ propagate_follow_pathspec_to_parent(opt,
+ item->string, commit, p->item);
+ }
+ }
+
opt->loginfo = NULL;
maybe_flush_or_die(opt->diffopt.file, "stdout");
opt->diffopt.no_free = no_free;
diff --git a/log-tree.h b/log-tree.h
index 07924be8bc..e8679b6c4a 100644
--- a/log-tree.h
+++ b/log-tree.h
@@ -26,6 +26,7 @@ struct decoration_options {
int parse_decorate_color_config(const char *var, const char *slot_name, const char *value);
int log_tree_diff_flush(struct rev_info *);
int log_tree_commit(struct rev_info *, struct commit *);
+void release_follow_pathspec_slab(struct rev_info *);
void show_log(struct rev_info *opt);
void format_decorations(struct strbuf *sb, const struct commit *commit,
enum git_colorbool use_color, const struct decoration_options *opts);
diff --git a/revision.c b/revision.c
index 5693618be4..caa85fb4c6 100644
--- a/revision.c
+++ b/revision.c
@@ -26,6 +26,7 @@
#include "decorate.h"
#include "string-list.h"
#include "line-log.h"
+#include "log-tree.h"
#include "mailmap.h"
#include "commit-slab.h"
#include "cache-tree.h"
@@ -3284,6 +3285,7 @@ void release_revisions(struct rev_info *revs)
line_log_free(revs);
oidset_clear(&revs->missing_commits);
release_revisions_bloom_keyvecs(revs);
+ release_follow_pathspec_slab(revs);
}
static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
diff --git a/revision.h b/revision.h
index c9a11827cc..607113ca74 100644
--- a/revision.h
+++ b/revision.h
@@ -65,6 +65,7 @@ struct repository;
struct rev_info;
struct string_list;
struct saved_parents;
+struct follow_pathspec_slab;
struct bloom_keyvec;
struct bloom_filter_settings;
struct option;
@@ -354,6 +355,9 @@ struct rev_info {
/* copies of the parent lists, for --full-diff display */
struct saved_parents *saved_parents_slab;
+ /* per-commit pathspec for --follow across merges */
+ struct follow_pathspec_slab *follow_pathspec_slab;
+
struct commit_list *previous_parents;
struct commit_list *ancestry_path_bottoms;
const char *break_bar;
diff --git a/t/meson.build b/t/meson.build
index c5832fee05..faecae2b50 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -576,6 +576,7 @@ integration_tests = [
't4215-log-skewed-merges.sh',
't4216-log-bloom.sh',
't4217-log-limit.sh',
+ 't4218-log-follow-merge.sh',
't4252-am-options.sh',
't4253-am-keep-cr-dos.sh',
't4254-am-corrupt.sh',
diff --git a/t/t4218-log-follow-merge.sh b/t/t4218-log-follow-merge.sh
new file mode 100755
index 0000000000..dcb0c937d7
--- /dev/null
+++ b/t/t4218-log-follow-merge.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+test_description='Test --follow follows renames across merges'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+test_expect_success 'setup subtree-merged repository' '
+ git init inner &&
+ echo inner >inner/inner.txt &&
+ git -C inner add inner.txt &&
+ git -C inner commit -m "inner init" &&
+
+ git init outer &&
+ echo outer >outer/outer.txt &&
+ git -C outer add outer.txt &&
+ git -C outer commit -m "outer init" &&
+
+ git -C outer fetch ../inner master &&
+ git -C outer merge -s ours --no-commit --allow-unrelated-histories \
+ FETCH_HEAD &&
+ git -C outer read-tree --prefix=inner/ -u FETCH_HEAD &&
+ git -C outer commit -m "Merge inner repo into inner/ subdirectory"
+'
+
+test_expect_success '--follow finds the pre-merge commit through a subtree merge' '
+ git -C outer log --follow --pretty=tformat:%s inner/inner.txt >actual &&
+ echo "inner init" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'setup merge of two branches that both renamed a file to README' '
+ git init foo &&
+ mkdir foo/foo &&
+ echo "foo readme" >foo/foo/README &&
+ git -C foo add foo/README &&
+ git -C foo commit -m "add foo README" &&
+
+ git -C foo mv foo/README README &&
+ git -C foo commit -m "promote foo README to toplevel" &&
+
+ echo "foo c" >foo/foo.c &&
+ git -C foo add foo.c &&
+ git -C foo commit -m "add foo C impl" &&
+
+ git init bar &&
+ mkdir bar/bar &&
+ echo "bar readme" >bar/bar/README &&
+ git -C bar add bar/README &&
+ git -C bar commit -m "add bar README" &&
+
+ git -C bar mv bar/README README &&
+ git -C bar commit -m "promote bar README to toplevel" &&
+
+ echo "bar c" >bar/bar.c &&
+ git -C bar add bar.c &&
+ git -C bar commit -m "add bar C impl" &&
+
+ git -C foo fetch ../bar master &&
+ git -C foo merge -s ours --no-commit --allow-unrelated-histories \
+ FETCH_HEAD &&
+ git -C foo checkout FETCH_HEAD -- bar.c &&
+ git -C foo commit -m "merge bar into foo"
+'
+
+test_expect_success '--follow follows renames across both sides of a merge' '
+ git -C foo log --follow --pretty=tformat:%s README >actual &&
+ sort actual >actual.sorted &&
+ cat >expect <<-\EOF &&
+ add bar README
+ add foo README
+ promote bar README to toplevel
+ promote foo README to toplevel
+ EOF
+ test_cmp expect actual.sorted
+'
+
+# When two branches rename a different file to the same name and then meet again
+# in a merge, log --follow needs to keep track both paths.
+test_expect_success 'setup criss-cross merge where two paths converge in ancestor' '
+ git init crisscross &&
+ echo "alpha content" >crisscross/alpha.txt &&
+ git -C crisscross add alpha.txt &&
+ git -C crisscross commit -m "root: add alpha.txt" &&
+
+ echo "beta content" >crisscross/beta.txt &&
+ git -C crisscross add beta.txt &&
+ git -C crisscross commit -m "fork: add beta.txt" &&
+
+ git -C crisscross checkout -b branchB &&
+ git -C crisscross mv alpha.txt combined.txt &&
+ git -C crisscross rm beta.txt &&
+ git -C crisscross commit -m "B: rename alpha to combined" &&
+
+ git -C crisscross checkout master &&
+ git -C crisscross checkout -b branchC &&
+ git -C crisscross mv beta.txt combined.txt &&
+ git -C crisscross rm alpha.txt &&
+ git -C crisscross commit -m "C: rename beta to combined" &&
+
+ git -C crisscross checkout branchB &&
+ git -C crisscross merge -s ours -m "merge C into B" branchC
+'
+
+test_expect_success '--follow follows two diverged paths past their common ancestor' '
+ git -C crisscross log --follow --pretty=tformat:%s combined.txt >actual &&
+ sort actual >actual.sorted &&
+ cat >expect <<-\EOF &&
+ B: rename alpha to combined
+ C: rename beta to combined
+ fork: add beta.txt
+ root: add alpha.txt
+ EOF
+ test_cmp expect actual.sorted
+'
+
+test_done
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2 3/3] doc: git-config: escape erroneous highlight markup
From: Jeff King @ 2026-06-11 6:24 UTC (permalink / raw)
To: Tuomas Ahola; +Cc: git, Kristoffer Haugsbakk, Junio C Hamano
In-Reply-To: <20260611061156.GC2187173@coredump.intra.peff.net>
On Thu, Jun 11, 2026 at 02:11:57AM -0400, Jeff King wrote:
> Though curiously the case of `#` in git-fast-import seems not to get
> marked as <code> in the html output (even though the nearby `LF` does).
> I wonder if there is some special treatment of `#` or something.
Ah, weird, it has to do with our config file.
If I do this (not in the git repository):
echo 'This is a literal `#` symbol.' >foo.adoc
asciidoc foo.adoc
grep -i symbol foo.html
then I get <code> markers, like:
<div class="paragraph"><p>This is a literal <code>#</code> symbol.</p></div>
But if I build with:
asciidoc -f path/to/git/Documentation/asciidoc.conf foo.adoc
then the grep shows:
<div class="paragraph"><p>This is a literal # symbol.</p></div>
Looks like it is due to our [literal-inlinemacro] definition, which
comes from 974cdca345 (doc: introduce a synopsis typesetting,
2024-09-24). I think this might have been an unintended side effect.
+cc the author of that commit.
For the purposes of your series, I think we can ignore any issues with
[literal-inlinemacro] for the moment, and decide on "\" versus ``
depending on which we prefer.
-Peff
^ permalink raw reply
* Re: [PATCH v2 3/3] doc: git-config: escape erroneous highlight markup
From: Jeff King @ 2026-06-11 6:25 UTC (permalink / raw)
To: Tuomas Ahola
Cc: git, Kristoffer Haugsbakk, Junio C Hamano, Jean-Noël Avila
In-Reply-To: <20260611062423.GA2189088@coredump.intra.peff.net>
[and naturally I forgot to cc Jean-Noël; resending, sorry for the noise]
On Thu, Jun 11, 2026 at 02:24:23AM -0400, Jeff King wrote:
> On Thu, Jun 11, 2026 at 02:11:57AM -0400, Jeff King wrote:
>
> > Though curiously the case of `#` in git-fast-import seems not to get
> > marked as <code> in the html output (even though the nearby `LF` does).
> > I wonder if there is some special treatment of `#` or something.
>
> Ah, weird, it has to do with our config file.
>
> If I do this (not in the git repository):
>
> echo 'This is a literal `#` symbol.' >foo.adoc
> asciidoc foo.adoc
> grep -i symbol foo.html
>
> then I get <code> markers, like:
>
> <div class="paragraph"><p>This is a literal <code>#</code> symbol.</p></div>
>
> But if I build with:
>
> asciidoc -f path/to/git/Documentation/asciidoc.conf foo.adoc
>
> then the grep shows:
>
> <div class="paragraph"><p>This is a literal # symbol.</p></div>
>
> Looks like it is due to our [literal-inlinemacro] definition, which
> comes from 974cdca345 (doc: introduce a synopsis typesetting,
> 2024-09-24). I think this might have been an unintended side effect.
> +cc the author of that commit.
>
> For the purposes of your series, I think we can ignore any issues with
> [literal-inlinemacro] for the moment, and decide on "\" versus ``
> depending on which we prefer.
>
> -Peff
^ permalink raw reply
* Re: [PATCH 3/7] setup: remove global `git_work_tree_cfg` variable
From: Patrick Steinhardt @ 2026-06-11 6:36 UTC (permalink / raw)
To: Justin Tobler; +Cc: git
In-Reply-To: <ainXM84fGggtEZzM@denethor>
On Wed, Jun 10, 2026 at 04:52:12PM -0500, Justin Tobler wrote:
> On 26/06/10 08:56AM, Patrick Steinhardt wrote:
> > diff --git a/setup.c b/setup.c
> > index 52228b42a1..71fc6b33da 100644
> > --- a/setup.c
> > +++ b/setup.c
> > @@ -31,9 +31,6 @@ enum allowed_bare_repo {
> > ALLOWED_BARE_REPO_ALL,
> > };
> >
> > -/* This is set by setup_git_directory_gently() and/or git_default_config() */
> > -static char *git_work_tree_cfg;
> > -
> > static struct startup_info the_startup_info;
> > struct startup_info *startup_info = &the_startup_info;
> > const char *tmp_original_cwd;
> > @@ -799,13 +796,10 @@ static int check_repository_format_gently(const char *gitdir,
> > }
> >
> > if (!has_common) {
> > - if (candidate->is_bare != -1) {
> > + if (candidate->is_bare != -1)
> > is_bare_repository_cfg = candidate->is_bare;
> > - }
> > - if (candidate->work_tree) {
> > - free(git_work_tree_cfg);
> > - git_work_tree_cfg = xstrdup(candidate->work_tree);
>
> Ok, we no longer set `git_work_tree_cfg` in favor of just relying on the
> worktree specified in the repository format.
>
> > - }
> > + } else {
> > + FREE_AND_NULL(candidate->work_tree);
>
> Huh, we were not previously freeing the worktree here, but I assume this
> to avoid a resource leak?
This is in fact a required change. Before this patch this here was the
place where we populated `git_work_tree_cfg`, and that variable was then
later on applied to the repository. So the implicit `else` branch was
basically just `git_work_tree_cfg = NULL`, but we didn't have to do that
as it already was set to `NULL`.
With the new code though we're not setting `git_work_tree_cfg` anymore
and instead directly populate from `candidate->work_tree`. But that also
means that we now have to clear that variable to retain previous
semantics.
I'll add an explanation to the commit message.
Patrick
^ permalink raw reply
* Re: [PATCH v2] describe: limit default ref iteration to tags
From: Jeff King @ 2026-06-11 6:37 UTC (permalink / raw)
To: D. Ben Knoble; +Cc: Tamir Duberstein, git, Junio C Hamano, Patrick Steinhardt
In-Reply-To: <CALnO6CB-9a=P4Os90978YzEH=3iYEHwSbG2oLv9sxVBjBfchMA@mail.gmail.com>
On Tue, Jun 09, 2026 at 09:40:25AM -0400, D. Ben Knoble wrote:
> > Given the discussion in earlier rounds and sibling topics, I assume the
> > commit message here was AI-generated. And it's OK in the sense that it
> > is describing what happened and I assume is entirely accurate. But as a
> > human reader, it feels so much more verbose than what I'd expect, as it
> > is full of semi-irrelevant details. Why set --warmup and --runs? Why
> > bother with --command-name, which just means you have to show the
> > commands separately anyway? Is the amount of RAM in the machine
> > important for this test? Surely it could be if it was absurdly tiny, but
> > in general, no, I would not expect it to be.
>
> [You probably know this] It is common in academic papers to report
> benchmarks with details about the hardware and how they were run to
> contextualize the results and help with reproducibility.
Yeah, I almost drew the same comparison in my original email. I agree
that having every last detail _could_ help with reproducing in the
future. And that's important when producing a high quality dataset or
academic paper. But the tradeoff seems worse in a commit message, where
it is easy to obscure the main point or overwhelm the reader in what is
otherwise a short-ish document.
> Of course, Git's commits do not form an academic paper… so I have no
> real opinion on what to see here. But I've seen a few other mails
> where having perf test outputs or similar was suggested (maybe that
> was to be reserved for the cover letter? idk).
>
> _If_ we show all the hyperfine details, I think it's reasonable to use
> --command-name to make distinguishing the versions easy, unless it's
> obvious from the path/to/git in each benchmark (which I think I've
> seen from Peff's benchmark reports before?).
Yeah, I tend to copy the various versions to their own executables,
which gives them short names (so you see "./git.old vs ./git.new" or
something). That's not always completely obvious either, though.
The "short" example I showed may have been a little hyperbolic. I'm OK
with hyperfine output in general, and sometimes show it myself. It is
kind of verbose, but occasionally the distribution of values, or user vs
system vs clock times are important. I'm even OK with --command-name if
it makes things more readable.
I guess what I was really responding to is that I think it is helpful
when the incoming data is cut down to the minimal set of useful details.
That helps a reader immediately assess what is important to the point
being made. Humans tend to do this naturally because we are lazy and
do not want to bother typing or pasting the uninteresting details.
Program output (whether AI or just verbose software) has less of that
impulse.
> Someone with better lore skills can probably dig up a few exemplars of
> how to write about performance in a commit message?
Probably searching for emails from René. :)
-Peff
^ permalink raw reply
* Re: [PATCH v2] describe: limit default ref iteration to tags
From: Jeff King @ 2026-06-11 6:41 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: Tamir Duberstein, git, Junio C Hamano
In-Reply-To: <aika_Q0rWhcI6eXR@pks.im>
On Wed, Jun 10, 2026 at 10:08:51AM +0200, Patrick Steinhardt wrote:
> > Given the discussion in earlier rounds and sibling topics, I assume the
> > commit message here was AI-generated. And it's OK in the sense that it
> > is describing what happened and I assume is entirely accurate. But as a
> > human reader, it feels so much more verbose than what I'd expect, as it
> > is full of semi-irrelevant details. Why set --warmup and --runs? Why
> > bother with --command-name, which just means you have to show the
> > commands separately anyway? Is the amount of RAM in the machine
> > important for this test? Surely it could be if it was absurdly tiny, but
> > in general, no, I would not expect it to be.
>
> I agree. Earlier this week I also drafted a message that was going down
> this angle, but I think I didn't end up sending it to the mailing list.
> Or at least I'm not able to find it anymore.
>
> To me the biggest problem is not the verbosity, even though it _is_
> overly verbose. The bigger problem though is the incoherence of the
> story that the commit message is trying to tell where it jumps around
> randomly. It almost feels like rambling to me, and that makes it
> extremely hard to follow the narrative and figure out what the message
> even wants to tell the reader in the first place.
Thanks, this hits directly at the point I was trying to make (I have
trouble sometimes with verbosity, too!). A commit message should
primarily be laying out a narrative about why we are going from the old
state to the new, with supporting arguments. Sometimes you need
back-story for that, sometimes not. Sometimes you need to discuss
alternatives, sometimes you need specific details about the platform or
versions used for testing, and so on.
> I very much think that we should and even have to expect that
> contributors adapt, because if we don't we will basically reinforce
> whatever AI is doing right now and increase the load on reviewers even
> more.
>
> I also think that we should reserve the right to reject a patch series
> completely in case we notice that we're basically just talking to a
> middleman that sits between an AI prompt and us (please note that I
> don't refer to this patch series specifically, this is more of a general
> statement). My assumption is that this will become more important as AI
> gets established in more workflows. The number of patch series that look
> sane on the surface but that are utter garbage will very likely increase
> quite significantly going forward.
Yep, agreed.
-Peff
^ permalink raw reply
* [PATCH v2 0/7] setup: drop global state
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260610-b4-pks-setup-drop-global-state-v1-0-5dff3eec8f06@pks.im>
Hi,
this patch series continues to refactor "setup.c", where the focus is to
drop remaining global state that we have in "setup.c". The most
important consequence of this is that we don't need to rely on
`the_repository` in `is_bare_repository()` anymore.
This series is built on top of 1ff279f340 (The 13th batch, 2026-06-09)
with ps/setup-centralize-odb-creation at 42b9d3dc9d (setup: construct
object database in `apply_repository_format()`, 2026-06-04) merged into
it.
Changes in v2:
- Improve documentation for some aspects of `check_repository_format_gently()`.
- Link to v1: https://patch.msgid.link/20260610-b4-pks-setup-drop-global-state-v1-0-5dff3eec8f06@pks.im
Thanks!
Patrick
---
Patrick Steinhardt (7):
builtin/init: stop modifying global `git_work_tree_cfg` variable
builtin/init: simplify logic to configure worktree
setup: remove global `git_work_tree_cfg` variable
builtin/init: stop modifying `is_bare_repository_cfg`
environment: split up concerns of `is_bare_repository_cfg`
environment: stop using `the_repository` in `is_bare_repository()`
treewide: drop USE_THE_REPOSITORY_VARIABLE
attr.c | 4 ++--
builtin/bisect.c | 2 +-
builtin/blame.c | 2 +-
builtin/check-attr.c | 2 +-
builtin/fetch.c | 2 +-
builtin/gc.c | 2 +-
builtin/history.c | 2 +-
builtin/init-db.c | 44 +++++++++++++++++++++++++-----------------
builtin/repack.c | 3 +--
builtin/repo.c | 2 +-
builtin/reset.c | 2 +-
builtin/rev-parse.c | 2 +-
environment.c | 10 +++-------
environment.h | 6 ++----
git.c | 2 +-
mailmap.c | 6 ++----
refs/files-backend.c | 2 +-
refs/reftable-backend.c | 4 +---
repository.c | 1 +
repository.h | 7 +++++++
setup.c | 51 +++++++++++++++++++++++++++++--------------------
setup.h | 6 ++++++
transport.c | 4 ++--
worktree.c | 4 ++--
24 files changed, 97 insertions(+), 75 deletions(-)
Range-diff versus v1:
1: 0281a4bca9 = 1: 96b71f5223 builtin/init: stop modifying global `git_work_tree_cfg` variable
2: 6fdc8d77e8 = 2: a51c0ff79d builtin/init: simplify logic to configure worktree
3: ce31595ff5 ! 3: e06393ddc5 setup: remove global `git_work_tree_cfg` variable
@@ Commit message
Refactor the code so that we instead use the worktree configuration as
discovered via the repository format. Drop the global variable.
+ Note that in `check_repository_format_gently()` we now have to free the
+ candidate work tree variable. This change is required to retain previous
+ semantics: before we essentially had an implicit `else` branch where we
+ set `git_work_tree_cfg = NULL`, but we were able to elide that branch
+ because we already knew that it would be `NULL` anyway. Now that we use
+ the candidate work tree directly to populate the repository's work tree
+ though we have to clear it to retain those semantics.
+
Signed-off-by: Patrick Steinhardt <ps@pks.im>
## setup.c ##
4: 6a69dc853c = 4: 628ed54c8c builtin/init: stop modifying `is_bare_repository_cfg`
5: afa2d8bbda ! 5: 02ceaf4a20 environment: split up concerns of `is_bare_repository_cfg`
@@ setup.c: static int check_repository_format_gently(const char *gitdir,
+ * dictate bareness; it is inherited from the main worktree.
+ */
+ candidate->is_bare = -1;
++
++ /*
++ * Furthermore, "core.worktree" is supposed to be ignored when
++ * we have a commondir configured, unless it comes from the
++ * per-worktree configuration.
++ */
FREE_AND_NULL(candidate->work_tree);
}
6: 04849a2cb5 = 6: a08aef5685 environment: stop using `the_repository` in `is_bare_repository()`
7: 78191c7557 = 7: f93f6599df treewide: drop USE_THE_REPOSITORY_VARIABLE
---
base-commit: f5a08a09a0fdf0fc2a355eba7979e2cfd65659e5
change-id: 20260422-b4-pks-setup-drop-global-state-6b1374aed5db
^ permalink raw reply
* [PATCH v2 1/7] builtin/init: stop modifying global `git_work_tree_cfg` variable
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
When executing git-init(1) we need to figure out the final location of
the worktree. This location can be configured in a couple of ways: via
an environment variable, via the preexisting "core.worktree" config in
case we're reinitializing, or implicitly when reinitializing a non-bare
repository.
When checking for the worktree location in "builtin/init-db.c" we
populate any potentially-discovered value both by setting the global
`git_work_tree_cfg` variable and via `set_git_work_tree()`, which
ultimately ends up modifying `struct repository::worktree`.
Modifying `git_work_tree_cfg` is unnecessary though: we configure the
worktree in `create_default_files()`, and that function derives the
worktree location via `repo_get_work_tree()`. Consequently, propagating
the worktree via `set_git_work_tree()` is sufficient.
Stop munging `git_work_tree_cfg` and make it file-local to "setup.c" and
function-local to `cmd_init_db()`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/init-db.c | 4 ++++
environment.c | 3 ---
environment.h | 1 -
setup.c | 3 +++
4 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index c55517ad94..01bc27904e 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -229,6 +229,8 @@ int cmd_init_db(int argc,
if (!is_bare_repository_cfg) {
const char *git_dir_parent = strrchr(git_dir, '/');
+ char *git_work_tree_cfg = NULL;
+
if (git_dir_parent) {
char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
git_work_tree_cfg = real_pathdup(rel, 1);
@@ -243,6 +245,8 @@ int cmd_init_db(int argc,
if (access(repo_get_work_tree(the_repository), X_OK))
die_errno (_("Cannot access work tree '%s'"),
repo_get_work_tree(the_repository));
+
+ free(git_work_tree_cfg);
}
else {
if (real_git_dir)
diff --git a/environment.c b/environment.c
index fc3ed8bb1c..4e86335f25 100644
--- a/environment.c
+++ b/environment.c
@@ -100,9 +100,6 @@ int auto_comment_line_char;
bool warn_on_auto_comment_char;
#endif /* !WITH_BREAKING_CHANGES */
-/* This is set by setup_git_directory_gently() and/or git_default_config() */
-char *git_work_tree_cfg;
-
/*
* Repository-local GIT_* environment variables; see environment.h for details.
*/
diff --git a/environment.h b/environment.h
index ccfcf37bfb..5d6e4e6c1b 100644
--- a/environment.h
+++ b/environment.h
@@ -149,7 +149,6 @@ int have_git_dir(void);
extern int is_bare_repository_cfg;
int is_bare_repository(void);
-extern char *git_work_tree_cfg;
/* Environment bits from configuration mechanism */
extern int trust_executable_bit;
diff --git a/setup.c b/setup.c
index b4652651df..52228b42a1 100644
--- a/setup.c
+++ b/setup.c
@@ -31,6 +31,9 @@ enum allowed_bare_repo {
ALLOWED_BARE_REPO_ALL,
};
+/* This is set by setup_git_directory_gently() and/or git_default_config() */
+static char *git_work_tree_cfg;
+
static struct startup_info the_startup_info;
struct startup_info *startup_info = &the_startup_info;
const char *tmp_original_cwd;
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
* [PATCH v2 2/7] builtin/init: simplify logic to configure worktree
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
In the preceding commit we have stopped modifying the global
`git_work_tree_cfg` variable. With this change there's now some code
paths where we end up setting the local `git_work_tree_cfg` variable,
but without actually using the value for anything.
Refactor the code a bit so that we only set the worktree configuration
in case it's actually needed. Furthermore, reflow it a bit to make the
code easier to follow.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/init-db.c | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 01bc27904e..b4343c2804 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -229,24 +229,29 @@ int cmd_init_db(int argc,
if (!is_bare_repository_cfg) {
const char *git_dir_parent = strrchr(git_dir, '/');
- char *git_work_tree_cfg = NULL;
- if (git_dir_parent) {
- char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
- git_work_tree_cfg = real_pathdup(rel, 1);
- free(rel);
- }
- if (!git_work_tree_cfg)
- git_work_tree_cfg = xgetcwd();
- if (work_tree)
+ if (work_tree) {
set_git_work_tree(the_repository, work_tree);
- else
- set_git_work_tree(the_repository, git_work_tree_cfg);
+ } else {
+ char *work_tree_cfg = NULL;
+
+ if (git_dir_parent) {
+ char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
+ work_tree_cfg = real_pathdup(rel, 1);
+ free(rel);
+ }
+
+ if (!work_tree_cfg)
+ work_tree_cfg = xgetcwd();
+
+ set_git_work_tree(the_repository, work_tree_cfg);
+
+ free(work_tree_cfg);
+ }
+
if (access(repo_get_work_tree(the_repository), X_OK))
die_errno (_("Cannot access work tree '%s'"),
repo_get_work_tree(the_repository));
-
- free(git_work_tree_cfg);
}
else {
if (real_git_dir)
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
* [PATCH v2 3/7] setup: remove global `git_work_tree_cfg` variable
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
The global `git_work_tree_cfg` variable used to be modified by both
"setup.c" and by "builtin/init-db.c". We have refactored the latter user
to not use that variable at all anymore in a preceding commit, which
makes "setup.c" the only remaining user.
Even for "setup.c" it is unnecessary though, as we only ever set it to
the value we have stored in the discovered repository format. The
consequence is that we only ever set it in case we already have it set
to the same value in our discovered repository format, which makes it
redundant.
Refactor the code so that we instead use the worktree configuration as
discovered via the repository format. Drop the global variable.
Note that in `check_repository_format_gently()` we now have to free the
candidate work tree variable. This change is required to retain previous
semantics: before we essentially had an implicit `else` branch where we
set `git_work_tree_cfg = NULL`, but we were able to elide that branch
because we already knew that it would be `NULL` anyway. Now that we use
the candidate work tree directly to populate the repository's work tree
though we have to clear it to retain those semantics.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
setup.c | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/setup.c b/setup.c
index 52228b42a1..71fc6b33da 100644
--- a/setup.c
+++ b/setup.c
@@ -31,9 +31,6 @@ enum allowed_bare_repo {
ALLOWED_BARE_REPO_ALL,
};
-/* This is set by setup_git_directory_gently() and/or git_default_config() */
-static char *git_work_tree_cfg;
-
static struct startup_info the_startup_info;
struct startup_info *startup_info = &the_startup_info;
const char *tmp_original_cwd;
@@ -799,13 +796,10 @@ static int check_repository_format_gently(const char *gitdir,
}
if (!has_common) {
- if (candidate->is_bare != -1) {
+ if (candidate->is_bare != -1)
is_bare_repository_cfg = candidate->is_bare;
- }
- if (candidate->work_tree) {
- free(git_work_tree_cfg);
- git_work_tree_cfg = xstrdup(candidate->work_tree);
- }
+ } else {
+ FREE_AND_NULL(candidate->work_tree);
}
return 0;
@@ -1145,7 +1139,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
if (work_tree_env)
set_git_work_tree(repo, work_tree_env);
else if (is_bare_repository_cfg > 0) {
- if (git_work_tree_cfg) {
+ if (repo_fmt->work_tree) {
/* #22.2, #30 */
warning("core.bare and core.worktree do not make sense");
repo->worktree_config_is_bogus = true;
@@ -1156,15 +1150,15 @@ static const char *setup_explicit_git_dir(struct repository *repo,
free(gitfile);
return NULL;
}
- else if (git_work_tree_cfg) { /* #6, #14 */
- if (is_absolute_path(git_work_tree_cfg))
- set_git_work_tree(repo, git_work_tree_cfg);
+ else if (repo_fmt->work_tree) { /* #6, #14 */
+ if (is_absolute_path(repo_fmt->work_tree))
+ set_git_work_tree(repo, repo_fmt->work_tree);
else {
char *core_worktree;
if (chdir(gitdirenv))
die_errno(_("cannot chdir to '%s'"), gitdirenv);
- if (chdir(git_work_tree_cfg))
- die_errno(_("cannot chdir to '%s'"), git_work_tree_cfg);
+ if (chdir(repo_fmt->work_tree))
+ die_errno(_("cannot chdir to '%s'"), repo_fmt->work_tree);
core_worktree = xgetcwd();
if (chdir(cwd->buf))
die_errno(_("cannot come back to cwd"));
@@ -1217,7 +1211,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
return NULL;
/* --work-tree is set without --git-dir; use discovered one */
- if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || repo_fmt->work_tree) {
char *to_free = NULL;
const char *ret;
@@ -1267,7 +1261,7 @@ static const char *setup_bare_git_dir(struct repository *repo,
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
/* --work-tree is set without --git-dir; use discovered one */
- if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || repo_fmt->work_tree) {
static const char *gitdir;
gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
* [PATCH v2 4/7] builtin/init: stop modifying `is_bare_repository_cfg`
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
We're modifying `is_bare_repository_cfg` in "builtin/init.c" to indicate
whether the newly created repository is supposed to be a bare repository
or not.
This is ultimately unnecessary though: when initializing the repository
in `init_db()` we eventually set `is_bare_repository_cfg = !work_tree`,
so all that matters is whether or not we have a working tree configured,
and the working tree is set up in the non-bare in "builtin/init.c".
Stop modifying the global variable in "builtin/init.c" in favor of a
local variable.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/init-db.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index b4343c2804..52aa92fb0a 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,6 +81,7 @@ int cmd_init_db(int argc,
const char *template_dir = NULL;
char *template_dir_to_free = NULL;
unsigned int flags = 0;
+ int bare = is_bare_repository_cfg;
const char *object_format = NULL;
const char *ref_format = NULL;
const char *initial_branch = NULL;
@@ -90,7 +91,7 @@ int cmd_init_db(int argc,
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, N_("template-directory"),
N_("directory from which templates will be used")),
- OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
+ OPT_SET_INT(0, "bare", &bare,
N_("create a bare repository"), 1),
{
.type = OPTION_CALLBACK,
@@ -116,7 +117,7 @@ int cmd_init_db(int argc,
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
- if (real_git_dir && is_bare_repository_cfg == 1)
+ if (real_git_dir && bare == 1)
die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
if (real_git_dir && !is_absolute_path(real_git_dir))
@@ -160,7 +161,7 @@ int cmd_init_db(int argc,
} else if (0 < argc) {
usage(init_db_usage[0]);
}
- if (is_bare_repository_cfg == 1) {
+ if (bare == 1) {
char *cwd = xgetcwd();
setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
free(cwd);
@@ -187,7 +188,7 @@ int cmd_init_db(int argc,
*/
git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT));
work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT));
- if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
+ if ((!git_dir || bare == 1) && work_tree)
die(_("%s (or --work-tree=<directory>) not allowed without "
"specifying %s (or --git-dir=<directory>)"),
GIT_WORK_TREE_ENVIRONMENT,
@@ -224,10 +225,10 @@ int cmd_init_db(int argc,
strbuf_release(&sb);
}
- if (is_bare_repository_cfg < 0)
- is_bare_repository_cfg = guess_repository_type(git_dir);
+ if (bare < 0)
+ bare = guess_repository_type(git_dir);
- if (!is_bare_repository_cfg) {
+ if (!bare) {
const char *git_dir_parent = strrchr(git_dir, '/');
if (work_tree) {
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
* [PATCH v2 5/7] environment: split up concerns of `is_bare_repository_cfg`
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
The `is_bare_repository_cfg` variable tracks two different pieces of
information:
- It tracks whether the user has invoked git with the "--bare" flag,
which makes us treat any discovered Git repository as if it was a
bare repository.
- Otherwise it tracks whether the discovered `the_repository` is bare.
This makes the flag extremely confusing and creates a bit of a challenge
when handling multiple repositories in the same process.
Split up the concerns of this variable into two pieces:
- `startup_info.force_bare_repository` tracks whether the user has
passed the "--bare" flag. This is used as a hint to treat newly set
up repositories as bare regardless of whether or not they have a
worktree.
- `struct repository::bare_cfg` tracks whether or not a repository is
considered bare. This takes into account both whether the user has
passed "--bare" and the discovered state of the repository itself.
Whether or not a repository is bare is now resolved when checking the
repository's format, and is then later applied to the repository itself
via `apply_repository_format()`.
This enables a subsequent change where we make `is_bare_repository()`
not depend on global state anymore.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/init-db.c | 2 +-
environment.c | 5 ++---
environment.h | 1 -
git.c | 2 +-
repository.c | 1 +
repository.h | 7 +++++++
setup.c | 27 ++++++++++++++++++++-------
setup.h | 6 ++++++
worktree.c | 2 +-
9 files changed, 39 insertions(+), 14 deletions(-)
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 52aa92fb0a..566732c9f4 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -81,7 +81,7 @@ int cmd_init_db(int argc,
const char *template_dir = NULL;
char *template_dir_to_free = NULL;
unsigned int flags = 0;
- int bare = is_bare_repository_cfg;
+ int bare = startup_info->force_bare_repository ? 1 : -1;
const char *object_format = NULL;
const char *ref_format = NULL;
const char *initial_branch = NULL;
diff --git a/environment.c b/environment.c
index 4e86335f25..9d7c908c55 100644
--- a/environment.c
+++ b/environment.c
@@ -48,7 +48,6 @@ int has_symlinks = 1;
int minimum_abbrev = 4, default_abbrev = -1;
int ignore_case;
int assume_unchanged;
-int is_bare_repository_cfg = -1; /* unspecified */
int warn_on_object_refname_ambiguity = 1;
char *git_commit_encoding;
char *git_log_output_encoding;
@@ -136,7 +135,7 @@ const char *getenv_safe(struct strvec *argv, const char *name)
int is_bare_repository(void)
{
/* if core.bare is not 'false', let's see if there is a work tree */
- return is_bare_repository_cfg && !repo_get_work_tree(the_repository);
+ return the_repository->bare_cfg && !repo_get_work_tree(the_repository);
}
int have_git_dir(void)
@@ -342,7 +341,7 @@ int git_default_core_config(const char *var, const char *value,
}
if (!strcmp(var, "core.bare")) {
- is_bare_repository_cfg = git_config_bool(var, value);
+ the_repository->bare_cfg = git_config_bool(var, value);
return 0;
}
diff --git a/environment.h b/environment.h
index 5d6e4e6c1b..afb5bcf197 100644
--- a/environment.h
+++ b/environment.h
@@ -147,7 +147,6 @@ void repo_config_values_init(struct repo_config_values *cfg);
*/
int have_git_dir(void);
-extern int is_bare_repository_cfg;
int is_bare_repository(void);
/* Environment bits from configuration mechanism */
diff --git a/git.c b/git.c
index 36f08891ef..387eabe38c 100644
--- a/git.c
+++ b/git.c
@@ -255,7 +255,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
*envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
char *cwd = xgetcwd();
- is_bare_repository_cfg = 1;
+ startup_info->force_bare_repository = true;
setenv(GIT_DIR_ENVIRONMENT, cwd, 0);
free(cwd);
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
diff --git a/repository.c b/repository.c
index 187dd471c4..c1e91eb0da 100644
--- a/repository.c
+++ b/repository.c
@@ -73,6 +73,7 @@ void initialize_repository(struct repository *repo)
ALLOC_ARRAY(repo->index, 1);
index_state_init(repo->index, repo);
repo->check_deprecated_config = true;
+ repo->bare_cfg = -1;
repo_config_values_init(&repo->config_values_private_);
/*
diff --git a/repository.h b/repository.h
index 36e2db2633..7d649e32e7 100644
--- a/repository.h
+++ b/repository.h
@@ -117,6 +117,13 @@ struct repository {
bool worktree_initialized;
bool worktree_config_is_bogus;
+ /*
+ * Whether the repository is bare, as set by "core.bare" config or
+ * inferred during repository discovery. -1 means unset/unknown, 0
+ * means non-bare, 1 means bare.
+ */
+ int bare_cfg;
+
/*
* Path from the root of the top-level superproject down to this
* repository. This is only non-NULL if the repository is initialized
diff --git a/setup.c b/setup.c
index 71fc6b33da..32f14a8688 100644
--- a/setup.c
+++ b/setup.c
@@ -795,10 +795,22 @@ static int check_repository_format_gently(const char *gitdir,
has_common = 0;
}
- if (!has_common) {
- if (candidate->is_bare != -1)
- is_bare_repository_cfg = candidate->is_bare;
- } else {
+ if (startup_info->force_bare_repository) {
+ candidate->is_bare = 1;
+ FREE_AND_NULL(candidate->work_tree);
+ } else if (has_common) {
+ /*
+ * When sharing a common dir with another repository (e.g. a
+ * linked worktree), do not let this repository's config
+ * dictate bareness; it is inherited from the main worktree.
+ */
+ candidate->is_bare = -1;
+
+ /*
+ * Furthermore, "core.worktree" is supposed to be ignored when
+ * we have a commondir configured, unless it comes from the
+ * per-worktree configuration.
+ */
FREE_AND_NULL(candidate->work_tree);
}
@@ -1138,7 +1150,7 @@ static const char *setup_explicit_git_dir(struct repository *repo,
/* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
if (work_tree_env)
set_git_work_tree(repo, work_tree_env);
- else if (is_bare_repository_cfg > 0) {
+ else if (repo_fmt->is_bare > 0) {
if (repo_fmt->work_tree) {
/* #22.2, #30 */
warning("core.bare and core.worktree do not make sense");
@@ -1225,7 +1237,7 @@ static const char *setup_discovered_git_dir(struct repository *repo,
}
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
- if (is_bare_repository_cfg > 0) {
+ if (repo_fmt->is_bare > 0) {
set_git_dir(repo, gitdir, (offset != cwd->len));
if (chdir(cwd->buf))
die_errno(_("cannot come back to cwd"));
@@ -1762,6 +1774,7 @@ int apply_repository_format(struct repository *repo,
alternate_object_directories = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT));
}
+ repo->bare_cfg = format->is_bare;
repo_set_hash_algo(repo, format->hash_algo);
repo->objects = odb_new(repo, object_directory,
alternate_object_directories);
@@ -2571,7 +2584,7 @@ static int create_default_files(struct repository *repo,
repo_settings_set_shared_repository(repo,
init_shared_repository);
- is_bare_repository_cfg = !work_tree;
+ repo->bare_cfg = !work_tree;
/*
* We would have created the above under user's umask -- under
diff --git a/setup.h b/setup.h
index 705d1d6ff7..b9fd96bea6 100644
--- a/setup.h
+++ b/setup.h
@@ -292,6 +292,12 @@ enum sharedrepo {
int git_config_perm(const char *var, const char *value);
struct startup_info {
+ /*
+ * Whether the user is asking us to treat the repository as bare via
+ * `git --bare`, even if it's not.
+ */
+ bool force_bare_repository;
+
int have_repository;
const char *prefix;
const char *original_cwd;
diff --git a/worktree.c b/worktree.c
index 97eddc3916..7d70f2c1da 100644
--- a/worktree.c
+++ b/worktree.c
@@ -123,7 +123,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
worktree->repo = the_repository;
worktree->path = strbuf_detach(&worktree_path, NULL);
worktree->is_current = is_current_worktree(worktree);
- worktree->is_bare = (is_bare_repository_cfg == 1) ||
+ worktree->is_bare = (the_repository->bare_cfg == 1) ||
is_bare_repository() ||
/*
* When in a secondary worktree we have to also verify if the main
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
* [PATCH v2 6/7] environment: stop using `the_repository` in `is_bare_repository()`
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
Refactor `is_bare_repository()` to take in a repository parameter so
that we no longer depend on `the_repository`. Adjust callers
accordingly.
Furthermore, move the function outside of the declarations that are only
available when `USE_THE_REPOSITORY_VARIABLE` is set, as it no longer
depends on that variable.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
attr.c | 4 ++--
builtin/bisect.c | 2 +-
builtin/blame.c | 2 +-
builtin/check-attr.c | 2 +-
builtin/fetch.c | 2 +-
builtin/gc.c | 2 +-
builtin/history.c | 2 +-
builtin/repack.c | 2 +-
builtin/repo.c | 2 +-
builtin/reset.c | 2 +-
builtin/rev-parse.c | 2 +-
environment.c | 4 ++--
environment.h | 4 ++--
mailmap.c | 4 ++--
refs/files-backend.c | 2 +-
refs/reftable-backend.c | 2 +-
setup.c | 2 +-
transport.c | 4 ++--
worktree.c | 2 +-
19 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/attr.c b/attr.c
index 75369547b3..04cb284954 100644
--- a/attr.c
+++ b/attr.c
@@ -681,7 +681,7 @@ static enum git_attr_direction direction;
void git_attr_set_direction(enum git_attr_direction new_direction)
{
- if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
+ if (is_bare_repository(the_repository) && new_direction != GIT_ATTR_INDEX)
BUG("non-INDEX attr direction in a bare repo");
if (new_direction != direction)
@@ -848,7 +848,7 @@ static struct attr_stack *read_attr(struct index_state *istate,
res = read_attr_from_index(istate, path, flags);
} else if (tree_oid) {
res = read_attr_from_blob(istate, tree_oid, path, flags);
- } else if (!is_bare_repository()) {
+ } else if (!is_bare_repository(the_repository)) {
if (direction == GIT_ATTR_CHECKOUT) {
res = read_attr_from_index(istate, path, flags);
if (!res)
diff --git a/builtin/bisect.c b/builtin/bisect.c
index e7c2d2f3bb..798e28f501 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -724,7 +724,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
struct object_id oid;
const char *head;
- if (is_bare_repository())
+ if (is_bare_repository(the_repository))
no_checkout = 1;
/*
diff --git a/builtin/blame.c b/builtin/blame.c
index ffbd3ce5c5..553f4cb780 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1163,7 +1163,7 @@ int cmd_blame(int argc,
revs.disable_stdin = 1;
setup_revisions(argc, argv, &revs, NULL);
- if (!revs.pending.nr && is_bare_repository()) {
+ if (!revs.pending.nr && is_bare_repository(the_repository)) {
struct commit *head_commit;
struct object_id head_oid;
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 98f64d5b92..217d83ea7d 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -116,7 +116,7 @@ int cmd_check_attr(int argc,
struct object_id initialized_oid;
int cnt, i, doubledash, filei;
- if (!is_bare_repository())
+ if (!is_bare_repository(the_repository))
setup_work_tree(the_repository);
repo_config(the_repository, git_default_config, NULL);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index c1d7c672f4..44b8c70da1 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1764,7 +1764,7 @@ static int set_head(const struct ref *remote_refs, struct remote *remote)
if (!head_name)
goto cleanup;
- baremirror = is_bare_repository() && remote->mirror;
+ baremirror = is_bare_repository(the_repository) && remote->mirror;
create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !baremirror;
if (baremirror) {
strbuf_addstr(&b_head, "HEAD");
diff --git a/builtin/gc.c b/builtin/gc.c
index 84a66d3240..61da30de9f 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -902,7 +902,7 @@ int cmd_gc(int argc,
die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
if (cfg.pack_refs < 0)
- cfg.pack_refs = !is_bare_repository();
+ cfg.pack_refs = !is_bare_repository(the_repository);
argc = parse_options(argc, argv, prefix, builtin_gc_options,
builtin_gc_usage, 0);
diff --git a/builtin/history.c b/builtin/history.c
index 091465a59e..fd83de8265 100644
--- a/builtin/history.c
+++ b/builtin/history.c
@@ -525,7 +525,7 @@ static int cmd_history_fixup(int argc,
if (action == REF_ACTION_DEFAULT)
action = REF_ACTION_BRANCHES;
- if (is_bare_repository()) {
+ if (is_bare_repository(repo)) {
ret = error(_("cannot run fixup in a bare repository"));
goto out;
}
diff --git a/builtin/repack.c b/builtin/repack.c
index 1524a9c13a..bbc6f51639 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -265,7 +265,7 @@ int cmd_repack(int argc,
if (write_bitmaps < 0) {
if (write_midx == REPACK_WRITE_MIDX_NONE &&
- (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
+ (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))
write_bitmaps = 0;
}
if (po_args.pack_kept_objects < 0)
diff --git a/builtin/repo.c b/builtin/repo.c
index 71a5c1c29c..34e96514bc 100644
--- a/builtin/repo.c
+++ b/builtin/repo.c
@@ -58,7 +58,7 @@ struct repo_info_field {
static int get_layout_bare(struct repository *repo UNUSED, struct strbuf *buf)
{
- strbuf_addstr(buf, is_bare_repository() ? "true" : "false");
+ strbuf_addstr(buf, is_bare_repository(the_repository) ? "true" : "false");
return 0;
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 3be6bd0121..78e69bd84b 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -470,7 +470,7 @@ int cmd_reset(int argc,
if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
setup_work_tree(the_repository);
- if (reset_type == MIXED && is_bare_repository())
+ if (reset_type == MIXED && is_bare_repository(the_repository))
die(_("%s reset is not allowed in a bare repository"),
_(reset_type_names[reset_type]));
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index bb882678fe..090e5cfbb0 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -1084,7 +1084,7 @@ int cmd_rev_parse(int argc,
continue;
}
if (!strcmp(arg, "--is-bare-repository")) {
- printf("%s\n", is_bare_repository() ? "true"
+ printf("%s\n", is_bare_repository(the_repository) ? "true"
: "false");
continue;
}
diff --git a/environment.c b/environment.c
index 9d7c908c55..bf20953415 100644
--- a/environment.c
+++ b/environment.c
@@ -132,10 +132,10 @@ const char *getenv_safe(struct strvec *argv, const char *name)
return argv->v[argv->nr - 1];
}
-int is_bare_repository(void)
+int is_bare_repository(struct repository *repo)
{
/* if core.bare is not 'false', let's see if there is a work tree */
- return the_repository->bare_cfg && !repo_get_work_tree(the_repository);
+ return repo->bare_cfg && !repo_get_work_tree(repo);
}
int have_git_dir(void)
diff --git a/environment.h b/environment.h
index afb5bcf197..164a55df2c 100644
--- a/environment.h
+++ b/environment.h
@@ -125,6 +125,8 @@ int git_default_core_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg);
+int is_bare_repository(struct repository *repo);
+
/*
* TODO: All the below state either explicitly or implicitly relies on
* `the_repository`. We should eventually get rid of these and make the
@@ -147,8 +149,6 @@ void repo_config_values_init(struct repo_config_values *cfg);
*/
int have_git_dir(void);
-int is_bare_repository(void);
-
/* Environment bits from configuration mechanism */
extern int trust_executable_bit;
extern int trust_ctime;
diff --git a/mailmap.c b/mailmap.c
index 3b2691781d..7d8590cdd6 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -219,10 +219,10 @@ int read_mailmap(struct repository *repo, struct string_list *map)
map->strdup_strings = 1;
map->cmp = namemap_cmp;
- if (!mailmap_blob && is_bare_repository())
+ if (!mailmap_blob && is_bare_repository(the_repository))
mailmap_blob = xstrdup("HEAD:.mailmap");
- if (!startup_info->have_repository || !is_bare_repository())
+ if (!startup_info->have_repository || !is_bare_repository(the_repository))
err |= read_mailmap_file(map, ".mailmap",
startup_info->have_repository ?
MAILMAP_NOFOLLOW : 0);
diff --git a/refs/files-backend.c b/refs/files-backend.c
index a4c7858787..2b27091484 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1865,7 +1865,7 @@ static int log_ref_setup(struct files_ref_store *refs,
char *logfile;
if (log_refs_cfg == LOG_REFS_UNSET)
- log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+ log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
files_reflog_path(refs, &logfile_sb, refname);
logfile = strbuf_detach(&logfile_sb, NULL);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 4ae22922de..101ef29ac8 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -288,7 +288,7 @@ static int should_write_log(struct reftable_ref_store *refs, const char *refname
{
enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
if (log_refs_cfg == LOG_REFS_UNSET)
- log_refs_cfg = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+ log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
switch (log_refs_cfg) {
case LOG_REFS_NONE:
diff --git a/setup.c b/setup.c
index 32f14a8688..e6db80ab07 100644
--- a/setup.c
+++ b/setup.c
@@ -2610,7 +2610,7 @@ static int create_default_files(struct repository *repo,
}
repo_config_set(repo, "core.filemode", filemode ? "true" : "false");
- if (is_bare_repository())
+ if (is_bare_repository(the_repository))
repo_config_set(repo, "core.bare", "true");
else {
repo_config_set(repo, "core.bare", "false");
diff --git a/transport.c b/transport.c
index 0f5ec30247..fc144f0aed 100644
--- a/transport.c
+++ b/transport.c
@@ -1482,7 +1482,7 @@ int transport_push(struct repository *r,
if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
- !is_bare_repository()) {
+ !is_bare_repository(the_repository)) {
struct ref *ref = remote_refs;
struct oid_array commits = OID_ARRAY_INIT;
@@ -1509,7 +1509,7 @@ int transport_push(struct repository *r,
if (((flags & TRANSPORT_RECURSE_SUBMODULES_CHECK) ||
((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
TRANSPORT_RECURSE_SUBMODULES_ONLY)) &&
- !pretend)) && !is_bare_repository()) {
+ !pretend)) && !is_bare_repository(the_repository)) {
struct ref *ref = remote_refs;
struct string_list needs_pushing = STRING_LIST_INIT_DUP;
struct oid_array commits = OID_ARRAY_INIT;
diff --git a/worktree.c b/worktree.c
index 7d70f2c1da..30125827fd 100644
--- a/worktree.c
+++ b/worktree.c
@@ -124,7 +124,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
worktree->path = strbuf_detach(&worktree_path, NULL);
worktree->is_current = is_current_worktree(worktree);
worktree->is_bare = (the_repository->bare_cfg == 1) ||
- is_bare_repository() ||
+ is_bare_repository(the_repository) ||
/*
* When in a secondary worktree we have to also verify if the main
* worktree is bare in $commondir/config.worktree.
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
* [PATCH v2 7/7] treewide: drop USE_THE_REPOSITORY_VARIABLE
From: Patrick Steinhardt @ 2026-06-11 6:44 UTC (permalink / raw)
To: git; +Cc: Justin Tobler
In-Reply-To: <20260611-b4-pks-setup-drop-global-state-v2-0-a6f7269c841d@pks.im>
Adapt a couple of trivial callers of `is_bare_repository()` to instead
use a repository available via the caller's context so that we can drop
the `USE_THE_REPOSITORY_VARIABLE` macro.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/repack.c | 3 +--
mailmap.c | 6 ++----
refs/reftable-backend.c | 4 +---
setup.c | 3 +--
4 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/builtin/repack.c b/builtin/repack.c
index bbc6f51639..d0465fb4f5 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "builtin.h"
@@ -265,7 +264,7 @@ int cmd_repack(int argc,
if (write_bitmaps < 0) {
if (write_midx == REPACK_WRITE_MIDX_NONE &&
- (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(the_repository)))
+ (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository(repo)))
write_bitmaps = 0;
}
if (po_args.pack_kept_objects < 0)
diff --git a/mailmap.c b/mailmap.c
index 7d8590cdd6..2d5514f833 100644
--- a/mailmap.c
+++ b/mailmap.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
#include "git-compat-util.h"
#include "environment.h"
#include "string-list.h"
@@ -219,10 +217,10 @@ int read_mailmap(struct repository *repo, struct string_list *map)
map->strdup_strings = 1;
map->cmp = namemap_cmp;
- if (!mailmap_blob && is_bare_repository(the_repository))
+ if (!mailmap_blob && is_bare_repository(repo))
mailmap_blob = xstrdup("HEAD:.mailmap");
- if (!startup_info->have_repository || !is_bare_repository(the_repository))
+ if (!startup_info->have_repository || !is_bare_repository(repo))
err |= read_mailmap_file(map, ".mailmap",
startup_info->have_repository ?
MAILMAP_NOFOLLOW : 0);
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index 101ef29ac8..c151d331e7 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -1,5 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
-
#include "../git-compat-util.h"
#include "../abspath.h"
#include "../chdir-notify.h"
@@ -288,7 +286,7 @@ static int should_write_log(struct reftable_ref_store *refs, const char *refname
{
enum log_refs_config log_refs_cfg = refs->log_all_ref_updates;
if (log_refs_cfg == LOG_REFS_UNSET)
- log_refs_cfg = is_bare_repository(the_repository) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
+ log_refs_cfg = is_bare_repository(refs->base.repo) ? LOG_REFS_NONE : LOG_REFS_NORMAL;
switch (log_refs_cfg) {
case LOG_REFS_NONE:
diff --git a/setup.c b/setup.c
index e6db80ab07..65f4ac95a8 100644
--- a/setup.c
+++ b/setup.c
@@ -1,4 +1,3 @@
-#define USE_THE_REPOSITORY_VARIABLE
#define DISABLE_SIGN_COMPARE_WARNINGS
#include "git-compat-util.h"
@@ -2610,7 +2609,7 @@ static int create_default_files(struct repository *repo,
}
repo_config_set(repo, "core.filemode", filemode ? "true" : "false");
- if (is_bare_repository(the_repository))
+ if (is_bare_repository(repo))
repo_config_set(repo, "core.bare", "true");
else {
repo_config_set(repo, "core.bare", "false");
--
2.54.0.1189.g8c84645362.dirty
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox