* [PATCH 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-07 11:56 [PATCH 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-07 11:56 ` D. Ben Knoble
2026-08-10 12:50 ` Patrick Steinhardt
2026-08-07 11:56 ` [PATCH 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
` (4 subsequent siblings)
5 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-07 11:56 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Patrick Steinhardt
Makefile-based builds have had this knob for most of the project's life,
since a479a564dc (Documentation/Makefile: allow
man.base.url.for.relative.link to be set from Make, 2009-12-03).
Meson, however, hard-codes the equivalent of $prefix/$mandir, which is
not really where all the HTML docs are stored in most distro builds.
Plus, this value is missing a trailing slash, so links come out broken,
like this in git.1:
1. Git User’s Manual
/usr/share/manuser-manual.html
Of course we can do better:
1. Change the default to match Make: use file://$(htmldir)/ (with
trailing slash!) to form a local URL pointing at the HTML docs. This
is safe because all current uses of link:<relative> point at HTML
docs:
git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http
produces only a single result (Documentation/howto/howto-index.sh)
which can be ignored. Since nothing else [*] in the normal build sets
MAN_BASE_URL, this seems like the right default.
2. Provide a configurable knob, just like the Makefile, so distributions
that build with Meson (like Gentoo) can decide where to make the
links if they need to. Those that set htmldir probably won't need to
tweak this any further, though.
[*]: Well, Git's todo branch has a script dodoc.sh to build and archive
docs for kernel.org; these docs are pulled by Homebrew
installations, for example. It sets MAN_BASE_URL to "git_htmldocs",
so the equivalent note on macOS + Homebrew is
1. Git User’s Manual
git-htmldocs/user-manual.html
which is not functional either, but that's a problem for
downstream. In any case, users can recover the right path with
"git --html-path".
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
This patch is mostly because I noticed the link I added in a later patch
didn't come out right.
I did an internet search for "MAN_BASE_URL" and got no real hits, so I'm
not sure if any distros today actually use it, but that's not a proper
audit in that I didn't look at any distro _code_ besides Gentoo (which,
as noted, uses Meson).
Documentation/meson.build | 7 ++++++-
meson_options.txt | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..cfa9c67609 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -379,13 +379,18 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml',
)
+ man_base_url = 'file://' + htmldir + '/'
+ if get_option('man_base_url') != ''
+ man_base_url = get_option('man_base_url')
+ endif
+
doc_targets += custom_target(
command: [
xmlto,
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
- 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man.base.url.for.relative.links=' + man_base_url,
'man',
manpage_xml_target,
'-o',
diff --git a/meson_options.txt b/meson_options.txt
index dc88f130d7..d590c21648 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
+option('man_base_url', type: 'string', value: '',
+ description: 'The base URL to use for relative links in manuals')
# Testing.
option('benchmarks', type: 'feature', value: 'auto',
--
2.55.0.340.g8e2bf96aa5.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-07 11:56 ` [PATCH 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-10 12:50 ` Patrick Steinhardt
0 siblings, 0 replies; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-10 12:50 UTC (permalink / raw)
To: D. Ben Knoble; +Cc: git, Junio C Hamano
On Fri, Aug 07, 2026 at 07:56:24AM -0400, D. Ben Knoble wrote:
> diff --git a/Documentation/meson.build b/Documentation/meson.build
> index f4854f802d..cfa9c67609 100644
> --- a/Documentation/meson.build
> +++ b/Documentation/meson.build
> @@ -379,13 +379,18 @@ foreach manpage, category : manpages
> output: fs.stem(manpage) + '.xml',
> )
>
> + man_base_url = 'file://' + htmldir + '/'
> + if get_option('man_base_url') != ''
> + man_base_url = get_option('man_base_url')
> + endif
> +
> doc_targets += custom_target(
> command: [
> xmlto,
> '-m', '@INPUT0@',
> '-m', '@INPUT1@',
> '--stringparam',
> - 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
> + 'man.base.url.for.relative.links=' + man_base_url,
> 'man',
> manpage_xml_target,
> '-o',
> diff --git a/meson_options.txt b/meson_options.txt
> index dc88f130d7..d590c21648 100644
> --- a/meson_options.txt
> +++ b/meson_options.txt
> @@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
> description: 'Default format used when executing git-help(1).')
> option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
> description: 'Which backend to use to generate documentation.')
> +option('man_base_url', type: 'string', value: '',
> + description: 'The base URL to use for relative links in manuals')
Makes sense. I also verified that we indeed use the "file://" prefix by
default in our Makefile.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH 2/3] environment: align repo_config_values_init with struct declaration
2026-08-07 11:56 [PATCH 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-07 11:56 ` [PATCH 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-07 11:56 ` D. Ben Knoble
2026-08-07 11:56 ` [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
` (3 subsequent siblings)
5 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-07 11:56 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Olamide Caleb Bello, Junio C Hamano, Tian Yuchen
The order of assignments in repo_config_values_init is chaotic and hard
to follow, especially when comparing with the struct definition to
ensure all members are initialized. As new members will be added in the
future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
environment.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/environment.c b/environment.c
index 76ee65e62b..6676e6f5ae 100644
--- a/environment.c
+++ b/environment.c
@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg)
{
+ /* section "core" config values */
cfg->attributes_file = NULL;
cfg->excludes_file = NULL;
cfg->editor_program = NULL;
@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->autorebase = AUTOREBASE_NEVER;
cfg->object_creation_mode = OBJECT_CREATION_MODE;
cfg->apply_sparse_checkout = 0;
- cfg->protect_hfs = PROTECT_HFS_DEFAULT;
- cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
- cfg->ignore_case = 0;
- cfg->trust_executable_bit = 1;
- cfg->has_symlinks = platform_has_symlinks();
- cfg->branch_track = BRANCH_TRACK_REMOTE;
cfg->trust_ctime = 1;
cfg->check_stat = 1;
cfg->zlib_compression_level = Z_BEST_SPEED;
cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
cfg->core_sparse_checkout_cone = 0;
- cfg->sparse_expect_files_outside_of_patterns = 0;
cfg->warn_on_object_refname_ambiguity = 1;
+ cfg->protect_hfs = PROTECT_HFS_DEFAULT;
+ cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
+ cfg->ignore_case = 0;
+ cfg->trust_executable_bit = 1;
+ cfg->has_symlinks = platform_has_symlinks();
+
+ /* section "sparse" config values */
+ cfg->sparse_expect_files_outside_of_patterns = 0;
+
+ /* section "branch" config values */
+ cfg->branch_track = BRANCH_TRACK_REMOTE;
}
void repo_config_values_clear(struct repo_config_values *cfg)
--
2.55.0.340.g8e2bf96aa5.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-07 11:56 [PATCH 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-07 11:56 ` [PATCH 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
2026-08-07 11:56 ` [PATCH 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-07 11:56 ` D. Ben Knoble
2026-08-07 21:17 ` Junio C Hamano
2026-08-10 12:50 ` Patrick Steinhardt
2026-08-14 12:33 ` [PATCH v2 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (2 subsequent siblings)
5 siblings, 2 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-07 11:56 UTC (permalink / raw)
To: git
Cc: D. Ben Knoble, Tian Yuchen, Todd Zullinger, Patrick Steinhardt,
Olamide Caleb Bello, Junio C Hamano
Racy Git problems persist today, manifesting themselves in the
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
but most builds we know about it don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
These days, most platforms are likely to be safe for the USE_NSEC code.
Regardless, we want to give users the ability to benefit from it. This
requires exposing the compile-time gated code as a runtime option.
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
Best-viewed-with: --ignore-space-change
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
Repeating the benchmark from my original mail [1] shows an improvement
# git worktree add -d ../perf-test HEAD
# hyperfine -N --warmup=10 './build/bin-wrappers/git diff'
Benchmark 1: ./build/bin-wrappers/git diff
Time (mean ± σ): 3.8 ms ± 0.4 ms [User: 4.7 ms, System: 4.4 ms]
Range (min … max): 3.2 ms … 5.6 ms 780 runs
# (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git diff')
Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git diff
Time (mean ± σ): 217.5 ms ± 2.9 ms [User: 202.1 ms, System: 23.4 ms]
Range (min … max): 213.9 ms … 223.3 ms 13 runs
# (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git -c core.useNanosec=true diff')
Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git -c core.useNanosec=true diff
Time (mean ± σ): 3.8 ms ± 0.4 ms [User: 5.3 ms, System: 4.2 ms]
Range (min … max): 3.2 ms … 6.9 ms 541 runs
[1]: <CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com>
Passing CI: https://github.com/benknoble/git/actions/runs/31104581195
Documentation/config/core.adoc | 6 ++++++
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 6 ++++++
environment.h | 1 +
read-cache.c | 17 +++++++++--------
statinfo.c | 14 +++++++-------
10 files changed, 37 insertions(+), 39 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 340329edc3..33104444ab 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -118,6 +118,12 @@ core.trustctime::
crawlers and some backup systems).
See linkgit:git-update-index[1]. True by default.
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
+ was compiled to store it).
+ See link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
See linkgit:git-update-index[1]. False by default.
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
index 59bea66c0f..499231585b 100644
--- a/Documentation/technical/racy-git.adoc
+++ b/Documentation/technical/racy-git.adoc
@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`
timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
-is not stable on network filesystems. With `USE_NSEC`
-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+is not stable on network filesystems. With 'core.useNanosec'
+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
2005-01-04). This patch is included in kernel 2.6.11 and newer, but
only fixes the issue for file systems with exactly 1 ns or 1 s
-resolution. Other file systems are still broken in current Linux
-kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
+resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)
+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT
+has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to
+work, too.
Racy Git
--------
diff --git a/Makefile b/Makefile
index fac3e8879c..b4ebcb9e83 100644
--- a/Makefile
+++ b/Makefile
@@ -197,18 +197,11 @@ include shared.mak
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.adoc for details.
-#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available. This automatically turns USE_NSEC off.
+# available.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
@@ -1935,9 +1928,6 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
-ifdef USE_NSEC
- BASIC_CFLAGS += -DUSE_NSEC
-endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 241abd4332..8e0c25655f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -130,7 +130,7 @@ static void xrmdir(const char *path)
static void avoid_racy(void)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
+ * not use if we could usleep(10) if core.useNanosec is defined. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..51ee03233b 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
} while (0)
#ifdef NO_NSEC
-#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
diff --git a/configure.ac b/configure.ac
index cfb50112bf..fc956776ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
diff --git a/environment.c b/environment.c
index 6676e6f5ae..e6a50060e8 100644
--- a/environment.c
+++ b/environment.c
@@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,
return 0;
}
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
}
@@ -769,6 +774,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
+ cfg->use_nanosec = 0;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index e7ec5b0437..a35534afe5 100644
--- a/environment.h
+++ b/environment.h
@@ -139,6 +139,7 @@ struct repo_config_values {
int ignore_case;
int trust_executable_bit;
int has_symlinks;
+ int use_nanosec;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
diff --git a/read-cache.c b/read-cache.c
index 6c449f393d..297646c357 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
+ int use_nsec = 0;
+ repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec);
+
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
-#else
- istate->timestamp.sec <= sd->sd_mtime.sec
-#endif
+ /* nanosecond timestamped files can also be racy! */
+ use_nsec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec
);
}
diff --git a/statinfo.c b/statinfo.c
index 5e00af127d..d9ddcf9382 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
-#ifdef USE_NSEC
- if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (cfg->trust_ctime && cfg->check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
if (cfg->check_stat) {
if (sd->sd_uid != (unsigned int) st->st_uid ||
--
2.55.0.340.g8e2bf96aa5.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-07 11:56 ` [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-07 21:17 ` Junio C Hamano
2026-08-08 16:31 ` SZEDER Gábor
2026-08-10 12:27 ` D. Ben Knoble
2026-08-10 12:50 ` Patrick Steinhardt
1 sibling, 2 replies; 68+ messages in thread
From: Junio C Hamano @ 2026-08-07 21:17 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Tian Yuchen, Todd Zullinger, Patrick Steinhardt,
Olamide Caleb Bello
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> Racy Git problems persist today, manifesting themselves in the
> performance of commands like "git diff" in new worktrees [1]. We have
> long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> precision when available, which mitigates most if not all racy issues,
> but most builds we know about it don't use it. In part, that's because
> someone distributing Git can't safely enable it at compile-time if they
> don't know exactly what platforms their distribution will be used on.
>
> [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
>
> These days, most platforms are likely to be safe for the USE_NSEC code.
> Regardless, we want to give users the ability to benefit from it. This
> requires exposing the compile-time gated code as a runtime option.
>
> In addition, update the Racy Git documentation and other mentions of
> USE_NSEC in the code.
>
> Best-viewed-with: --ignore-space-change
Don't do this. It probably is helpful to have something like that
below the three-dash lines, though.
> Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
> ---
> diff --git a/environment.c b/environment.c
> index 6676e6f5ae..e6a50060e8 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,
> return 0;
> }
>
> + if (!strcmp(var, "core.usenanosec")) {
> + cfg->use_nanosec = git_config_bool(var, value);
> + return 0;
> + }
OK.
> diff --git a/read-cache.c b/read-cache.c
> index 6c449f393d..297646c357 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> static int is_racy_stat(const struct index_state *istate,
> const struct stat_data *sd)
> {
> + int use_nsec = 0;
> + repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec);
Yeek. Isn't this a relatively hot code path? If it is, it is
criminal to force string parsing and matching like this, every time
somebody calls the function.
Doesn't istate know what repository it is working with and in there
you should be able find its repo_settings struct cheaply, no?
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-07 21:17 ` Junio C Hamano
@ 2026-08-08 16:31 ` SZEDER Gábor
2026-08-10 12:27 ` D. Ben Knoble
2026-08-10 12:27 ` D. Ben Knoble
1 sibling, 1 reply; 68+ messages in thread
From: SZEDER Gábor @ 2026-08-08 16:31 UTC (permalink / raw)
To: Junio C Hamano
Cc: D. Ben Knoble, git, Tian Yuchen, Todd Zullinger,
Patrick Steinhardt, Olamide Caleb Bello
On Fri, Aug 07, 2026 at 02:17:39PM -0700, Junio C Hamano wrote:
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > Racy Git problems persist today, manifesting themselves in the
> > performance of commands like "git diff" in new worktrees [1]. We have
> > long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> > precision when available, which mitigates most if not all racy issues,
> > but most builds we know about it don't use it. In part, that's because
> > someone distributing Git can't safely enable it at compile-time if they
> > don't know exactly what platforms their distribution will be used on.
> >
> > [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
> >
> > These days, most platforms are likely to be safe for the USE_NSEC code.
> > Regardless, we want to give users the ability to benefit from it. This
> > requires exposing the compile-time gated code as a runtime option.
> >
> > In addition, update the Racy Git documentation and other mentions of
> > USE_NSEC in the code.
> >
> > Best-viewed-with: --ignore-space-change
>
> Don't do this. It probably is helpful to have something like that
> below the three-dash lines, though.
Including this hint in the commit message could be useful for anyone
who stumbles upon this commit in a couple of months or years time.
Whether it should be a trailer or not is another question.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-08 16:31 ` SZEDER Gábor
@ 2026-08-10 12:27 ` D. Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-10 12:27 UTC (permalink / raw)
To: SZEDER Gábor
Cc: Junio C Hamano, git, Tian Yuchen, Todd Zullinger,
Patrick Steinhardt, Olamide Caleb Bello
On Sat, Aug 8, 2026 at 12:31 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:
>
> On Fri, Aug 07, 2026 at 02:17:39PM -0700, Junio C Hamano wrote:
> > "D. Ben Knoble" <ben.knoble@gmail.com> writes:
> >
> > > Racy Git problems persist today, manifesting themselves in the
> > > performance of commands like "git diff" in new worktrees [1]. We have
> > > long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> > > precision when available, which mitigates most if not all racy issues,
> > > but most builds we know about it don't use it. In part, that's because
> > > someone distributing Git can't safely enable it at compile-time if they
> > > don't know exactly what platforms their distribution will be used on.
> > >
> > > [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
> > >
> > > These days, most platforms are likely to be safe for the USE_NSEC code.
> > > Regardless, we want to give users the ability to benefit from it. This
> > > requires exposing the compile-time gated code as a runtime option.
> > >
> > > In addition, update the Racy Git documentation and other mentions of
> > > USE_NSEC in the code.
> > >
> > > Best-viewed-with: --ignore-space-change
> >
> > Don't do this. It probably is helpful to have something like that
> > below the three-dash lines, though.
>
> Including this hint in the commit message could be useful for anyone
> who stumbles upon this commit in a couple of months or years time.
> Whether it should be a trailer or not is another question.
Yep, the trailer is a force-of-habit for me. I'll move it into the
commit message body in the next version.
I do find it helpful when the author of a patch---who presumably knows
the changes best---provides some guidance on making sense of the diff.
In this case, some code is re-indented as '#ifdef's change to runtime
'if's, so ignoring whitespace changes makes it easier to see there was
no change there.
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-07 21:17 ` Junio C Hamano
2026-08-08 16:31 ` SZEDER Gábor
@ 2026-08-10 12:27 ` D. Ben Knoble
2026-08-10 12:44 ` Patrick Steinhardt
1 sibling, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-10 12:27 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Tian Yuchen, Todd Zullinger, Patrick Steinhardt,
Olamide Caleb Bello
[-- Attachment #1: Type: text/plain, Size: 8817 bytes --]
On Fri, Aug 7, 2026 at 5:17 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > Racy Git problems persist today, manifesting themselves in the
> > performance of commands like "git diff" in new worktrees [1]. We have
> > long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> > precision when available, which mitigates most if not all racy issues,
> > but most builds we know about it don't use it. In part, that's because
> > someone distributing Git can't safely enable it at compile-time if they
> > don't know exactly what platforms their distribution will be used on.
> >
> > [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
> >
> > These days, most platforms are likely to be safe for the USE_NSEC code.
> > Regardless, we want to give users the ability to benefit from it. This
> > requires exposing the compile-time gated code as a runtime option.
> >
> > In addition, update the Racy Git documentation and other mentions of
> > USE_NSEC in the code.
> >
> > Best-viewed-with: --ignore-space-change
>
> Don't do this. It probably is helpful to have something like that
> below the three-dash lines, though.
[replied to SZEDER down-thread]
>
> > Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
> > ---
>
> > diff --git a/environment.c b/environment.c
> > index 6676e6f5ae..e6a50060e8 100644
> > --- a/environment.c
> > +++ b/environment.c
> > @@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,
> > return 0;
> > }
> >
> > + if (!strcmp(var, "core.usenanosec")) {
> > + cfg->use_nanosec = git_config_bool(var, value);
> > + return 0;
> > + }
>
> OK.
>
> > diff --git a/read-cache.c b/read-cache.c
> > index 6c449f393d..297646c357 100644
> > --- a/read-cache.c
> > +++ b/read-cache.c
> > @@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> > static int is_racy_stat(const struct index_state *istate,
> > const struct stat_data *sd)
> > {
> > + int use_nsec = 0;
> > + repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec);
>
> Yeek. Isn't this a relatively hot code path? If it is, it is
> criminal to force string parsing and matching like this, every time
> somebody calls the function.
>
> Doesn't istate know what repository it is working with and in there
> you should be able find its repo_settings struct cheaply, no?
TL;DR yes, but the patch series doesn't currently put the member in
repo_settings (repo_config_values). End of mail contains some
commentary there; folks from <anlmwaEtwcCPse1N@pks.im> cc'd.
I did some benchmarking on linux.git @ 848acc8ffe1b7cd5f1bf427b93069becfebc2c9d.
Brand-new worktree, without refreshing the index:
hyperfine -N --warmup=10 \
-n core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \
-n core.useNanosec=true ~c/'git/build/bin-wrappers/git -c
core.useNanosec=true diff' \
-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'
Benchmark 1: core.useNanosec=false
Time (mean ± σ): 853.7 ms ± 23.2 ms [User: 823.2 ms, System: 159.3 ms]
Range (min … max): 839.5 ms … 904.7 ms 10 runs
Warning: Statistical outliers were detected. Consider re-running
this benchmark on a quiet system without any interferences from other
programs. It might help to use the '--warmup' or '--prepare' options.
Benchmark 2: core.useNanosec=true
Time (mean ± σ): 20.4 ms ± 1.5 ms [User: 41.0 ms, System: 102.2 ms]
Range (min … max): 17.6 ms … 24.8 ms 122 runs
Benchmark 3: v2.55.0_USE_NSEC_disabled
Time (mean ± σ): 839.2 ms ± 12.7 ms [User: 796.8 ms, System: 158.8 ms]
Range (min … max): 830.5 ms … 864.4 ms 10 runs
Warning: Statistical outliers were detected. Consider re-running
this benchmark on a quiet system without any interferences from other
programs. It might help to use the '--warmup' or '--prepare' options.
Summary
core.useNanosec=true ran
41.06 ± 3.03 times faster than v2.55.0_USE_NSEC_disabled
41.77 ± 3.22 times faster than core.useNanosec=false
Same worktree after "git update-index --refresh":
hyperfine -N --warmup=10 \
-n core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \
-n core.useNanosec=true ~c/'git/build/bin-wrappers/git -c
core.useNanosec=true diff' \
-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'
Benchmark 1: core.useNanosec=false
Time (mean ± σ): 20.8 ms ± 2.1 ms [User: 41.8 ms, System: 102.9 ms]
Range (min … max): 17.4 ms … 26.4 ms 126 runs
Benchmark 2: core.useNanosec=true
Time (mean ± σ): 20.0 ms ± 1.0 ms [User: 40.4 ms, System: 101.8 ms]
Range (min … max): 18.0 ms … 23.6 ms 158 runs
Benchmark 3: v2.55.0_USE_NSEC_disabled
Time (mean ± σ): 19.2 ms ± 1.1 ms [User: 27.3 ms, System: 100.2 ms]
Range (min … max): 16.9 ms … 23.4 ms 160 runs
Summary
v2.55.0_USE_NSEC_disabled ran
1.04 ± 0.08 times faster than core.useNanosec=true
1.08 ± 0.13 times faster than core.useNanosec=false
So yeah, when we don't need the nanosec timings, this ends up minutely
slower than without it. When I apply the attached patch (sorry, GMail)
on top to poke through
istate->repo->config_values_private_.use_nanosec:
New worktree, no index refresh:
hyperfine -N --warmup=10 \
-n v2_core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \
-n v2_core.useNanosec=true ~c/'git/build/bin-wrappers/git -c
core.useNanosec=true diff' \
-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'
Benchmark 1: v2_core.useNanosec=false
Time (mean ± σ): 148.0 ms ± 2.8 ms [User: 142.5 ms, System: 124.0 ms]
Range (min … max): 144.3 ms … 155.3 ms 20 runs
Benchmark 2: v2_core.useNanosec=true
Time (mean ± σ): 21.2 ms ± 2.0 ms [User: 27.6 ms, System: 101.4 ms]
Range (min … max): 17.5 ms … 28.8 ms 123 runs
Benchmark 3: v2.55.0_USE_NSEC_disabled
Time (mean ± σ): 148.4 ms ± 8.6 ms [User: 141.0 ms, System: 122.8 ms]
Range (min … max): 140.9 ms … 179.6 ms 21 runs
Summary
v2_core.useNanosec=true ran
7.00 ± 0.67 times faster than v2_core.useNanosec=false
7.01 ± 0.77 times faster than v2.55.0_USE_NSEC_disabled
(We can see the raciness in the variability of the timings, neat)
After "git update-index --refresh":
hyperfine -N --warmup=10 \
-n v2_core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \
-n v2_core.useNanosec=true ~c/'git/build/bin-wrappers/git -c
core.useNanosec=true diff' \
-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'
Benchmark 1: v2_core.useNanosec=false
Time (mean ± σ): 20.8 ms ± 2.6 ms [User: 27.9 ms, System: 103.8 ms]
Range (min … max): 17.2 ms … 29.1 ms 132 runs
Benchmark 2: v2_core.useNanosec=true
Time (mean ± σ): 19.7 ms ± 1.5 ms [User: 29.2 ms, System: 100.0 ms]
Range (min … max): 17.0 ms … 28.2 ms 170 runs
Benchmark 3: v2.55.0_USE_NSEC_disabled
Time (mean ± σ): 19.7 ms ± 1.6 ms [User: 27.8 ms, System: 99.1 ms]
Range (min … max): 16.8 ms … 25.0 ms 154 runs
Summary
v2_core.useNanosec=true ran
1.00 ± 0.11 times faster than v2.55.0_USE_NSEC_disabled
1.05 ± 0.15 times faster than v2_core.useNanosec=false
Back down to being on-par with original code. So that's good. The next
version will include some variant that reads a struct member instead
of going through repo_config_get_bool().
But which? Reading the private_ member is obviously wrong; I suppose
I'm supposed to use repo_config_values() there. Or, rework the series
to put this member in repo_settings. I think I originally assumed that
struct is for things that are settings that aren't configured by
git-config, but… now I'm not sure. Looking at prepare_repo_settings()
shows lots of repo_cfg_*() calls. So I think I see how to adapt to
using repo_settings,
Patrick, Junio, and Tian had a brief discussion in
<anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't
really want to wait for it to settle to land this change, but we might
want to work together on identifying the best path forward for
core.useNanosec :)
I don't suppose it really matters to me which struct I put the member
in. As I said, v2 will definitely fix the hot path lookup here. Just a
matter of input on which struct we want to use this time, I guess.
--
D. Ben Knoble
[-- Attachment #2: perf-read-use_nsec-from-struct.patch --]
[-- Type: application/octet-stream, Size: 672 bytes --]
diff --git i/read-cache.c w/read-cache.c
index 297646c357..4bb5f466a1 100644
--- i/read-cache.c
+++ w/read-cache.c
@@ -353,8 +353,9 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
- int use_nsec = 0;
- repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec);
+ /* supposed to use repo_config_values(), probably?
+ * or we should move this member to struct repo_settings */
+ int use_nsec = istate->repo->config_values_private_.use_nanosec;
return (istate->timestamp.sec &&
/* nanosecond timestamped files can also be racy! */
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-10 12:27 ` D. Ben Knoble
@ 2026-08-10 12:44 ` Patrick Steinhardt
2026-08-11 16:26 ` Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-10 12:44 UTC (permalink / raw)
To: D. Ben Knoble
Cc: Junio C Hamano, git, Tian Yuchen, Todd Zullinger,
Olamide Caleb Bello
On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:
[snip]
> Back down to being on-par with original code. So that's good. The next
> version will include some variant that reads a struct member instead
> of going through repo_config_get_bool().
>
> But which? Reading the private_ member is obviously wrong; I suppose
> I'm supposed to use repo_config_values() there. Or, rework the series
> to put this member in repo_settings. I think I originally assumed that
> struct is for things that are settings that aren't configured by
> git-config, but… now I'm not sure. Looking at prepare_repo_settings()
> shows lots of repo_cfg_*() calls. So I think I see how to adapt to
> using repo_settings,
>
> Patrick, Junio, and Tian had a brief discussion in
> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't
> really want to wait for it to settle to land this change, but we might
> want to work together on identifying the best path forward for
> core.useNanosec :)
>
> I don't suppose it really matters to me which struct I put the member
> in. As I said, v2 will definitely fix the hot path lookup here. Just a
> matter of input on which struct we want to use this time, I guess.
I think `repo_config_values()` is the modern variant that we're slowly
migrating stuff into. But that struct only works with `the_repository`,
so the question is whether we ever use "core.useNsec" for a different
repository. My hunch would be yes, for example when recusing into
submodules, but I'm not sure.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-10 12:44 ` Patrick Steinhardt
@ 2026-08-11 16:26 ` Ben Knoble
2026-08-13 21:40 ` D. Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Ben Knoble @ 2026-08-11 16:26 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Junio C Hamano, git, Yuchen Tian, Todd Zullinger,
Olamide Caleb Bello
> Le 10 août 2026 à 08:44, Patrick Steinhardt <ps@pks.im> a écrit :
>
> On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:
> [snip]
>> Back down to being on-par with original code. So that's good. The next
>> version will include some variant that reads a struct member instead
>> of going through repo_config_get_bool().
>>
>> But which? Reading the private_ member is obviously wrong; I suppose
>> I'm supposed to use repo_config_values() there. Or, rework the series
>> to put this member in repo_settings. I think I originally assumed that
>> struct is for things that are settings that aren't configured by
>> git-config, but… now I'm not sure. Looking at prepare_repo_settings()
>> shows lots of repo_cfg_*() calls. So I think I see how to adapt to
>> using repo_settings,
>>
>> Patrick, Junio, and Tian had a brief discussion in
>> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't
>> really want to wait for it to settle to land this change, but we might
>> want to work together on identifying the best path forward for
>> core.useNanosec :)
>>
>> I don't suppose it really matters to me which struct I put the member
>> in. As I said, v2 will definitely fix the hot path lookup here. Just a
>> matter of input on which struct we want to use this time, I guess.
>
> I think `repo_config_values()` is the modern variant that we're slowly
> migrating stuff into. But that struct only works with `the_repository`,
> so the question is whether we ever use "core.useNsec" for a different
> repository. My hunch would be yes, for example when recusing into
> submodules, but I'm not sure.
>
> Patrick
Thanks. I’m working on control-flow analysis to see what kinds of repo values end up there. Of course I’ll also run the test suite and so on with the repo_config_values change. But the analysis will take some time.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-11 16:26 ` Ben Knoble
@ 2026-08-13 21:40 ` D. Ben Knoble
2026-08-14 11:06 ` Patrick Steinhardt
0 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-13 21:40 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Junio C Hamano, git, Yuchen Tian, Todd Zullinger,
Olamide Caleb Bello
On Tue, Aug 11, 2026 at 12:26 PM Ben Knoble <ben.knoble@gmail.com> wrote:
>
>
> > Le 10 août 2026 à 08:44, Patrick Steinhardt <ps@pks.im> a écrit :
> >
> > On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:
> > [snip]
> >> Back down to being on-par with original code. So that's good. The next
> >> version will include some variant that reads a struct member instead
> >> of going through repo_config_get_bool().
> >>
> >> But which? Reading the private_ member is obviously wrong; I suppose
> >> I'm supposed to use repo_config_values() there. Or, rework the series
> >> to put this member in repo_settings. I think I originally assumed that
> >> struct is for things that are settings that aren't configured by
> >> git-config, but… now I'm not sure. Looking at prepare_repo_settings()
> >> shows lots of repo_cfg_*() calls. So I think I see how to adapt to
> >> using repo_settings,
> >>
> >> Patrick, Junio, and Tian had a brief discussion in
> >> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't
> >> really want to wait for it to settle to land this change, but we might
> >> want to work together on identifying the best path forward for
> >> core.useNanosec :)
> >>
> >> I don't suppose it really matters to me which struct I put the member
> >> in. As I said, v2 will definitely fix the hot path lookup here. Just a
> >> matter of input on which struct we want to use this time, I guess.
> >
> > I think `repo_config_values()` is the modern variant that we're slowly
> > migrating stuff into. But that struct only works with `the_repository`,
> > so the question is whether we ever use "core.useNsec" for a different
> > repository. My hunch would be yes, for example when recusing into
> > submodules, but I'm not sure.
> >
> > Patrick
>
> Thanks. I’m working on control-flow analysis to see what kinds of repo values end up there. Of course I’ll also run the test suite and so on with the repo_config_values change. But the analysis will take some time.
Ok, CI run: https://github.com/benknoble/git/actions/runs/31701945211.
This demonstrates that nothing our test suite does across the many CI
configurations ends up where with a non-the_repository-repository
(ahem).
I have been working on control-flow analysis by hand in my Git time
this week. It's of the form "Z calls Y calls X …" until we can see
what the repository that's (eventually) fed to repo_config_values()
here in is_racy_stat() is. My notes are one node per line, which
indentation showing callee relationships. Some lines are pointers to
other nodes to avoid duplicating work.
With that in mind, filtering out the pointer nodes, I've analyzed 214
nodes in the graph. If I'm lucky, I'm approaching the halfway mark,
but I somewhat doubt it.
But since CI shows things work… I'd rather not continue the analysis
if we're satisfied for now. (Esp. since that will give me more Git
time back for reviewing ;) It being outside-of-work time, I only have
so much of it.)
A few other related things:
- Some of the edges of the graph appear to be public libgit.a
interfaces. That means we can't guarantee that only the_repository is
used.
- On a related note, I don't know how large the current "must only use
the_repository" (e.g., via repo_config_values()) surface area is right
now. Based on the partial analysis I mentioned above, this feels like
it's introducing (or at least contributing to) a rather large surface
area. So, this change might make it more critical to resolve the
limitation mentioned in the other thread. OTOH, I don't think this
change is likely to represent the only pervasive the_repository-only
limitation, and I'm afraid it will never land if it must be
the_repository clean (unless repo_settings is the_repository clean and
we decide that's an acceptable place for this member).
So, idk. If we're happy with the CI run + use of repo_config_values()
overall, I can send a v2 shortly (in next 24h), I think.
Thoughts? Strong opinions?
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-13 21:40 ` D. Ben Knoble
@ 2026-08-14 11:06 ` Patrick Steinhardt
2026-08-14 11:29 ` Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-14 11:06 UTC (permalink / raw)
To: D. Ben Knoble
Cc: Junio C Hamano, git, Yuchen Tian, Todd Zullinger,
Olamide Caleb Bello
On Thu, Aug 13, 2026 at 05:40:31PM -0400, D. Ben Knoble wrote:
> On Tue, Aug 11, 2026 at 12:26 PM Ben Knoble <ben.knoble@gmail.com> wrote:
> > > Le 10 août 2026 à 08:44, Patrick Steinhardt <ps@pks.im> a écrit :
> > > On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:
> > > [snip]
> > >> Back down to being on-par with original code. So that's good. The next
> > >> version will include some variant that reads a struct member instead
> > >> of going through repo_config_get_bool().
> > >>
> > >> But which? Reading the private_ member is obviously wrong; I suppose
> > >> I'm supposed to use repo_config_values() there. Or, rework the series
> > >> to put this member in repo_settings. I think I originally assumed that
> > >> struct is for things that are settings that aren't configured by
> > >> git-config, but… now I'm not sure. Looking at prepare_repo_settings()
> > >> shows lots of repo_cfg_*() calls. So I think I see how to adapt to
> > >> using repo_settings,
> > >>
> > >> Patrick, Junio, and Tian had a brief discussion in
> > >> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't
> > >> really want to wait for it to settle to land this change, but we might
> > >> want to work together on identifying the best path forward for
> > >> core.useNanosec :)
> > >>
> > >> I don't suppose it really matters to me which struct I put the member
> > >> in. As I said, v2 will definitely fix the hot path lookup here. Just a
> > >> matter of input on which struct we want to use this time, I guess.
> > >
> > > I think `repo_config_values()` is the modern variant that we're slowly
> > > migrating stuff into. But that struct only works with `the_repository`,
> > > so the question is whether we ever use "core.useNsec" for a different
> > > repository. My hunch would be yes, for example when recusing into
> > > submodules, but I'm not sure.
> > >
> > > Patrick
> >
> > Thanks. I’m working on control-flow analysis to see what kinds of repo values end up there. Of course I’ll also run the test suite and so on with the repo_config_values change. But the analysis will take some time.
>
> Ok, CI run: https://github.com/benknoble/git/actions/runs/31701945211.
> This demonstrates that nothing our test suite does across the many CI
> configurations ends up where with a non-the_repository-repository
> (ahem).
>
> I have been working on control-flow analysis by hand in my Git time
> this week. It's of the form "Z calls Y calls X …" until we can see
> what the repository that's (eventually) fed to repo_config_values()
> here in is_racy_stat() is. My notes are one node per line, which
> indentation showing callee relationships. Some lines are pointers to
> other nodes to avoid duplicating work.
>
> With that in mind, filtering out the pointer nodes, I've analyzed 214
> nodes in the graph. If I'm lucky, I'm approaching the halfway mark,
> but I somewhat doubt it.
>
> But since CI shows things work… I'd rather not continue the analysis
> if we're satisfied for now. (Esp. since that will give me more Git
> time back for reviewing ;) It being outside-of-work time, I only have
> so much of it.)
>
> A few other related things:
> - Some of the edges of the graph appear to be public libgit.a
> interfaces. That means we can't guarantee that only the_repository is
> used.
> - On a related note, I don't know how large the current "must only use
> the_repository" (e.g., via repo_config_values()) surface area is right
> now. Based on the partial analysis I mentioned above, this feels like
> it's introducing (or at least contributing to) a rather large surface
> area. So, this change might make it more critical to resolve the
> limitation mentioned in the other thread. OTOH, I don't think this
> change is likely to represent the only pervasive the_repository-only
> limitation, and I'm afraid it will never land if it must be
> the_repository clean (unless repo_settings is the_repository clean and
> we decide that's an acceptable place for this member).
>
> So, idk. If we're happy with the CI run + use of repo_config_values()
> overall, I can send a v2 shortly (in next 24h), I think.
>
> Thoughts? Strong opinions?
No strong opinions from my side, other than that we should stop
converting everything to `repo_config_values()` until we have a plan for
how to make it work with repositories other than `the_repository`.
I don't feel like holding this series in hostage though, so if your
analysis and the test suite both say that this is probably fine then we
may want to pursue it. Or we just use a global variable for it for the
time being and then wait until the `repo_config_values()` dust has
settled.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-14 11:06 ` Patrick Steinhardt
@ 2026-08-14 11:29 ` Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: Ben Knoble @ 2026-08-14 11:29 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Junio C Hamano, git, Yuchen Tian, Todd Zullinger,
Olamide Caleb Bello
> Le 14 août 2026 à 07:07, Patrick Steinhardt <ps@pks.im> a écrit :
>
> On Thu, Aug 13, 2026 at 05:40:31PM -0400, D. Ben Knoble wrote:
>>
>>
>> Ok, CI run: https://github.com/benknoble/git/actions/runs/31701945211.
>> This demonstrates that nothing our test suite does across the many CI
>> configurations ends up where with a non-the_repository-repository
>> (ahem).
>>
>> I have been working on control-flow analysis by hand in my Git time
>> this week. It's of the form "Z calls Y calls X …" until we can see
>> what the repository that's (eventually) fed to repo_config_values()
>> here in is_racy_stat() is. My notes are one node per line, which
>> indentation showing callee relationships. Some lines are pointers to
>> other nodes to avoid duplicating work.
>>
>> With that in mind, filtering out the pointer nodes, I've analyzed 214
>> nodes in the graph. If I'm lucky, I'm approaching the halfway mark,
>> but I somewhat doubt it.
>>
>> But since CI shows things work… I'd rather not continue the analysis
>> if we're satisfied for now. (Esp. since that will give me more Git
>> time back for reviewing ;) It being outside-of-work time, I only have
>> so much of it.)
>>
>> A few other related things:
>> - Some of the edges of the graph appear to be public libgit.a
>> interfaces. That means we can't guarantee that only the_repository is
>> used.
>> - On a related note, I don't know how large the current "must only use
>> the_repository" (e.g., via repo_config_values()) surface area is right
>> now. Based on the partial analysis I mentioned above, this feels like
>> it's introducing (or at least contributing to) a rather large surface
>> area. So, this change might make it more critical to resolve the
>> limitation mentioned in the other thread. OTOH, I don't think this
>> change is likely to represent the only pervasive the_repository-only
>> limitation, and I'm afraid it will never land if it must be
>> the_repository clean (unless repo_settings is the_repository clean and
>> we decide that's an acceptable place for this member).
>>
>> So, idk. If we're happy with the CI run + use of repo_config_values()
>> overall, I can send a v2 shortly (in next 24h), I think.
>>
>> Thoughts? Strong opinions?
>
> No strong opinions from my side, other than that we should stop
> converting everything to `repo_config_values()` until we have a plan for
> how to make it work with repositories other than `the_repository`.
>
> I don't feel like holding this series in hostage though, so if your
> analysis and the test suite both say that this is probably fine then we
> may want to pursue it. Or we just use a global variable for it for the
> time being and then wait until the `repo_config_values()` dust has
> settled.
>
> Patrick
Makes sense. I should have also mentioned that, of the nodes I’ve analyzed so far, they all terminate in a path that uses the_repository (some intermediate nodes are also exposed, though, as written previously).
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-07 11:56 ` [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2026-08-07 21:17 ` Junio C Hamano
@ 2026-08-10 12:50 ` Patrick Steinhardt
1 sibling, 0 replies; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-10 12:50 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Tian Yuchen, Todd Zullinger, Olamide Caleb Bello,
Junio C Hamano
On Fri, Aug 07, 2026 at 07:56:26AM -0400, D. Ben Knoble wrote:
> diff --git a/compat/posix.h b/compat/posix.h
> index e2e794cad7..51ee03233b 100644
> --- a/compat/posix.h
> +++ b/compat/posix.h
> @@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
> } while (0)
>
> #ifdef NO_NSEC
> -#undef USE_NSEC
> #define ST_CTIME_NSEC(st) 0
> #define ST_MTIME_NSEC(st) 0
> #else
Ah, I was about to ask whether all platforms even support nanoseconds.
But I wasn't aware that we have both NO_NSEC and USE_NSEC, so we still
know to not use nanoseconds if unsupported by the platform.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v2 0/3] Convert USE_NSEC to runtime config
2026-08-07 11:56 [PATCH 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (2 preceding siblings ...)
2026-08-07 11:56 ` [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-14 12:33 ` D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
` (2 more replies)
2026-08-18 14:59 ` [PATCH v3 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
5 siblings, 3 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-14 12:33 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble
Topic name: dk/use-nsec-runtime (applied)
Topic summary: Expose USE_NSEC as a runtime configuration, since
build-time is too early for distributing Git [1]. As a result, common
index-related options, like git-diff, are less likely to hit "racy git"
problems on supported filesystems.
[1]: https://git.github.io/rev_news/2026/07/31/edition-137/
Built on master (2c78326f81 (The 11th batch, 2026-08-05)).
Changes in v2:
- move Best-viewed-with trailer into message body as descriptive
text.
- read core.useNanosec through struct repo instead of parsing
config strings. The test suite passes locally this way, though that
skipped 151 tests.
- CI run: https://github.com/benknoble/git/actions/runs/31701945211
Original cover letter:
Hi all, this series follows up on the previous racy Git/USE_NSEC
conversations.
- The first patch is a mostly-unrelated documentation fix for Meson, but
it came out of something I spotted while reviewing the outputs of the
final (main) patch.
- The second patch is a preliminary no-op reorganization of
repo_config_values_init.
- The third patch is the meat, converting USE_NSEC into core.useNanosec.
There is a small textual and semantic conflict with
'ty/repo-config-cleanups' in 'seen', since that branch removes the
comments in 'struct repo_config_values' which this series adds to. (The
semantic conflict is that, if we drop those comments, we should probably
not add them to repo_config_values_init like I do in patch 2.)
Todo: I haven't touched any tests; I saw a bunch of hits for "git grep
racy t" but wasn't sure how to fit this particular change in, especially
since it won't be equally valid on all systems? Advice welcome.
Todo: I wonder if "useNanosec" paints us into too much of a corner; that
is (slightly more abstractly), we are using *extended precision* in the
index. Maybe the name and documentation should reflect that, so we
aren't too committed to "nanoseconds"?
- Some platforms could offer extended precision that is not as
precise as nanoseconds
- Some could offer precision _beyond_ nanoseconds
idk.
v1: <cover.1786103607.git.ben.knoble@gmail.com>
[1/3] meson: expose knob for xmlto relative links in manuals
[2/3] environment: align repo_config_values_init with struct declaration
[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
Documentation/config/core.adoc | 6 ++++++
Documentation/meson.build | 7 ++++++-
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 25 ++++++++++++++++++-------
environment.h | 1 +
meson_options.txt | 2 ++
read-cache.c | 16 ++++++++--------
statinfo.c | 14 +++++++-------
12 files changed, 56 insertions(+), 47 deletions(-)
Diff-intervalle contre v1 :
1: d612de6c2d = 1: d612de6c2d meson: expose knob for xmlto relative links in manuals
2: 5693baa992 = 2: 5693baa992 environment: align repo_config_values_init with struct declaration
3: dbbd96d508 ! 3: 2d1424732a core: convert build-time USE_NSEC into runtime core.useNanosec
@@ Commit message
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
- Best-viewed-with: --ignore-space-change
+ Due to the conversion from #ifdef to runtime check, using the flag
+ "--ignore-space-change" may be particularly helpful when viewing changes
+ from this patch.
## Notes (benknoble/commits) ##
- Repeating the benchmark from my original mail [1] shows an improvement
-
- # git worktree add -d ../perf-test HEAD
- # hyperfine -N --warmup=10 './build/bin-wrappers/git diff'
- Benchmark 1: ./build/bin-wrappers/git diff
- Time (mean ± σ): 3.8 ms ± 0.4 ms [User: 4.7 ms, System: 4.4 ms]
- Range (min … max): 3.2 ms … 5.6 ms 780 runs
- # (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git diff')
- Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git diff
- Time (mean ± σ): 217.5 ms ± 2.9 ms [User: 202.1 ms, System: 23.4 ms]
- Range (min … max): 213.9 ms … 223.3 ms 13 runs
- # (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git -c core.useNanosec=true diff')
- Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git -c core.useNanosec=true diff
- Time (mean ± σ): 3.8 ms ± 0.4 ms [User: 5.3 ms, System: 4.2 ms]
- Range (min … max): 3.2 ms … 6.9 ms 541 runs
-
- [1]: <CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com>
-
- Passing CI: https://github.com/benknoble/git/actions/runs/31104581195
+ Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
+ CI: <https://github.com/benknoble/git/actions/runs/31701945211>
## Documentation/config/core.adoc ##
@@ Documentation/config/core.adoc: core.trustctime::
@@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struc
static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
-+ int use_nsec = 0;
-+ repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec);
++ int use_nsec = repo_config_values(istate->repo)->use_nanosec;
+
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
base-commit: 2c78326f810173a4f3aefd8021f1e07575412481
--
2.55.0.699.gb54405d56f.dirty
^ permalink raw reply [flat|nested] 68+ messages in thread* [PATCH v2 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-14 12:33 ` [PATCH v2 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-14 12:34 ` D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-14 12:34 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Patrick Steinhardt
Makefile-based builds have had this knob for most of the project's life,
since a479a564dc (Documentation/Makefile: allow
man.base.url.for.relative.link to be set from Make, 2009-12-03).
Meson, however, hard-codes the equivalent of $prefix/$mandir, which is
not really where all the HTML docs are stored in most distro builds.
Plus, this value is missing a trailing slash, so links come out broken,
like this in git.1:
1. Git User’s Manual
/usr/share/manuser-manual.html
Of course we can do better:
1. Change the default to match Make: use file://$(htmldir)/ (with
trailing slash!) to form a local URL pointing at the HTML docs. This
is safe because all current uses of link:<relative> point at HTML
docs:
git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http
produces only a single result (Documentation/howto/howto-index.sh)
which can be ignored. Since nothing else [*] in the normal build sets
MAN_BASE_URL, this seems like the right default.
2. Provide a configurable knob, just like the Makefile, so distributions
that build with Meson (like Gentoo) can decide where to make the
links if they need to. Those that set htmldir probably won't need to
tweak this any further, though.
[*]: Well, Git's todo branch has a script dodoc.sh to build and archive
docs for kernel.org; these docs are pulled by Homebrew
installations, for example. It sets MAN_BASE_URL to "git_htmldocs",
so the equivalent note on macOS + Homebrew is
1. Git User’s Manual
git-htmldocs/user-manual.html
which is not functional either, but that's a problem for
downstream. In any case, users can recover the right path with
"git --html-path".
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
This patch is mostly because I noticed the link I added in a later patch
didn't come out right.
I did an internet search for "MAN_BASE_URL" and got no real hits, so I'm
not sure if any distros today actually use it, but that's not a proper
audit in that I didn't look at any distro _code_ besides Gentoo (which,
as noted, uses Meson).
Documentation/meson.build | 7 ++++++-
meson_options.txt | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..cfa9c67609 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -379,13 +379,18 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml',
)
+ man_base_url = 'file://' + htmldir + '/'
+ if get_option('man_base_url') != ''
+ man_base_url = get_option('man_base_url')
+ endif
+
doc_targets += custom_target(
command: [
xmlto,
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
- 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man.base.url.for.relative.links=' + man_base_url,
'man',
manpage_xml_target,
'-o',
diff --git a/meson_options.txt b/meson_options.txt
index dc88f130d7..d590c21648 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
+option('man_base_url', type: 'string', value: '',
+ description: 'The base URL to use for relative links in manuals')
# Testing.
option('benchmarks', type: 'feature', value: 'auto',
--
2.55.0.699.gb54405d56f.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v2 2/3] environment: align repo_config_values_init with struct declaration
2026-08-14 12:33 ` [PATCH v2 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-14 12:34 ` D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-14 12:34 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Tian Yuchen, Junio C Hamano, Olamide Caleb Bello
The order of assignments in repo_config_values_init is chaotic and hard
to follow, especially when comparing with the struct definition to
ensure all members are initialized. As new members will be added in the
future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
environment.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/environment.c b/environment.c
index 76ee65e62b..6676e6f5ae 100644
--- a/environment.c
+++ b/environment.c
@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg)
{
+ /* section "core" config values */
cfg->attributes_file = NULL;
cfg->excludes_file = NULL;
cfg->editor_program = NULL;
@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->autorebase = AUTOREBASE_NEVER;
cfg->object_creation_mode = OBJECT_CREATION_MODE;
cfg->apply_sparse_checkout = 0;
- cfg->protect_hfs = PROTECT_HFS_DEFAULT;
- cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
- cfg->ignore_case = 0;
- cfg->trust_executable_bit = 1;
- cfg->has_symlinks = platform_has_symlinks();
- cfg->branch_track = BRANCH_TRACK_REMOTE;
cfg->trust_ctime = 1;
cfg->check_stat = 1;
cfg->zlib_compression_level = Z_BEST_SPEED;
cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
cfg->core_sparse_checkout_cone = 0;
- cfg->sparse_expect_files_outside_of_patterns = 0;
cfg->warn_on_object_refname_ambiguity = 1;
+ cfg->protect_hfs = PROTECT_HFS_DEFAULT;
+ cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
+ cfg->ignore_case = 0;
+ cfg->trust_executable_bit = 1;
+ cfg->has_symlinks = platform_has_symlinks();
+
+ /* section "sparse" config values */
+ cfg->sparse_expect_files_outside_of_patterns = 0;
+
+ /* section "branch" config values */
+ cfg->branch_track = BRANCH_TRACK_REMOTE;
}
void repo_config_values_clear(struct repo_config_values *cfg)
--
2.55.0.699.gb54405d56f.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-14 12:33 ` [PATCH v2 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
2026-08-14 12:34 ` [PATCH v2 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-14 12:34 ` D. Ben Knoble
2026-08-14 16:38 ` Junio C Hamano
2 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-14 12:34 UTC (permalink / raw)
To: git
Cc: D. Ben Knoble, Todd Zullinger, Junio C Hamano, Tian Yuchen,
Olamide Caleb Bello, Patrick Steinhardt
Racy Git problems persist today, manifesting themselves in the
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
but most builds we know about it don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
These days, most platforms are likely to be safe for the USE_NSEC code.
Regardless, we want to give users the ability to benefit from it. This
requires exposing the compile-time gated code as a runtime option.
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
Due to the conversion from #ifdef to runtime check, using the flag
"--ignore-space-change" may be particularly helpful when viewing changes
from this patch.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
CI: <https://github.com/benknoble/git/actions/runs/31701945211>
Documentation/config/core.adoc | 6 ++++++
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 6 ++++++
environment.h | 1 +
read-cache.c | 16 ++++++++--------
statinfo.c | 14 +++++++-------
10 files changed, 36 insertions(+), 39 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 340329edc3..33104444ab 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -118,6 +118,12 @@ core.trustctime::
crawlers and some backup systems).
See linkgit:git-update-index[1]. True by default.
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
+ was compiled to store it).
+ See link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
See linkgit:git-update-index[1]. False by default.
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
index 59bea66c0f..499231585b 100644
--- a/Documentation/technical/racy-git.adoc
+++ b/Documentation/technical/racy-git.adoc
@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`
timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
-is not stable on network filesystems. With `USE_NSEC`
-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+is not stable on network filesystems. With 'core.useNanosec'
+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
2005-01-04). This patch is included in kernel 2.6.11 and newer, but
only fixes the issue for file systems with exactly 1 ns or 1 s
-resolution. Other file systems are still broken in current Linux
-kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
+resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)
+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT
+has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to
+work, too.
Racy Git
--------
diff --git a/Makefile b/Makefile
index fac3e8879c..b4ebcb9e83 100644
--- a/Makefile
+++ b/Makefile
@@ -197,18 +197,11 @@ include shared.mak
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.adoc for details.
-#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available. This automatically turns USE_NSEC off.
+# available.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
@@ -1935,9 +1928,6 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
-ifdef USE_NSEC
- BASIC_CFLAGS += -DUSE_NSEC
-endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 241abd4332..8e0c25655f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -130,7 +130,7 @@ static void xrmdir(const char *path)
static void avoid_racy(void)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
+ * not use if we could usleep(10) if core.useNanosec is defined. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..51ee03233b 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
} while (0)
#ifdef NO_NSEC
-#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
diff --git a/configure.ac b/configure.ac
index cfb50112bf..fc956776ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
diff --git a/environment.c b/environment.c
index 6676e6f5ae..e6a50060e8 100644
--- a/environment.c
+++ b/environment.c
@@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,
return 0;
}
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
}
@@ -769,6 +774,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
+ cfg->use_nanosec = 0;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index e7ec5b0437..a35534afe5 100644
--- a/environment.h
+++ b/environment.h
@@ -139,6 +139,7 @@ struct repo_config_values {
int ignore_case;
int trust_executable_bit;
int has_symlinks;
+ int use_nanosec;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
diff --git a/read-cache.c b/read-cache.c
index 6c449f393d..abecdf0342 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -353,15 +353,15 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
+ int use_nsec = repo_config_values(istate->repo)->use_nanosec;
+
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
-#else
- istate->timestamp.sec <= sd->sd_mtime.sec
-#endif
+ /* nanosecond timestamped files can also be racy! */
+ use_nsec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec
);
}
diff --git a/statinfo.c b/statinfo.c
index 5e00af127d..d9ddcf9382 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
-#ifdef USE_NSEC
- if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (cfg->trust_ctime && cfg->check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
if (cfg->check_stat) {
if (sd->sd_uid != (unsigned int) st->st_uid ||
--
2.55.0.699.gb54405d56f.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-14 12:34 ` [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-14 16:38 ` Junio C Hamano
2026-08-14 19:03 ` D. Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-08-14 16:38 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Todd Zullinger, Tian Yuchen, Olamide Caleb Bello,
Patrick Steinhardt
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> -#ifdef USE_NSEC
> - if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
> - changed |= MTIME_CHANGED;
> - if (cfg->trust_ctime && cfg->check_stat &&
> - sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
> - changed |= CTIME_CHANGED;
> -#endif
> + if (cfg->use_nanosec) {
> + if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
> + changed |= MTIME_CHANGED;
> + if (cfg->trust_ctime && cfg->check_stat &&
> + sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
> + changed |= CTIME_CHANGED;
> + }
>
> if (cfg->check_stat) {
> if (sd->sd_uid != (unsigned int) st->st_uid ||
This is iffy.
If you have core.usenanosec=true in a networked $HOME/.gitconfig
mounted on both USE_NSEC-capable and incapable platforms, what would
ST_CTIME_NSEC() yield on the latter? I wonder if cfg's
'.use_nanosec' should be force-disabled in NO_NSEC builds, or
something similar?
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-14 16:38 ` Junio C Hamano
@ 2026-08-14 19:03 ` D. Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-14 19:03 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Todd Zullinger, Tian Yuchen, Olamide Caleb Bello,
Patrick Steinhardt
On Fri, Aug 14, 2026 at 12:38 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > -#ifdef USE_NSEC
> > - if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
> > - changed |= MTIME_CHANGED;
> > - if (cfg->trust_ctime && cfg->check_stat &&
> > - sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
> > - changed |= CTIME_CHANGED;
> > -#endif
> > + if (cfg->use_nanosec) {
> > + if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
> > + changed |= MTIME_CHANGED;
> > + if (cfg->trust_ctime && cfg->check_stat &&
> > + sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
> > + changed |= CTIME_CHANGED;
> > + }
> >
> > if (cfg->check_stat) {
> > if (sd->sd_uid != (unsigned int) st->st_uid ||
>
> This is iffy.
>
> If you have core.usenanosec=true in a networked $HOME/.gitconfig
> mounted on both USE_NSEC-capable and incapable platforms, what would
> ST_CTIME_NSEC() yield on the latter?
Perhaps "if it hurts, don't do that"? This config is definitely about
exposing the underlying system's capabilities to Git, so if you cannot
confidently do so globally, you probably shouldn't. That might limit
the usefulness of the optimization for folks that share filesystems
between multiple machines in this way, I suppose. Or maybe it will
incentivize folks to be nsec-compatible in more places ;) Either way,
users that can benefit from it will have the option.
> I wonder if cfg's
> '.use_nanosec' should be force-disabled in NO_NSEC builds, or
> something similar?
This does, however, make some sense to me:
- Git today with NO_NSEC doesn't bother with the USE_NSEC paths, since
we #undef USE_NSEC in that case.
- Git "tomorrow" should probably say "I was built with NO_NSEC, so I
will (continue) ignoring platform-specific nanosecond optimizations."
I'll queue this change locally until I send out the next version,
unless someone objects.
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v3 0/3] Convert USE_NSEC to runtime config
2026-08-07 11:56 [PATCH 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (3 preceding siblings ...)
2026-08-14 12:33 ` [PATCH v2 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-18 14:59 ` D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
` (2 more replies)
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
5 siblings, 3 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-18 14:59 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble
Topic name: dk/use-nsec-runtime (applied)
Topic summary: Expose USE_NSEC as a runtime configuration, since
build-time is too early for distributing Git [1]. As a result, common
index-related options, like git-diff, are less likely to hit "racy git"
problems on supported filesystems.
[1]: https://git.github.io/rev_news/2026/07/31/edition-137/
Built on master (2c78326f81 (The 11th batch, 2026-08-05)).
Changes in v3:
- #ifdef out use_nanosec when NO_NSEC is requested
As I have heard no comments about the "Todo" lines below, which perhaps
could more clearly be marked "RFC"/"RFH", I've added this line to call
them out ;) and renamed them "Comments welcome"
Changes in v2:
- move Best-viewed-with trailer into message body as descriptive
text.
- read core.useNanosec through struct repo instead of parsing
config strings. The test suite passes locally this way, though that
skipped 151 tests.
- CI run: https://github.com/benknoble/git/actions/runs/31701945211
Original cover letter:
Hi all, this series follows up on the previous racy Git/USE_NSEC
conversations.
- The first patch is a mostly-unrelated documentation fix for Meson, but
it came out of something I spotted while reviewing the outputs of the
final (main) patch.
- The second patch is a preliminary no-op reorganization of
repo_config_values_init.
- The third patch is the meat, converting USE_NSEC into core.useNanosec.
There is a small textual and semantic conflict with
'ty/repo-config-cleanups' in 'seen', since that branch removes the
comments in 'struct repo_config_values' which this series adds to. (The
semantic conflict is that, if we drop those comments, we should probably
not add them to repo_config_values_init like I do in patch 2.)
Comments welcome: I haven't touched any tests; I saw a bunch of hits for
"git grep racy t" but wasn't sure how to fit this particular change in,
especially since it won't be equally valid on all systems? Advice
welcome.
Comments welcome: I wonder if "useNanosec" paints us into too much of a
corner; that is (slightly more abstractly), we are using *extended
precision* in the index. Maybe the name and documentation should reflect
that, so we aren't too committed to "nanoseconds"?
- Some platforms could offer extended precision that is not as
precise as nanoseconds
- Some could offer precision _beyond_ nanoseconds
idk.
v1: <cover.1786103607.git.ben.knoble@gmail.com>
v2: <cover.1786710807.git.ben.knoble@gmail.com>
[1/3] meson: expose knob for xmlto relative links in manuals
[2/3] environment: align repo_config_values_init with struct declaration
[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
Documentation/config/core.adoc | 6 ++++++
Documentation/meson.build | 7 ++++++-
Documentation/technical/racy-git.adoc | 11 +++++-----
Makefile | 12 +----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 29 ++++++++++++++++++++-------
environment.h | 1 +
meson_options.txt | 2 ++
read-cache.c | 16 ++++++++++-----
statinfo.c | 14 +++++++------
12 files changed, 64 insertions(+), 43 deletions(-)
Diff-intervalle contre v2 :
1: d612de6c2d = 1: d612de6c2d meson: expose knob for xmlto relative links in manuals
2: 5693baa992 = 2: 5693baa992 environment: align repo_config_values_init with struct declaration
3: 2d1424732a ! 3: 48fceb4b57 core: convert build-time USE_NSEC into runtime core.useNanosec
@@ Commit message
## Notes (benknoble/commits) ##
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
- CI: <https://github.com/benknoble/git/actions/runs/31701945211>
+ CI: <https://github.com/benknoble/git/actions/runs/32137191115>
+
+ v3:
+ We could perhaps be cute in read-cache.c:is_racy_stat() by writing
+ the preprocessor directive like
+
+ return (istate->timestamp.sec &&
+ #ifndef NO_NSEC
+ /* nanosecond timestamped files can also be racy! */
+ use_nsec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ :
+ #endif
+ istate->timestamp.sec <= sd->sd_mtime.sec
+
+ but that seemed maybe too clever?
## Documentation/config/core.adoc ##
@@ Documentation/config/core.adoc: core.trustctime::
@@ environment.c: int git_default_core_config(const char *var, const char *value,
return 0;
}
++#ifndef NO_NSEC
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
++#endif
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
@@ environment.c: void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
++#ifndef NO_NSEC
+ cfg->use_nanosec = 0;
++#endif
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
@@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struc
static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
++#ifndef NO_NSEC
+ int use_nsec = repo_config_values(istate->repo)->use_nanosec;
++#endif
+
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
@@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struc
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
--#else
-- istate->timestamp.sec <= sd->sd_mtime.sec
--#endif
++#ifndef NO_NSEC
+ /* nanosecond timestamped files can also be racy! */
+ use_nsec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec
- );
- }
-
+ #else
+ istate->timestamp.sec <= sd->sd_mtime.sec
+ #endif
## statinfo.c ##
@@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)
@@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
--#endif
++#ifndef NO_NSEC
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
@@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
+ #endif
if (cfg->check_stat) {
- if (sd->sd_uid != (unsigned int) st->st_uid ||
base-commit: 2c78326f810173a4f3aefd8021f1e07575412481
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply [flat|nested] 68+ messages in thread* [PATCH v3 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-18 14:59 ` [PATCH v3 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-18 14:59 ` D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-18 14:59 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Patrick Steinhardt
Makefile-based builds have had this knob for most of the project's life,
since a479a564dc (Documentation/Makefile: allow
man.base.url.for.relative.link to be set from Make, 2009-12-03).
Meson, however, hard-codes the equivalent of $prefix/$mandir, which is
not really where all the HTML docs are stored in most distro builds.
Plus, this value is missing a trailing slash, so links come out broken,
like this in git.1:
1. Git User’s Manual
/usr/share/manuser-manual.html
Of course we can do better:
1. Change the default to match Make: use file://$(htmldir)/ (with
trailing slash!) to form a local URL pointing at the HTML docs. This
is safe because all current uses of link:<relative> point at HTML
docs:
git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http
produces only a single result (Documentation/howto/howto-index.sh)
which can be ignored. Since nothing else [*] in the normal build sets
MAN_BASE_URL, this seems like the right default.
2. Provide a configurable knob, just like the Makefile, so distributions
that build with Meson (like Gentoo) can decide where to make the
links if they need to. Those that set htmldir probably won't need to
tweak this any further, though.
[*]: Well, Git's todo branch has a script dodoc.sh to build and archive
docs for kernel.org; these docs are pulled by Homebrew
installations, for example. It sets MAN_BASE_URL to "git_htmldocs",
so the equivalent note on macOS + Homebrew is
1. Git User’s Manual
git-htmldocs/user-manual.html
which is not functional either, but that's a problem for
downstream. In any case, users can recover the right path with
"git --html-path".
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
This patch is mostly because I noticed the link I added in a later patch
didn't come out right.
I did an internet search for "MAN_BASE_URL" and got no real hits, so I'm
not sure if any distros today actually use it, but that's not a proper
audit in that I didn't look at any distro _code_ besides Gentoo (which,
as noted, uses Meson).
Documentation/meson.build | 7 ++++++-
meson_options.txt | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..cfa9c67609 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -379,13 +379,18 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml',
)
+ man_base_url = 'file://' + htmldir + '/'
+ if get_option('man_base_url') != ''
+ man_base_url = get_option('man_base_url')
+ endif
+
doc_targets += custom_target(
command: [
xmlto,
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
- 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man.base.url.for.relative.links=' + man_base_url,
'man',
manpage_xml_target,
'-o',
diff --git a/meson_options.txt b/meson_options.txt
index dc88f130d7..d590c21648 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
+option('man_base_url', type: 'string', value: '',
+ description: 'The base URL to use for relative links in manuals')
# Testing.
option('benchmarks', type: 'feature', value: 'auto',
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v3 2/3] environment: align repo_config_values_init with struct declaration
2026-08-18 14:59 ` [PATCH v3 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-18 14:59 ` D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-18 14:59 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Tian Yuchen, Olamide Caleb Bello
The order of assignments in repo_config_values_init is chaotic and hard
to follow, especially when comparing with the struct definition to
ensure all members are initialized. As new members will be added in the
future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
environment.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/environment.c b/environment.c
index 76ee65e62b..6676e6f5ae 100644
--- a/environment.c
+++ b/environment.c
@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg)
{
+ /* section "core" config values */
cfg->attributes_file = NULL;
cfg->excludes_file = NULL;
cfg->editor_program = NULL;
@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->autorebase = AUTOREBASE_NEVER;
cfg->object_creation_mode = OBJECT_CREATION_MODE;
cfg->apply_sparse_checkout = 0;
- cfg->protect_hfs = PROTECT_HFS_DEFAULT;
- cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
- cfg->ignore_case = 0;
- cfg->trust_executable_bit = 1;
- cfg->has_symlinks = platform_has_symlinks();
- cfg->branch_track = BRANCH_TRACK_REMOTE;
cfg->trust_ctime = 1;
cfg->check_stat = 1;
cfg->zlib_compression_level = Z_BEST_SPEED;
cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
cfg->core_sparse_checkout_cone = 0;
- cfg->sparse_expect_files_outside_of_patterns = 0;
cfg->warn_on_object_refname_ambiguity = 1;
+ cfg->protect_hfs = PROTECT_HFS_DEFAULT;
+ cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
+ cfg->ignore_case = 0;
+ cfg->trust_executable_bit = 1;
+ cfg->has_symlinks = platform_has_symlinks();
+
+ /* section "sparse" config values */
+ cfg->sparse_expect_files_outside_of_patterns = 0;
+
+ /* section "branch" config values */
+ cfg->branch_track = BRANCH_TRACK_REMOTE;
}
void repo_config_values_clear(struct repo_config_values *cfg)
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-18 14:59 ` [PATCH v3 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
2026-08-18 14:59 ` [PATCH v3 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-18 14:59 ` D. Ben Knoble
2026-08-18 18:51 ` Junio C Hamano
2026-08-19 8:24 ` Patrick Steinhardt
2 siblings, 2 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-18 14:59 UTC (permalink / raw)
To: git
Cc: D. Ben Knoble, Todd Zullinger, Junio C Hamano, Tian Yuchen,
Patrick Steinhardt, Olamide Caleb Bello
Racy Git problems persist today, manifesting themselves in the
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
but most builds we know about it don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
These days, most platforms are likely to be safe for the USE_NSEC code.
Regardless, we want to give users the ability to benefit from it. This
requires exposing the compile-time gated code as a runtime option.
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
Due to the conversion from #ifdef to runtime check, using the flag
"--ignore-space-change" may be particularly helpful when viewing changes
from this patch.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
CI: <https://github.com/benknoble/git/actions/runs/32137191115>
v3:
We could perhaps be cute in read-cache.c:is_racy_stat() by writing
the preprocessor directive like
return (istate->timestamp.sec &&
#ifndef NO_NSEC
/* nanosecond timestamped files can also be racy! */
use_nsec
? (istate->timestamp.sec < sd->sd_mtime.sec ||
(istate->timestamp.sec == sd->sd_mtime.sec &&
istate->timestamp.nsec <= sd->sd_mtime.nsec))
:
#endif
istate->timestamp.sec <= sd->sd_mtime.sec
but that seemed maybe too clever?
Documentation/config/core.adoc | 6 ++++++
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 10 ++++++++++
environment.h | 1 +
read-cache.c | 16 +++++++++++-----
statinfo.c | 14 ++++++++------
10 files changed, 44 insertions(+), 35 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 340329edc3..33104444ab 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -118,6 +118,12 @@ core.trustctime::
crawlers and some backup systems).
See linkgit:git-update-index[1]. True by default.
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
+ was compiled to store it).
+ See link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
See linkgit:git-update-index[1]. False by default.
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
index 59bea66c0f..499231585b 100644
--- a/Documentation/technical/racy-git.adoc
+++ b/Documentation/technical/racy-git.adoc
@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`
timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
-is not stable on network filesystems. With `USE_NSEC`
-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+is not stable on network filesystems. With 'core.useNanosec'
+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
2005-01-04). This patch is included in kernel 2.6.11 and newer, but
only fixes the issue for file systems with exactly 1 ns or 1 s
-resolution. Other file systems are still broken in current Linux
-kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
+resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)
+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT
+has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to
+work, too.
Racy Git
--------
diff --git a/Makefile b/Makefile
index fac3e8879c..b4ebcb9e83 100644
--- a/Makefile
+++ b/Makefile
@@ -197,18 +197,11 @@ include shared.mak
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.adoc for details.
-#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available. This automatically turns USE_NSEC off.
+# available.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
@@ -1935,9 +1928,6 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
-ifdef USE_NSEC
- BASIC_CFLAGS += -DUSE_NSEC
-endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 241abd4332..8e0c25655f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -130,7 +130,7 @@ static void xrmdir(const char *path)
static void avoid_racy(void)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
+ * not use if we could usleep(10) if core.useNanosec is defined. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..51ee03233b 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
} while (0)
#ifdef NO_NSEC
-#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
diff --git a/configure.ac b/configure.ac
index cfb50112bf..fc956776ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
diff --git a/environment.c b/environment.c
index 6676e6f5ae..c7f6b801f4 100644
--- a/environment.c
+++ b/environment.c
@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
return 0;
}
+#ifndef NO_NSEC
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
+#endif
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
}
@@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
+#ifndef NO_NSEC
+ cfg->use_nanosec = 0;
+#endif
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index e7ec5b0437..a35534afe5 100644
--- a/environment.h
+++ b/environment.h
@@ -139,6 +139,7 @@ struct repo_config_values {
int ignore_case;
int trust_executable_bit;
int has_symlinks;
+ int use_nanosec;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
diff --git a/read-cache.c b/read-cache.c
index 6c449f393d..31888f77ee 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
+#ifndef NO_NSEC
+ int use_nsec = repo_config_values(istate->repo)->use_nanosec;
+#endif
+
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
+#ifndef NO_NSEC
+ /* nanosecond timestamped files can also be racy! */
+ use_nsec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec
#else
istate->timestamp.sec <= sd->sd_mtime.sec
#endif
diff --git a/statinfo.c b/statinfo.c
index 5e00af127d..2f2cec6282 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -72,12 +72,14 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
-#ifdef USE_NSEC
- if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
+#ifndef NO_NSEC
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (cfg->trust_ctime && cfg->check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
#endif
if (cfg->check_stat) {
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-18 14:59 ` [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-18 18:51 ` Junio C Hamano
2026-08-19 12:53 ` D. Ben Knoble
2026-08-19 8:24 ` Patrick Steinhardt
1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-08-18 18:51 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Todd Zullinger, Tian Yuchen, Patrick Steinhardt,
Olamide Caleb Bello
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> diff --git a/environment.c b/environment.c
> index 6676e6f5ae..c7f6b801f4 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> return 0;
> }
>
> +#ifndef NO_NSEC
> + if (!strcmp(var, "core.usenanosec")) {
> + cfg->use_nanosec = git_config_bool(var, value);
> + return 0;
> + }
> +#endif
What this hunk tells us: At build time, you could choose to ignore
core.usenanosec configuration variable, preventing cfg->use_nanosec
from getting flipped to true by the configured value.
> @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)
> cfg->ignore_case = 0;
> cfg->trust_executable_bit = 1;
> cfg->has_symlinks = platform_has_symlinks();
> +#ifndef NO_NSEC
> + cfg->use_nanosec = 0;
> +#endif
I think we want to unconditionally initialize it to 0, unless the
definition of the .use_nanosec member itself in the structure is
conditional on NO_NSEC. And ...
>
> /* section "sparse" config values */
> cfg->sparse_expect_files_outside_of_patterns = 0;
> diff --git a/environment.h b/environment.h
> index e7ec5b0437..a35534afe5 100644
> --- a/environment.h
> +++ b/environment.h
> @@ -139,6 +139,7 @@ struct repo_config_values {
> int ignore_case;
> int trust_executable_bit;
> int has_symlinks;
> + int use_nanosec;
... that is not the case.
Which means that git_default_core_config() does keep the initial
value of the member without getting affected by the configuration,
but it does not necessarily be keeping "false". It may be keeping
the uninitialized state instead ;-).
> diff --git a/read-cache.c b/read-cache.c
> index 6c449f393d..31888f77ee 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> static int is_racy_stat(const struct index_state *istate,
> const struct stat_data *sd)
> {
> +#ifndef NO_NSEC
> + int use_nsec = repo_config_values(istate->repo)->use_nanosec;
> +#endif
> +
> return (istate->timestamp.sec &&
> -#ifdef USE_NSEC
> - /* nanosecond timestamped files can also be racy! */
> - (istate->timestamp.sec < sd->sd_mtime.sec ||
> - (istate->timestamp.sec == sd->sd_mtime.sec &&
> - istate->timestamp.nsec <= sd->sd_mtime.nsec))
> +#ifndef NO_NSEC
> + /* nanosecond timestamped files can also be racy! */
> + use_nsec
> + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> + (istate->timestamp.sec == sd->sd_mtime.sec &&
> + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> + : istate->timestamp.sec <= sd->sd_mtime.sec
> #else
> istate->timestamp.sec <= sd->sd_mtime.sec
> #endif
Ugly. How about getting rid of the latter #ifndef/#else/#endif and
instead keeping the "if use_nsec, pay attention to nsec, otherwise
only the seconds part" ternary? As to the early part, as you can
arrange cfg's '.use_nanosec' to always hold a sensible value, the
function can become
return (istate->timestamp.sec &&
(repo_config_values(istate->repo)->use_nanosec
? (istate->timestamp.sec < sd->sd_mtime.sec ||
(istate->timestamp.sec == sd->sd_mtime.sec &&
istate->timestamp.nsec <= sd->sd_mtime.nsec))
: istate->timestamp.sec <= sd->sd_mtime.sec));
I think.
The code you presented here for is_racy_stat() sprinkled with
#ifndef/#else/#endif would be sensible if repo_config_values struct
defined the '.use_nanosec' member conditionally. But that is not
what is happening here.
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-18 18:51 ` Junio C Hamano
@ 2026-08-19 12:53 ` D. Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-19 12:53 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Todd Zullinger, Tian Yuchen, Patrick Steinhardt,
Olamide Caleb Bello
[Patrick, the below probably helps answer some of your questions as well.]
On Tue, Aug 18, 2026 at 2:51 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > diff --git a/environment.c b/environment.c
> > index 6676e6f5ae..c7f6b801f4 100644
> > --- a/environment.c
> > +++ b/environment.c
> > @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> > return 0;
> > }
> >
> > +#ifndef NO_NSEC
> > + if (!strcmp(var, "core.usenanosec")) {
> > + cfg->use_nanosec = git_config_bool(var, value);
> > + return 0;
> > + }
> > +#endif
>
> What this hunk tells us: At build time, you could choose to ignore
> core.usenanosec configuration variable, preventing cfg->use_nanosec
> from getting flipped to true by the configured value.
>
> > @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)
> > cfg->ignore_case = 0;
> > cfg->trust_executable_bit = 1;
> > cfg->has_symlinks = platform_has_symlinks();
> > +#ifndef NO_NSEC
> > + cfg->use_nanosec = 0;
> > +#endif
>
> I think we want to unconditionally initialize it to 0, unless the
> definition of the .use_nanosec member itself in the structure is
> conditional on NO_NSEC. And ...
>
> >
> > /* section "sparse" config values */
> > cfg->sparse_expect_files_outside_of_patterns = 0;
> > diff --git a/environment.h b/environment.h
> > index e7ec5b0437..a35534afe5 100644
> > --- a/environment.h
> > +++ b/environment.h
> > @@ -139,6 +139,7 @@ struct repo_config_values {
> > int ignore_case;
> > int trust_executable_bit;
> > int has_symlinks;
> > + int use_nanosec;
>
> ... that is not the case.
Doh! I actually intended to send this version with a compiled-out
member when NO_NSEC, since that was the only path I had come up with.
No point in running around with code that's been asked to be ignored,
eh? However…
> Which means that git_default_core_config() does keep the initial
> value of the member without getting affected by the configuration,
> but it does not necessarily be keeping "false". It may be keeping
> the uninitialized state instead ;-).
[ugly #ifdef trimmed]
> Ugly. How about getting rid of the latter #ifndef/#else/#endif and
> instead keeping the "if use_nsec, pay attention to nsec, otherwise
> only the seconds part" ternary? As to the early part, as you can
> arrange cfg's '.use_nanosec' to always hold a sensible value, the
> function can become
>
> return (istate->timestamp.sec &&
> (repo_config_values(istate->repo)->use_nanosec
> ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> (istate->timestamp.sec == sd->sd_mtime.sec &&
> istate->timestamp.nsec <= sd->sd_mtime.nsec))
> : istate->timestamp.sec <= sd->sd_mtime.sec));
>
> I think.
>
> The code you presented here for is_racy_stat() sprinkled with
> #ifndef/#else/#endif would be sensible if repo_config_values struct
> defined the '.use_nanosec' member conditionally. But that is not
> what is happening here.
…I now see a world where we could avoid quite a bit of headache:
- use #if[n]def NO_NSEC to ignore the config variable, but otherwise
- unconditionally compile the cfg->use_nanosec checks
That is, future readers/writers won't have to remember that they can
only use the use_nanosec member under compiler conditionals; it will
always be initialized to a safe value (either always false or from
config). If we're lucky, the compiler will optimize the checks away in
NO_NSEC builds ;)
I think this is what you are suggesting Junio, so let me see what I
can come up with.
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-18 14:59 ` [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2026-08-18 18:51 ` Junio C Hamano
@ 2026-08-19 8:24 ` Patrick Steinhardt
2026-08-19 13:09 ` D. Ben Knoble
2026-08-19 16:15 ` Junio C Hamano
1 sibling, 2 replies; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-19 8:24 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Todd Zullinger, Junio C Hamano, Tian Yuchen,
Olamide Caleb Bello
On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:
> Racy Git problems persist today, manifesting themselves in the
> performance of commands like "git diff" in new worktrees [1]. We have
> long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> precision when available, which mitigates most if not all racy issues,
> but most builds we know about it don't use it. In part, that's because
s/about it/about/
> diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
> index 340329edc3..33104444ab 100644
> --- a/Documentation/config/core.adoc
> +++ b/Documentation/config/core.adoc
> @@ -118,6 +118,12 @@ core.trustctime::
> crawlers and some backup systems).
> See linkgit:git-update-index[1]. True by default.
>
> +core.useNanosec::
> + If true, use nanosecond precision for ctime and mtime
> + comparisions between the index and the working tree (if Git
> + was compiled to store it).
> + See link:technical/racy-git.html[Racy Git]. False by default.
Should we mentino here that this may not be safe on all platforms and/or
filesystems, in addition to linking to racy-hit?
And do we really want to link to the HTML page here? The user may be
reading a manpage, so doing so feels a bit weird to me.
> diff --git a/environment.c b/environment.c
> index 6676e6f5ae..c7f6b801f4 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> return 0;
> }
>
> +#ifndef NO_NSEC
> + if (!strcmp(var, "core.usenanosec")) {
> + cfg->use_nanosec = git_config_bool(var, value);
> + return 0;
> + }
> +#endif
Do we want to omit a warning in case the config is enabled and we have
NO_SEC set? Or would that be too obnoxious?
> @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)
> cfg->ignore_case = 0;
> cfg->trust_executable_bit = 1;
> cfg->has_symlinks = platform_has_symlinks();
> +#ifndef NO_NSEC
> + cfg->use_nanosec = 0;
> +#endif
Can't we set this unconditionally? The respective field exists
unconditionally, too.
> diff --git a/read-cache.c b/read-cache.c
> index 6c449f393d..31888f77ee 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> static int is_racy_stat(const struct index_state *istate,
> const struct stat_data *sd)
> {
> +#ifndef NO_NSEC
> + int use_nsec = repo_config_values(istate->repo)->use_nanosec;
> +#endif
> +
> return (istate->timestamp.sec &&
> -#ifdef USE_NSEC
> - /* nanosecond timestamped files can also be racy! */
> - (istate->timestamp.sec < sd->sd_mtime.sec ||
> - (istate->timestamp.sec == sd->sd_mtime.sec &&
> - istate->timestamp.nsec <= sd->sd_mtime.nsec))
> +#ifndef NO_NSEC
> + /* nanosecond timestamped files can also be racy! */
> + use_nsec
> + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> + (istate->timestamp.sec == sd->sd_mtime.sec &&
> + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> + : istate->timestamp.sec <= sd->sd_mtime.sec
> #else
> istate->timestamp.sec <= sd->sd_mtime.sec
> #endif
I think this would be a bit more readable if we had a single NO_NSEC
block.
> diff --git a/statinfo.c b/statinfo.c
> index 5e00af127d..2f2cec6282 100644
> --- a/statinfo.c
> +++ b/statinfo.c
> @@ -72,12 +72,14 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
> sd->sd_ctime.sec != (unsigned int)st->st_ctime)
> changed |= CTIME_CHANGED;
>
> -#ifdef USE_NSEC
> - if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
> - changed |= MTIME_CHANGED;
> - if (cfg->trust_ctime && cfg->check_stat &&
> - sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
> - changed |= CTIME_CHANGED;
> +#ifndef NO_NSEC
> + if (cfg->use_nanosec) {
> + if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
> + changed |= MTIME_CHANGED;
> + if (cfg->trust_ctime && cfg->check_stat &&
> + sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
> + changed |= CTIME_CHANGED;
> + }
> #endif
There's one more site in "builtin/update-index.c" where we mention
USE_NSEC that wasn't updated as part of this patch.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-19 8:24 ` Patrick Steinhardt
@ 2026-08-19 13:09 ` D. Ben Knoble
2026-08-20 5:24 ` Patrick Steinhardt
2026-08-19 16:15 ` Junio C Hamano
1 sibling, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-19 13:09 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: git, Todd Zullinger, Junio C Hamano, Tian Yuchen,
Olamide Caleb Bello
On Wed, Aug 19, 2026 at 4:24 AM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:
> > Racy Git problems persist today, manifesting themselves in the
> > performance of commands like "git diff" in new worktrees [1]. We have
> > long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> > precision when available, which mitigates most if not all racy issues,
> > but most builds we know about it don't use it. In part, that's because
>
> s/about it/about/
Thanks; fixed locally.
> > diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
> > index 340329edc3..33104444ab 100644
> > --- a/Documentation/config/core.adoc
> > +++ b/Documentation/config/core.adoc
> > @@ -118,6 +118,12 @@ core.trustctime::
> > crawlers and some backup systems).
> > See linkgit:git-update-index[1]. True by default.
> >
> > +core.useNanosec::
> > + If true, use nanosecond precision for ctime and mtime
> > + comparisions between the index and the working tree (if Git
> > + was compiled to store it).
> > + See link:technical/racy-git.html[Racy Git]. False by default.
>
> Should we mentino here that this may not be safe on all platforms and/or
> filesystems, in addition to linking to racy-hit?
Yeah, a brief mention here is probably warranted.
> And do we really want to link to the HTML page here? The user may be
> reading a manpage, so doing so feels a bit weird to me.
See a variation on the grep done in patch 1; we link lots of HTML
documentation in our manuals (including when rendered to manpage
format).
AFAICT, the idea is that we produce manual pages for commands and a
few other "special" documents; we produce HTML of everything. So there
isn't a good non-HTML link target for, e.g., the Racy Git document. In
particular, even "git help" doesn't know about Racy Git. I have a
script [1] that opens files out of "git --html-path", so that provides
one way to access the Racy Git document (aside: neither of my
systems---Homebrew macOS or Portage Gentoo---install anything into
"git --info-path", so that would not make a good link target even if I
knew how to write it). Patch 1/3 makes it easier to get the correct
link in the manual for folks who can click links in their terminal
emulators (or copy-paste).
[1]: https://github.com/benknoble/Dotfiles/tree/master/links/bin/git-doc
(with completion!
https://github.com/benknoble/Dotfiles/tree/master/links/zshfns/_git_doc)
TBH, I am not sure what other folks do for these HTML links in
manuals. As I mention in patch 1, the Homebrew links are broken. If
you know about "git --html-path" you can find the documents, or use
the Git SCM website's rendered versions.
Anyway, this is the current "normal" style for linking, I think.
> > diff --git a/environment.c b/environment.c
> > index 6676e6f5ae..c7f6b801f4 100644
> > --- a/environment.c
> > +++ b/environment.c
> > @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> > return 0;
> > }
> >
> > +#ifndef NO_NSEC
> > + if (!strcmp(var, "core.usenanosec")) {
> > + cfg->use_nanosec = git_config_bool(var, value);
> > + return 0;
> > + }
> > +#endif
>
> Do we want to omit a warning in case the config is enabled and we have
> NO_SEC set? Or would that be too obnoxious?
I would say that can always be done later ;) Perhaps it should be
better documented, though, so let me try that, too.
>
> > @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)
> > cfg->ignore_case = 0;
> > cfg->trust_executable_bit = 1;
> > cfg->has_symlinks = platform_has_symlinks();
> > +#ifndef NO_NSEC
> > + cfg->use_nanosec = 0;
> > +#endif
>
> Can't we set this unconditionally? The respective field exists
> unconditionally, too.
Yep, see reply to Junio.
> > diff --git a/read-cache.c b/read-cache.c
> > index 6c449f393d..31888f77ee 100644
> > --- a/read-cache.c
> > +++ b/read-cache.c
> > @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> > static int is_racy_stat(const struct index_state *istate,
> > const struct stat_data *sd)
> > {
> > +#ifndef NO_NSEC
> > + int use_nsec = repo_config_values(istate->repo)->use_nanosec;
> > +#endif
> > +
> > return (istate->timestamp.sec &&
> > -#ifdef USE_NSEC
> > - /* nanosecond timestamped files can also be racy! */
> > - (istate->timestamp.sec < sd->sd_mtime.sec ||
> > - (istate->timestamp.sec == sd->sd_mtime.sec &&
> > - istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > +#ifndef NO_NSEC
> > + /* nanosecond timestamped files can also be racy! */
> > + use_nsec
> > + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> > + (istate->timestamp.sec == sd->sd_mtime.sec &&
> > + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > + : istate->timestamp.sec <= sd->sd_mtime.sec
> > #else
> > istate->timestamp.sec <= sd->sd_mtime.sec
> > #endif
>
> I think this would be a bit more readable if we had a single NO_NSEC
> block.
I'm not sure what "single block" means here, but I think the plan (see
reply to Junio) is to make this more readable by not needing
pre-processor directives at all.
[snip]
> There's one more site in "builtin/update-index.c" where we mention
> USE_NSEC that wasn't updated as part of this patch.
Oh, did I miss one? The only spot I saw in builtin/update-index.c that
mentions USE_NSEC is a comment that I'm sure patch 3 updated. Maybe
you were thinking of that, or maybe you know of something I left out?
(That is, locally on this branch, "git grep USE_NSEC" returns one hit
in Documentation/RelNotes/2.5.0.adoc.)
Thanks!
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-19 13:09 ` D. Ben Knoble
@ 2026-08-20 5:24 ` Patrick Steinhardt
2026-08-20 11:50 ` D. Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-20 5:24 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Todd Zullinger, Junio C Hamano, Tian Yuchen,
Olamide Caleb Bello
On Wed, Aug 19, 2026 at 09:09:59AM -0400, D. Ben Knoble wrote:
> On Wed, Aug 19, 2026 at 4:24 AM Patrick Steinhardt <ps@pks.im> wrote:
> > On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:
> > > diff --git a/read-cache.c b/read-cache.c
> > > index 6c449f393d..31888f77ee 100644
> > > --- a/read-cache.c
> > > +++ b/read-cache.c
> > > @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
> > > static int is_racy_stat(const struct index_state *istate,
> > > const struct stat_data *sd)
> > > {
> > > +#ifndef NO_NSEC
> > > + int use_nsec = repo_config_values(istate->repo)->use_nanosec;
> > > +#endif
> > > +
> > > return (istate->timestamp.sec &&
> > > -#ifdef USE_NSEC
> > > - /* nanosecond timestamped files can also be racy! */
> > > - (istate->timestamp.sec < sd->sd_mtime.sec ||
> > > - (istate->timestamp.sec == sd->sd_mtime.sec &&
> > > - istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > > +#ifndef NO_NSEC
> > > + /* nanosecond timestamped files can also be racy! */
> > > + use_nsec
> > > + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> > > + (istate->timestamp.sec == sd->sd_mtime.sec &&
> > > + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > > + : istate->timestamp.sec <= sd->sd_mtime.sec
> > > #else
> > > istate->timestamp.sec <= sd->sd_mtime.sec
> > > #endif
> >
> > I think this would be a bit more readable if we had a single NO_NSEC
> > block.
>
> I'm not sure what "single block" means here, but I think the plan (see
> reply to Junio) is to make this more readable by not needing
> pre-processor directives at all.
That'd be quite welcome indeed. The less ifdeffery the bettery. :)
> > There's one more site in "builtin/update-index.c" where we mention
> > USE_NSEC that wasn't updated as part of this patch.
>
> Oh, did I miss one? The only spot I saw in builtin/update-index.c that
> mentions USE_NSEC is a comment that I'm sure patch 3 updated. Maybe
> you were thinking of that, or maybe you know of something I left out?
> (That is, locally on this branch, "git grep USE_NSEC" returns one hit
> in Documentation/RelNotes/2.5.0.adoc.)
Oh, I guess I just missed it because I already trimmed context of this
mail. Never mind then.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-20 5:24 ` Patrick Steinhardt
@ 2026-08-20 11:50 ` D. Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-20 11:50 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: git, Todd Zullinger, Junio C Hamano, Tian Yuchen,
Olamide Caleb Bello
On Thu, Aug 20, 2026 at 1:24 AM Patrick Steinhardt <ps@pks.im> wrote:
>
> That'd be quite welcome indeed. The less ifdeffery the bettery. :)
Agreed!
> On Wed, Aug 19, 2026 at 09:09:59AM -0400, D. Ben Knoble wrote:
> > On Wed, Aug 19, 2026 at 4:24 AM Patrick Steinhardt <ps@pks.im> wrote:
> > > There's one more site in "builtin/update-index.c" where we mention
> > > USE_NSEC that wasn't updated as part of this patch.
> >
> > Oh, did I miss one? The only spot I saw in builtin/update-index.c that
> > mentions USE_NSEC is a comment that I'm sure patch 3 updated. Maybe
> > you were thinking of that, or maybe you know of something I left out?
> > (That is, locally on this branch, "git grep USE_NSEC" returns one hit
> > in Documentation/RelNotes/2.5.0.adoc.)
>
> Oh, I guess I just missed it because I already trimmed context of this
> mail. Never mind then.
>
> Patrick
No worries, I appreciate the careful read!
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-19 8:24 ` Patrick Steinhardt
2026-08-19 13:09 ` D. Ben Knoble
@ 2026-08-19 16:15 ` Junio C Hamano
2026-08-19 22:56 ` D. Ben Knoble
2026-08-20 5:26 ` Patrick Steinhardt
1 sibling, 2 replies; 68+ messages in thread
From: Junio C Hamano @ 2026-08-19 16:15 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: D. Ben Knoble, git, Todd Zullinger, Tian Yuchen,
Olamide Caleb Bello
Patrick Steinhardt <ps@pks.im> writes:
>> diff --git a/environment.c b/environment.c
>> index 6676e6f5ae..c7f6b801f4 100644
>> --- a/environment.c
>> +++ b/environment.c
>> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
>> return 0;
>> }
>>
>> +#ifndef NO_NSEC
>> + if (!strcmp(var, "core.usenanosec")) {
>> + cfg->use_nanosec = git_config_bool(var, value);
>> + return 0;
>> + }
>> +#endif
>
> Do we want to omit a warning in case the config is enabled and we have
> NO_SEC set? Or would that be too obnoxious?
Those who use a $HOME/.gitconfig shared across two machines with
different builds would be annoyed with one of them constantly
complaining, I am afraid.
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-19 16:15 ` Junio C Hamano
@ 2026-08-19 22:56 ` D. Ben Knoble
2026-08-20 5:26 ` Patrick Steinhardt
1 sibling, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-19 22:56 UTC (permalink / raw)
To: Junio C Hamano
Cc: Patrick Steinhardt, git, Todd Zullinger, Tian Yuchen,
Olamide Caleb Bello
On Wed, Aug 19, 2026 at 12:15 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Patrick Steinhardt <ps@pks.im> writes:
>
> >> diff --git a/environment.c b/environment.c
> >> index 6676e6f5ae..c7f6b801f4 100644
> >> --- a/environment.c
> >> +++ b/environment.c
> >> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> >> return 0;
> >> }
> >>
> >> +#ifndef NO_NSEC
> >> + if (!strcmp(var, "core.usenanosec")) {
> >> + cfg->use_nanosec = git_config_bool(var, value);
> >> + return 0;
> >> + }
> >> +#endif
> >
> > Do we want to omit a warning in case the config is enabled and we have
> > NO_SEC set? Or would that be too obnoxious?
>
> Those who use a $HOME/.gitconfig shared across two machines with
> different builds would be annoyed with one of them constantly
> complaining, I am afraid.
Ah, that reminds me; my shared ~/.gitconfig includes a "site-local"
config path, which could then be used to set this option (or not) only
where supported.
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-19 16:15 ` Junio C Hamano
2026-08-19 22:56 ` D. Ben Knoble
@ 2026-08-20 5:26 ` Patrick Steinhardt
1 sibling, 0 replies; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-20 5:26 UTC (permalink / raw)
To: Junio C Hamano
Cc: D. Ben Knoble, git, Todd Zullinger, Tian Yuchen,
Olamide Caleb Bello
On Wed, Aug 19, 2026 at 09:15:44AM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
> >> diff --git a/environment.c b/environment.c
> >> index 6676e6f5ae..c7f6b801f4 100644
> >> --- a/environment.c
> >> +++ b/environment.c
> >> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> >> return 0;
> >> }
> >>
> >> +#ifndef NO_NSEC
> >> + if (!strcmp(var, "core.usenanosec")) {
> >> + cfg->use_nanosec = git_config_bool(var, value);
> >> + return 0;
> >> + }
> >> +#endif
> >
> > Do we want to omit a warning in case the config is enabled and we have
> > NO_SEC set? Or would that be too obnoxious?
>
> Those who use a $HOME/.gitconfig shared across two machines with
> different builds would be annoyed with one of them constantly
> complaining, I am afraid.
Yeah, that's what I was hinting at with "too obnovious". So I agree,
let's not add one.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v4 0/3] Convert USE_NSEC to runtime config
2026-08-07 11:56 [PATCH 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (4 preceding siblings ...)
2026-08-18 14:59 ` [PATCH v3 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-20 13:18 ` D. Ben Knoble
2026-08-20 13:18 ` [PATCH v4 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
` (4 more replies)
5 siblings, 5 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-20 13:18 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble
Topic name: dk/use-nsec-runtime (applied)
Topic summary: Expose USE_NSEC as a runtime configuration, since
build-time is too early for distributing Git [1]. As a result, common
index-related options, like git-diff, are less likely to hit "racy git"
problems on supported filesystems.
[1]: https://git.github.io/rev_news/2026/07/31/edition-137/
Built on master (2c78326f81 (The 11th batch, 2026-08-05)).
Changes in v4:
- fix message typo
- change #ifdef strategy: only ignore the config variable.
Otherwise, use the use_nanosec member unconditionally. Also clarify
that config might be ignore depending on build options in the docs.
- mention potential platform unsafety directly in config doc in
addition to the link to Racy Git
Changes in v3:
- #ifdef out use_nanosec when NO_NSEC is requested
As I have heard no comments about the "Todo" lines below, which perhaps
could more clearly be marked "RFC"/"RFH", I've added this line to call
them out ;) and renamed them "Comments welcome"
Changes in v2:
- move Best-viewed-with trailer into message body as descriptive
text.
- read core.useNanosec through struct repo instead of parsing
config strings. The test suite passes locally this way, though that
skipped 151 tests.
- CI run: https://github.com/benknoble/git/actions/runs/31701945211
Original cover letter:
Hi all, this series follows up on the previous racy Git/USE_NSEC
conversations.
- The first patch is a mostly-unrelated documentation fix for Meson, but
it came out of something I spotted while reviewing the outputs of the
final (main) patch.
- The second patch is a preliminary no-op reorganization of
repo_config_values_init.
- The third patch is the meat, converting USE_NSEC into core.useNanosec.
There is a small textual and semantic conflict with
'ty/repo-config-cleanups' in 'seen', since that branch removes the
comments in 'struct repo_config_values' which this series adds to. (The
semantic conflict is that, if we drop those comments, we should probably
not add them to repo_config_values_init like I do in patch 2.)
Comments welcome: I haven't touched any tests; I saw a bunch of hits for
"git grep racy t" but wasn't sure how to fit this particular change in,
especially since it won't be equally valid on all systems? Advice
welcome.
Comments welcome: I wonder if "useNanosec" paints us into too much of a
corner; that is (slightly more abstractly), we are using *extended
precision* in the index. Maybe the name and documentation should reflect
that, so we aren't too committed to "nanoseconds"?
- Some platforms could offer extended precision that is not as
precise as nanoseconds
- Some could offer precision _beyond_ nanoseconds
idk.
v1: <cover.1786103607.git.ben.knoble@gmail.com>
v2: <cover.1786710807.git.ben.knoble@gmail.com>
v3: <cover.1787065125.git.ben.knoble@gmail.com>
[1/3] meson: expose knob for xmlto relative links in manuals
[2/3] environment: align repo_config_values_init with struct declaration
[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
Documentation/config/core.adoc | 7 +++++++
Documentation/meson.build | 7 ++++++-
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 27 ++++++++++++++++++++-------
environment.h | 1 +
meson_options.txt | 2 ++
read-cache.c | 15 ++++++---------
statinfo.c | 14 +++++++-------
12 files changed, 57 insertions(+), 48 deletions(-)
Diff-intervalle contre v3 :
1: d612de6c2d = 1: d612de6c2d meson: expose knob for xmlto relative links in manuals
2: 5693baa992 = 2: 5693baa992 environment: align repo_config_values_init with struct declaration
3: 48fceb4b57 ! 3: 0aa0e9fc17 core: convert build-time USE_NSEC into runtime core.useNanosec
@@ Commit message
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
- but most builds we know about it don't use it. In part, that's because
+ but most builds we know about don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
@@ Commit message
## Notes (benknoble/commits) ##
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
- CI: <https://github.com/benknoble/git/actions/runs/32137191115>
-
- v3:
- We could perhaps be cute in read-cache.c:is_racy_stat() by writing
- the preprocessor directive like
-
- return (istate->timestamp.sec &&
- #ifndef NO_NSEC
- /* nanosecond timestamped files can also be racy! */
- use_nsec
- ? (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
- :
- #endif
- istate->timestamp.sec <= sd->sd_mtime.sec
-
- but that seemed maybe too clever?
+ CI: <https://github.com/benknoble/git/actions/runs/32365602564>
## Documentation/config/core.adoc ##
@@ Documentation/config/core.adoc: core.trustctime::
@@ Documentation/config/core.adoc: core.trustctime::
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
-+ was compiled to store it).
-+ See link:technical/racy-git.html[Racy Git]. False by default.
++ was compiled to respect this option).
++ This is unsafe on some platforms;
++ see link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
@@ environment.c: void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
-+#ifndef NO_NSEC
+ cfg->use_nanosec = 0;
-+#endif
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
@@ environment.h: struct repo_config_values {
int sparse_expect_files_outside_of_patterns;
## read-cache.c ##
-@@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
- static int is_racy_stat(const struct index_state *istate,
+@@ read-cache.c: static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
-+#ifndef NO_NSEC
-+ int use_nsec = repo_config_values(istate->repo)->use_nanosec;
-+#endif
-+
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
-+#ifndef NO_NSEC
+-#else
+- istate->timestamp.sec <= sd->sd_mtime.sec
+-#endif
+- );
+ /* nanosecond timestamped files can also be racy! */
-+ use_nsec
-+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
-+ (istate->timestamp.sec == sd->sd_mtime.sec &&
-+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
-+ : istate->timestamp.sec <= sd->sd_mtime.sec
- #else
- istate->timestamp.sec <= sd->sd_mtime.sec
- #endif
++ (repo_config_values(istate->repo)->use_nanosec
++ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
++ (istate->timestamp.sec == sd->sd_mtime.sec &&
++ istate->timestamp.nsec <= sd->sd_mtime.nsec))
++ : istate->timestamp.sec <= sd->sd_mtime.sec));
+ }
+
+ int is_racy_timestamp(const struct index_state *istate,
## statinfo.c ##
@@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)
@@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-+#ifndef NO_NSEC
+-#endif
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
@@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
- #endif
if (cfg->check_stat) {
+ if (sd->sd_uid != (unsigned int) st->st_uid ||
base-commit: 2c78326f810173a4f3aefd8021f1e07575412481
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply [flat|nested] 68+ messages in thread* [PATCH v4 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-20 13:18 ` D. Ben Knoble
2026-08-20 13:18 ` [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
` (3 subsequent siblings)
4 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-20 13:18 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Patrick Steinhardt, Junio C Hamano
Makefile-based builds have had this knob for most of the project's life,
since a479a564dc (Documentation/Makefile: allow
man.base.url.for.relative.link to be set from Make, 2009-12-03).
Meson, however, hard-codes the equivalent of $prefix/$mandir, which is
not really where all the HTML docs are stored in most distro builds.
Plus, this value is missing a trailing slash, so links come out broken,
like this in git.1:
1. Git User’s Manual
/usr/share/manuser-manual.html
Of course we can do better:
1. Change the default to match Make: use file://$(htmldir)/ (with
trailing slash!) to form a local URL pointing at the HTML docs. This
is safe because all current uses of link:<relative> point at HTML
docs:
git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http
produces only a single result (Documentation/howto/howto-index.sh)
which can be ignored. Since nothing else [*] in the normal build sets
MAN_BASE_URL, this seems like the right default.
2. Provide a configurable knob, just like the Makefile, so distributions
that build with Meson (like Gentoo) can decide where to make the
links if they need to. Those that set htmldir probably won't need to
tweak this any further, though.
[*]: Well, Git's todo branch has a script dodoc.sh to build and archive
docs for kernel.org; these docs are pulled by Homebrew
installations, for example. It sets MAN_BASE_URL to "git_htmldocs",
so the equivalent note on macOS + Homebrew is
1. Git User’s Manual
git-htmldocs/user-manual.html
which is not functional either, but that's a problem for
downstream. In any case, users can recover the right path with
"git --html-path".
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
This patch is mostly because I noticed the link I added in a later patch
didn't come out right.
I did an internet search for "MAN_BASE_URL" and got no real hits, so I'm
not sure if any distros today actually use it, but that's not a proper
audit in that I didn't look at any distro _code_ besides Gentoo (which,
as noted, uses Meson).
Documentation/meson.build | 7 ++++++-
meson_options.txt | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..cfa9c67609 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -379,13 +379,18 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml',
)
+ man_base_url = 'file://' + htmldir + '/'
+ if get_option('man_base_url') != ''
+ man_base_url = get_option('man_base_url')
+ endif
+
doc_targets += custom_target(
command: [
xmlto,
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
- 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man.base.url.for.relative.links=' + man_base_url,
'man',
manpage_xml_target,
'-o',
diff --git a/meson_options.txt b/meson_options.txt
index dc88f130d7..d590c21648 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
+option('man_base_url', type: 'string', value: '',
+ description: 'The base URL to use for relative links in manuals')
# Testing.
option('benchmarks', type: 'feature', value: 'auto',
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-20 13:18 ` [PATCH v4 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-20 13:18 ` D. Ben Knoble
2026-08-20 17:45 ` Junio C Hamano
2026-08-20 13:18 ` [PATCH v4 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
` (2 subsequent siblings)
4 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-20 13:18 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Tian Yuchen, Olamide Caleb Bello
The order of assignments in repo_config_values_init is chaotic and hard
to follow, especially when comparing with the struct definition to
ensure all members are initialized. As new members will be added in the
future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
environment.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/environment.c b/environment.c
index 76ee65e62b..6676e6f5ae 100644
--- a/environment.c
+++ b/environment.c
@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg)
{
+ /* section "core" config values */
cfg->attributes_file = NULL;
cfg->excludes_file = NULL;
cfg->editor_program = NULL;
@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->autorebase = AUTOREBASE_NEVER;
cfg->object_creation_mode = OBJECT_CREATION_MODE;
cfg->apply_sparse_checkout = 0;
- cfg->protect_hfs = PROTECT_HFS_DEFAULT;
- cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
- cfg->ignore_case = 0;
- cfg->trust_executable_bit = 1;
- cfg->has_symlinks = platform_has_symlinks();
- cfg->branch_track = BRANCH_TRACK_REMOTE;
cfg->trust_ctime = 1;
cfg->check_stat = 1;
cfg->zlib_compression_level = Z_BEST_SPEED;
cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
cfg->core_sparse_checkout_cone = 0;
- cfg->sparse_expect_files_outside_of_patterns = 0;
cfg->warn_on_object_refname_ambiguity = 1;
+ cfg->protect_hfs = PROTECT_HFS_DEFAULT;
+ cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
+ cfg->ignore_case = 0;
+ cfg->trust_executable_bit = 1;
+ cfg->has_symlinks = platform_has_symlinks();
+
+ /* section "sparse" config values */
+ cfg->sparse_expect_files_outside_of_patterns = 0;
+
+ /* section "branch" config values */
+ cfg->branch_track = BRANCH_TRACK_REMOTE;
}
void repo_config_values_clear(struct repo_config_values *cfg)
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration
2026-08-20 13:18 ` [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-20 17:45 ` Junio C Hamano
2026-08-21 12:10 ` D. Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-08-20 17:45 UTC (permalink / raw)
To: D. Ben Knoble; +Cc: git, Tian Yuchen, Olamide Caleb Bello
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> The order of assignments in repo_config_values_init is chaotic and hard
> to follow, especially when comparing with the struct definition to
> ensure all members are initialized. As new members will be added in the
> future, make it easier to validate changes by aligning the two.
>
> Refactor assignment order with no behavioral changes.
After reading the above three times, I am tempted to slightly tweak
the above:
... comparing with the definition of 'struct repo_config_values' to
ensure ...
Other than that, great improvement.
Thanks.
>
> Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
> ---
> environment.c | 19 ++++++++++++-------
> 1 file changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/environment.c b/environment.c
> index 76ee65e62b..6676e6f5ae 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
>
> void repo_config_values_init(struct repo_config_values *cfg)
> {
> + /* section "core" config values */
> cfg->attributes_file = NULL;
> cfg->excludes_file = NULL;
> cfg->editor_program = NULL;
> @@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
> cfg->autorebase = AUTOREBASE_NEVER;
> cfg->object_creation_mode = OBJECT_CREATION_MODE;
> cfg->apply_sparse_checkout = 0;
> - cfg->protect_hfs = PROTECT_HFS_DEFAULT;
> - cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
> - cfg->ignore_case = 0;
> - cfg->trust_executable_bit = 1;
> - cfg->has_symlinks = platform_has_symlinks();
> - cfg->branch_track = BRANCH_TRACK_REMOTE;
> cfg->trust_ctime = 1;
> cfg->check_stat = 1;
> cfg->zlib_compression_level = Z_BEST_SPEED;
> cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
> cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
> cfg->core_sparse_checkout_cone = 0;
> - cfg->sparse_expect_files_outside_of_patterns = 0;
> cfg->warn_on_object_refname_ambiguity = 1;
> + cfg->protect_hfs = PROTECT_HFS_DEFAULT;
> + cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
> + cfg->ignore_case = 0;
> + cfg->trust_executable_bit = 1;
> + cfg->has_symlinks = platform_has_symlinks();
> +
> + /* section "sparse" config values */
> + cfg->sparse_expect_files_outside_of_patterns = 0;
> +
> + /* section "branch" config values */
> + cfg->branch_track = BRANCH_TRACK_REMOTE;
> }
>
> void repo_config_values_clear(struct repo_config_values *cfg)
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration
2026-08-20 17:45 ` Junio C Hamano
@ 2026-08-21 12:10 ` D. Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-21 12:10 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Tian Yuchen, Olamide Caleb Bello
On Thu, Aug 20, 2026 at 1:45 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > The order of assignments in repo_config_values_init is chaotic and hard
> > to follow, especially when comparing with the struct definition to
> > ensure all members are initialized. As new members will be added in the
> > future, make it easier to validate changes by aligning the two.
> >
> > Refactor assignment order with no behavioral changes.
>
> After reading the above three times, I am tempted to slightly tweak
> the above:
>
> ... comparing with the definition of 'struct repo_config_values' to
> ensure ...
>
> Other than that, great improvement.
>
> Thanks.
Yep, that flows much better. Amended locally.
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v4 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-20 13:18 ` [PATCH v4 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
2026-08-20 13:18 ` [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-20 13:18 ` D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
4 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-20 13:18 UTC (permalink / raw)
To: git
Cc: D. Ben Knoble, Tian Yuchen, Todd Zullinger, Junio C Hamano,
Olamide Caleb Bello, Patrick Steinhardt
Racy Git problems persist today, manifesting themselves in the
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
but most builds we know about don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
These days, most platforms are likely to be safe for the USE_NSEC code.
Regardless, we want to give users the ability to benefit from it. This
requires exposing the compile-time gated code as a runtime option.
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
Due to the conversion from #ifdef to runtime check, using the flag
"--ignore-space-change" may be particularly helpful when viewing changes
from this patch.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
CI: <https://github.com/benknoble/git/actions/runs/32365602564>
Documentation/config/core.adoc | 7 +++++++
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 8 ++++++++
environment.h | 1 +
read-cache.c | 15 ++++++---------
statinfo.c | 14 +++++++-------
10 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 340329edc3..b793f62e42 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -118,6 +118,13 @@ core.trustctime::
crawlers and some backup systems).
See linkgit:git-update-index[1]. True by default.
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
+ was compiled to respect this option).
+ This is unsafe on some platforms;
+ see link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
See linkgit:git-update-index[1]. False by default.
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
index 59bea66c0f..499231585b 100644
--- a/Documentation/technical/racy-git.adoc
+++ b/Documentation/technical/racy-git.adoc
@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`
timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
-is not stable on network filesystems. With `USE_NSEC`
-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+is not stable on network filesystems. With 'core.useNanosec'
+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
2005-01-04). This patch is included in kernel 2.6.11 and newer, but
only fixes the issue for file systems with exactly 1 ns or 1 s
-resolution. Other file systems are still broken in current Linux
-kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
+resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)
+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT
+has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to
+work, too.
Racy Git
--------
diff --git a/Makefile b/Makefile
index fac3e8879c..b4ebcb9e83 100644
--- a/Makefile
+++ b/Makefile
@@ -197,18 +197,11 @@ include shared.mak
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.adoc for details.
-#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available. This automatically turns USE_NSEC off.
+# available.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
@@ -1935,9 +1928,6 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
-ifdef USE_NSEC
- BASIC_CFLAGS += -DUSE_NSEC
-endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 241abd4332..8e0c25655f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -130,7 +130,7 @@ static void xrmdir(const char *path)
static void avoid_racy(void)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
+ * not use if we could usleep(10) if core.useNanosec is defined. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..51ee03233b 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
} while (0)
#ifdef NO_NSEC
-#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
diff --git a/configure.ac b/configure.ac
index cfb50112bf..fc956776ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
diff --git a/environment.c b/environment.c
index 6676e6f5ae..c83cf44839 100644
--- a/environment.c
+++ b/environment.c
@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
return 0;
}
+#ifndef NO_NSEC
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
+#endif
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
}
@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
+ cfg->use_nanosec = 0;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index e7ec5b0437..a35534afe5 100644
--- a/environment.h
+++ b/environment.h
@@ -139,6 +139,7 @@ struct repo_config_values {
int ignore_case;
int trust_executable_bit;
int has_symlinks;
+ int use_nanosec;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
diff --git a/read-cache.c b/read-cache.c
index 6c449f393d..b32cfd0ef1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
-#else
- istate->timestamp.sec <= sd->sd_mtime.sec
-#endif
- );
+ /* nanosecond timestamped files can also be racy! */
+ (repo_config_values(istate->repo)->use_nanosec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec));
}
int is_racy_timestamp(const struct index_state *istate,
diff --git a/statinfo.c b/statinfo.c
index 5e00af127d..d9ddcf9382 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
-#ifdef USE_NSEC
- if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (cfg->trust_ctime && cfg->check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
if (cfg->check_stat) {
if (sd->sd_uid != (unsigned int) st->st_uid ||
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v5 0/3] Convert USE_NSEC to runtime config
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (2 preceding siblings ...)
2026-08-20 13:18 ` [PATCH v4 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-29 13:38 ` D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
` (2 more replies)
2026-08-31 20:01 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
4 siblings, 3 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-29 13:38 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble
Topic name: dk/use-nsec-runtime (applied)
Topic summary: Expose USE_NSEC as a runtime configuration, since
build-time is too early for distributing Git [1]. As a result, common
index-related options, like git-diff, are less likely to hit "racy git"
problems on supported filesystems.
[1]: https://git.github.io/rev_news/2026/07/31/edition-137/
Built on master (2c78326f81 (The 11th batch, 2026-08-05)).
Changes in v5:
- improve message flow in patch 2
Junio: my apologies. I missed that the "What's cooking" changed from "Needs
review" (#10) to "expecting a small (hopefully final) reroll" (#11, #12),
since I was expecting to see Patrick's review. This just tweaks the commit
message as you suggested.
Changes in v4:
- fix message typo
- change #ifdef strategy: only ignore the config variable.
Otherwise, use the use_nanosec member unconditionally. Also clarify
that config might be ignore depending on build options in the docs.
- mention potential platform unsafety directly in config doc in
addition to the link to Racy Git
Changes in v3:
- #ifdef out use_nanosec when NO_NSEC is requested
As I have heard no comments about the "Todo" lines below, which perhaps
could more clearly be marked "RFC"/"RFH", I've added this line to call
them out ;) and renamed them "Comments welcome"
Changes in v2:
- move Best-viewed-with trailer into message body as descriptive
text.
- read core.useNanosec through struct repo instead of parsing
config strings. The test suite passes locally this way, though that
skipped 151 tests.
- CI run: https://github.com/benknoble/git/actions/runs/31701945211
Original cover letter:
Hi all, this series follows up on the previous racy Git/USE_NSEC
conversations.
- The first patch is a mostly-unrelated documentation fix for Meson, but
it came out of something I spotted while reviewing the outputs of the
final (main) patch.
- The second patch is a preliminary no-op reorganization of
repo_config_values_init.
- The third patch is the meat, converting USE_NSEC into core.useNanosec.
There is a small textual and semantic conflict with
'ty/repo-config-cleanups' in 'seen', since that branch removes the
comments in 'struct repo_config_values' which this series adds to. (The
semantic conflict is that, if we drop those comments, we should probably
not add them to repo_config_values_init like I do in patch 2.)
Comments welcome: I haven't touched any tests; I saw a bunch of hits for
"git grep racy t" but wasn't sure how to fit this particular change in,
especially since it won't be equally valid on all systems? Advice
welcome.
Comments welcome: I wonder if "useNanosec" paints us into too much of a
corner; that is (slightly more abstractly), we are using *extended
precision* in the index. Maybe the name and documentation should reflect
that, so we aren't too committed to "nanoseconds"?
- Some platforms could offer extended precision that is not as
precise as nanoseconds
- Some could offer precision _beyond_ nanoseconds
idk.
v1: <cover.1786103607.git.ben.knoble@gmail.com>
v2: <cover.1786710807.git.ben.knoble@gmail.com>
v3: <cover.1787065125.git.ben.knoble@gmail.com>
v4: <cover.1787231825.git.ben.knoble@gmail.com>
[1/3] meson: expose knob for xmlto relative links in manuals
[2/3] environment: align repo_config_values_init with struct declaration
[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
Documentation/config/core.adoc | 7 +++++++
Documentation/meson.build | 7 ++++++-
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 27 ++++++++++++++++++++-------
environment.h | 1 +
meson_options.txt | 2 ++
read-cache.c | 15 ++++++---------
statinfo.c | 14 +++++++-------
12 files changed, 57 insertions(+), 48 deletions(-)
Diff-intervalle contre v4 :
1: d612de6c2d = 1: d612de6c2d meson: expose knob for xmlto relative links in manuals
2: 5693baa992 ! 2: 12974e07d0 environment: align repo_config_values_init with struct declaration
@@ Commit message
environment: align repo_config_values_init with struct declaration
The order of assignments in repo_config_values_init is chaotic and hard
- to follow, especially when comparing with the struct definition to
- ensure all members are initialized. As new members will be added in the
- future, make it easier to validate changes by aligning the two.
+ to follow, especially with the definition of 'struct repo_config_values'
+ to ensure all members are initialized. As new members will be added in
+ the future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
3: 0aa0e9fc17 = 3: 01cd487cd2 core: convert build-time USE_NSEC into runtime core.useNanosec
base-commit: 2c78326f810173a4f3aefd8021f1e07575412481
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply [flat|nested] 68+ messages in thread* [PATCH v5 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-29 13:38 ` [PATCH v5 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-29 13:38 ` D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-29 13:38 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Patrick Steinhardt
Makefile-based builds have had this knob for most of the project's life,
since a479a564dc (Documentation/Makefile: allow
man.base.url.for.relative.link to be set from Make, 2009-12-03).
Meson, however, hard-codes the equivalent of $prefix/$mandir, which is
not really where all the HTML docs are stored in most distro builds.
Plus, this value is missing a trailing slash, so links come out broken,
like this in git.1:
1. Git User’s Manual
/usr/share/manuser-manual.html
Of course we can do better:
1. Change the default to match Make: use file://$(htmldir)/ (with
trailing slash!) to form a local URL pointing at the HTML docs. This
is safe because all current uses of link:<relative> point at HTML
docs:
git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http
produces only a single result (Documentation/howto/howto-index.sh)
which can be ignored. Since nothing else [*] in the normal build sets
MAN_BASE_URL, this seems like the right default.
2. Provide a configurable knob, just like the Makefile, so distributions
that build with Meson (like Gentoo) can decide where to make the
links if they need to. Those that set htmldir probably won't need to
tweak this any further, though.
[*]: Well, Git's todo branch has a script dodoc.sh to build and archive
docs for kernel.org; these docs are pulled by Homebrew
installations, for example. It sets MAN_BASE_URL to "git_htmldocs",
so the equivalent note on macOS + Homebrew is
1. Git User’s Manual
git-htmldocs/user-manual.html
which is not functional either, but that's a problem for
downstream. In any case, users can recover the right path with
"git --html-path".
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
This patch is mostly because I noticed the link I added in a later patch
didn't come out right.
I did an internet search for "MAN_BASE_URL" and got no real hits, so I'm
not sure if any distros today actually use it, but that's not a proper
audit in that I didn't look at any distro _code_ besides Gentoo (which,
as noted, uses Meson).
Documentation/meson.build | 7 ++++++-
meson_options.txt | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..cfa9c67609 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -379,13 +379,18 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml',
)
+ man_base_url = 'file://' + htmldir + '/'
+ if get_option('man_base_url') != ''
+ man_base_url = get_option('man_base_url')
+ endif
+
doc_targets += custom_target(
command: [
xmlto,
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
- 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man.base.url.for.relative.links=' + man_base_url,
'man',
manpage_xml_target,
'-o',
diff --git a/meson_options.txt b/meson_options.txt
index dc88f130d7..d590c21648 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
+option('man_base_url', type: 'string', value: '',
+ description: 'The base URL to use for relative links in manuals')
# Testing.
option('benchmarks', type: 'feature', value: 'auto',
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v5 2/3] environment: align repo_config_values_init with struct declaration
2026-08-29 13:38 ` [PATCH v5 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-29 13:38 ` D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-29 13:38 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Tian Yuchen, Olamide Caleb Bello, Junio C Hamano
The order of assignments in repo_config_values_init is chaotic and hard
to follow, especially with the definition of 'struct repo_config_values'
to ensure all members are initialized. As new members will be added in
the future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
environment.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/environment.c b/environment.c
index 76ee65e62b..6676e6f5ae 100644
--- a/environment.c
+++ b/environment.c
@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg)
{
+ /* section "core" config values */
cfg->attributes_file = NULL;
cfg->excludes_file = NULL;
cfg->editor_program = NULL;
@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->autorebase = AUTOREBASE_NEVER;
cfg->object_creation_mode = OBJECT_CREATION_MODE;
cfg->apply_sparse_checkout = 0;
- cfg->protect_hfs = PROTECT_HFS_DEFAULT;
- cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
- cfg->ignore_case = 0;
- cfg->trust_executable_bit = 1;
- cfg->has_symlinks = platform_has_symlinks();
- cfg->branch_track = BRANCH_TRACK_REMOTE;
cfg->trust_ctime = 1;
cfg->check_stat = 1;
cfg->zlib_compression_level = Z_BEST_SPEED;
cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
cfg->core_sparse_checkout_cone = 0;
- cfg->sparse_expect_files_outside_of_patterns = 0;
cfg->warn_on_object_refname_ambiguity = 1;
+ cfg->protect_hfs = PROTECT_HFS_DEFAULT;
+ cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
+ cfg->ignore_case = 0;
+ cfg->trust_executable_bit = 1;
+ cfg->has_symlinks = platform_has_symlinks();
+
+ /* section "sparse" config values */
+ cfg->sparse_expect_files_outside_of_patterns = 0;
+
+ /* section "branch" config values */
+ cfg->branch_track = BRANCH_TRACK_REMOTE;
}
void repo_config_values_clear(struct repo_config_values *cfg)
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-29 13:38 ` [PATCH v5 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
2026-08-29 13:38 ` [PATCH v5 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-29 13:38 ` D. Ben Knoble
2026-08-30 21:15 ` Junio C Hamano
2026-08-31 9:27 ` Patrick Steinhardt
2 siblings, 2 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-29 13:38 UTC (permalink / raw)
To: git
Cc: D. Ben Knoble, Olamide Caleb Bello, Todd Zullinger, Tian Yuchen,
Patrick Steinhardt, Junio C Hamano
Racy Git problems persist today, manifesting themselves in the
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
but most builds we know about don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
These days, most platforms are likely to be safe for the USE_NSEC code.
Regardless, we want to give users the ability to benefit from it. This
requires exposing the compile-time gated code as a runtime option.
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
Due to the conversion from #ifdef to runtime check, using the flag
"--ignore-space-change" may be particularly helpful when viewing changes
from this patch.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
CI: <https://github.com/benknoble/git/actions/runs/32365602564>
Documentation/config/core.adoc | 7 +++++++
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 8 ++++++++
environment.h | 1 +
read-cache.c | 15 ++++++---------
statinfo.c | 14 +++++++-------
10 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 340329edc3..b793f62e42 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -118,6 +118,13 @@ core.trustctime::
crawlers and some backup systems).
See linkgit:git-update-index[1]. True by default.
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
+ was compiled to respect this option).
+ This is unsafe on some platforms;
+ see link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
See linkgit:git-update-index[1]. False by default.
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
index 59bea66c0f..499231585b 100644
--- a/Documentation/technical/racy-git.adoc
+++ b/Documentation/technical/racy-git.adoc
@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`
timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
-is not stable on network filesystems. With `USE_NSEC`
-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+is not stable on network filesystems. With 'core.useNanosec'
+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
2005-01-04). This patch is included in kernel 2.6.11 and newer, but
only fixes the issue for file systems with exactly 1 ns or 1 s
-resolution. Other file systems are still broken in current Linux
-kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
+resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)
+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT
+has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to
+work, too.
Racy Git
--------
diff --git a/Makefile b/Makefile
index fac3e8879c..b4ebcb9e83 100644
--- a/Makefile
+++ b/Makefile
@@ -197,18 +197,11 @@ include shared.mak
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.adoc for details.
-#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available. This automatically turns USE_NSEC off.
+# available.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
@@ -1935,9 +1928,6 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
-ifdef USE_NSEC
- BASIC_CFLAGS += -DUSE_NSEC
-endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 241abd4332..8e0c25655f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -130,7 +130,7 @@ static void xrmdir(const char *path)
static void avoid_racy(void)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
+ * not use if we could usleep(10) if core.useNanosec is defined. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..51ee03233b 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
} while (0)
#ifdef NO_NSEC
-#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
diff --git a/configure.ac b/configure.ac
index cfb50112bf..fc956776ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
diff --git a/environment.c b/environment.c
index 6676e6f5ae..c83cf44839 100644
--- a/environment.c
+++ b/environment.c
@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
return 0;
}
+#ifndef NO_NSEC
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
+#endif
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
}
@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
+ cfg->use_nanosec = 0;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index e7ec5b0437..a35534afe5 100644
--- a/environment.h
+++ b/environment.h
@@ -139,6 +139,7 @@ struct repo_config_values {
int ignore_case;
int trust_executable_bit;
int has_symlinks;
+ int use_nanosec;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
diff --git a/read-cache.c b/read-cache.c
index 6c449f393d..b32cfd0ef1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
-#else
- istate->timestamp.sec <= sd->sd_mtime.sec
-#endif
- );
+ /* nanosecond timestamped files can also be racy! */
+ (repo_config_values(istate->repo)->use_nanosec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec));
}
int is_racy_timestamp(const struct index_state *istate,
diff --git a/statinfo.c b/statinfo.c
index 5e00af127d..d9ddcf9382 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
-#ifdef USE_NSEC
- if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (cfg->trust_ctime && cfg->check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
if (cfg->check_stat) {
if (sd->sd_uid != (unsigned int) st->st_uid ||
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-29 13:38 ` [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-30 21:15 ` Junio C Hamano
2026-08-31 0:27 ` D. Ben Knoble
2026-08-31 9:27 ` Patrick Steinhardt
1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-08-30 21:15 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Olamide Caleb Bello, Todd Zullinger, Tian Yuchen,
Patrick Steinhardt
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> + /* nanosecond timestamped files can also be racy! */
> + (repo_config_values(istate->repo)->use_nanosec
> + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> + (istate->timestamp.sec == sd->sd_mtime.sec &&
> + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> + : istate->timestamp.sec <= sd->sd_mtime.sec));
> }
Currently this is probably fine, but the use of repo_config_values()
here means that the order in which we can transition/libify two
unrelated things are forced on us:
* We'd first need to make sure repo_config_values() can work on an
instance of repository that is not the_repository,
* And until the above happens, we cannot do a --recurse-submodule
option that loads the index in a submodule and operate on it in
the same process (e.g., "git diff --resurse-submodules"),
because immediately at this step, istate taken from a submodule
would have its .repo member pointing at something that is not
the_repository and we will hit a BUG().
And after writing all of the above, I realized that I am mostly
repeating what Patric already said in the upstream, e.g.,
https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/
Other than that, this looks good to me.
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-30 21:15 ` Junio C Hamano
@ 2026-08-31 0:27 ` D. Ben Knoble
2026-08-31 9:27 ` Patrick Steinhardt
0 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 0:27 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Olamide Caleb Bello, Todd Zullinger, Tian Yuchen,
Patrick Steinhardt
On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > + /* nanosecond timestamped files can also be racy! */
> > + (repo_config_values(istate->repo)->use_nanosec
> > + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> > + (istate->timestamp.sec == sd->sd_mtime.sec &&
> > + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > + : istate->timestamp.sec <= sd->sd_mtime.sec));
> > }
>
> Currently this is probably fine, but the use of repo_config_values()
> here means that the order in which we can transition/libify two
> unrelated things are forced on us:
>
> * We'd first need to make sure repo_config_values() can work on an
> instance of repository that is not the_repository,
>
> * And until the above happens, we cannot do a --recurse-submodule
> option that loads the index in a submodule and operate on it in
> the same process (e.g., "git diff --resurse-submodules"),
> because immediately at this step, istate taken from a submodule
> would have its .repo member pointing at something that is not
> the_repository and we will hit a BUG().
>
> And after writing all of the above, I realized that I am mostly
> repeating what Patric already said in the upstream, e.g.,
>
> https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/
Yep---just so I'm clear, we don't currently have such an option,
right? I mean, there is no --recurse-submodules for git-diff(1), and I
tweaked t4060 to run "git -c core.useNanosec=true diff
--submodule=diff" without any issue.
I would happily prove that at least none of our existing tests fail
with core.useNanosec=true, but I'm not really sure how to shove
configuration into every test invocation of git. Even if we could, I'm
not sure we necessarily want to add another CI job for that (though
that's a separate matter).
In particular, (among others) I have not received any concrete comments for
> Comments welcome: I haven't touched any tests; I saw a bunch of hits for
> "git grep racy t" but wasn't sure how to fit this particular change in,
> especially since it won't be equally valid on all systems? Advice
> welcome.
so if there's at least a way to exercise this path on all the tests on
my system (which should support it), that would probably be a good
thing.
> Other than that, this looks good to me.
Thank
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 0:27 ` D. Ben Knoble
@ 2026-08-31 9:27 ` Patrick Steinhardt
2026-08-31 13:00 ` D. Ben Knoble
[not found] ` <CALnO6CCNwXC1_PUCTWEU-HXBk+W+sBGqn7Sr8D=ZHW3Mxcu20g@mail.gmail.com>
0 siblings, 2 replies; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-31 9:27 UTC (permalink / raw)
To: D. Ben Knoble
Cc: Junio C Hamano, git, Olamide Caleb Bello, Todd Zullinger,
Tian Yuchen
On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:
> On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:
> >
> > "D. Ben Knoble" <ben.knoble@gmail.com> writes:
> >
> > > + /* nanosecond timestamped files can also be racy! */
> > > + (repo_config_values(istate->repo)->use_nanosec
> > > + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> > > + (istate->timestamp.sec == sd->sd_mtime.sec &&
> > > + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > > + : istate->timestamp.sec <= sd->sd_mtime.sec));
> > > }
> >
> > Currently this is probably fine, but the use of repo_config_values()
> > here means that the order in which we can transition/libify two
> > unrelated things are forced on us:
> >
> > * We'd first need to make sure repo_config_values() can work on an
> > instance of repository that is not the_repository,
> >
> > * And until the above happens, we cannot do a --recurse-submodule
> > option that loads the index in a submodule and operate on it in
> > the same process (e.g., "git diff --resurse-submodules"),
> > because immediately at this step, istate taken from a submodule
> > would have its .repo member pointing at something that is not
> > the_repository and we will hit a BUG().
> >
> > And after writing all of the above, I realized that I am mostly
> > repeating what Patric already said in the upstream, e.g.,
> >
> > https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/
>
> Yep---just so I'm clear, we don't currently have such an option,
> right? I mean, there is no --recurse-submodules for git-diff(1), and I
> tweaked t4060 to run "git -c core.useNanosec=true diff
> --submodule=diff" without any issue.
I do have a patch series coming up where we start to rely more on
sub-repositories when recursing. The motivation behind that series is
that it allows us to get rid of registering submodule object databases
with the main ODB. But I just double-checked, and your series luckily
doesn't break it.
> I would happily prove that at least none of our existing tests fail
> with core.useNanosec=true, but I'm not really sure how to shove
> configuration into every test invocation of git. Even if we could, I'm
> not sure we necessarily want to add another CI job for that (though
> that's a separate matter).
>
> In particular, (among others) I have not received any concrete comments for
>
> > Comments welcome: I haven't touched any tests; I saw a bunch of hits for
> > "git grep racy t" but wasn't sure how to fit this particular change in,
> > especially since it won't be equally valid on all systems? Advice
> > welcome.
>
> so if there's at least a way to exercise this path on all the tests on
> my system (which should support it), that would probably be a good
> thing.
Yeah, I simply don't have a good answer here. It's messy, and I'm not a
fan of the current direction of `repo_config_values()` because nobody
has yet stepped up to untangle it from `the_repository`. I gave it a
quick shot at one point in time, but the result was messy at best
because of how we populate it via `repo_config(git_default_config)`.
In any case, if we see that your changes interact badly with some edge
cases that we don't currently have on our radar then we can still
refactor the series and move the value into `struct repo_settings`
instead, as that structure works alright with different repositories.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 9:27 ` Patrick Steinhardt
@ 2026-08-31 13:00 ` D. Ben Knoble
[not found] ` <CALnO6CCNwXC1_PUCTWEU-HXBk+W+sBGqn7Sr8D=ZHW3Mxcu20g@mail.gmail.com>
1 sibling, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 13:00 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Junio C Hamano, git, Olamide Caleb Bello, Todd Zullinger,
Tian Yuchen
[Apologies for duplicates; Gmail switched out of plain-text mode
without permission. I've yet to finish setting up aerc…]
Hi Patrick,
On Mon, Aug 31, 2026 at 5:27 AM Patrick Steinhardt <ps@pks.im> wrote:
>
> On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:
> > On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:
> > >
> > > "D. Ben Knoble" <ben.knoble@gmail.com> writes:
> > >
> > > > + /* nanosecond timestamped files can also be racy! */
> > > > + (repo_config_values(istate->repo)->use_nanosec
> > > > + ? (istate->timestamp.sec < sd->sd_mtime.sec ||
> > > > + (istate->timestamp.sec == sd->sd_mtime.sec &&
> > > > + istate->timestamp.nsec <= sd->sd_mtime.nsec))
> > > > + : istate->timestamp.sec <= sd->sd_mtime.sec));
> > > > }
> > >
> > > Currently this is probably fine, but the use of repo_config_values()
> > > here means that the order in which we can transition/libify two
> > > unrelated things are forced on us:
> > >
> > > * We'd first need to make sure repo_config_values() can work on an
> > > instance of repository that is not the_repository,
> > >
> > > * And until the above happens, we cannot do a --recurse-submodule
> > > option that loads the index in a submodule and operate on it in
> > > the same process (e.g., "git diff --resurse-submodules"),
> > > because immediately at this step, istate taken from a submodule
> > > would have its .repo member pointing at something that is not
> > > the_repository and we will hit a BUG().
> > >
> > > And after writing all of the above, I realized that I am mostly
> > > repeating what Patric already said in the upstream, e.g.,
> > >
> > > https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/
> >
> > Yep---just so I'm clear, we don't currently have such an option,
> > right? I mean, there is no --recurse-submodules for git-diff(1), and I
> > tweaked t4060 to run "git -c core.useNanosec=true diff
> > --submodule=diff" without any issue.
>
> I do have a patch series coming up where we start to rely more on
> sub-repositories when recursing. The motivation behind that series is
> that it allows us to get rid of registering submodule object databases
> with the main ODB. But I just double-checked, and your series luckily
> doesn't break it.
Glad it worked out ;)
> > I would happily prove that at least none of our existing tests fail
> > with core.useNanosec=true, but I'm not really sure how to shove
> > configuration into every test invocation of git. Even if we could, I'm
> > not sure we necessarily want to add another CI job for that (though
> > that's a separate matter).
> >
> > In particular, (among others) I have not received any concrete comments for
> >
> > > Comments welcome: I haven't touched any tests; I saw a bunch of hits for
> > > "git grep racy t" but wasn't sure how to fit this particular change in,
> > > especially since it won't be equally valid on all systems? Advice
> > > welcome.
> >
> > so if there's at least a way to exercise this path on all the tests on
> > my system (which should support it), that would probably be a good
> > thing.
>
> Yeah, I simply don't have a good answer here. It's messy, and I'm not a
> fan of the current direction of `repo_config_values()` because nobody
> has yet stepped up to untangle it from `the_repository`. I gave it a
> quick shot at one point in time, but the result was messy at best
> because of how we populate it via `repo_config(git_default_config)`.
I took a quick look (being unfamiliar), and yeah, it does seem pretty
tangled. I suppose one way to go about it would be to have
repo_config() forward the repository argument through configset_iter
to the config_fn_t callback? I'm a bit surprised (leaving aside how
pervasive the_repository is otherwise) to see it doesn't already do
that :)
Is that the approach you took? Or, where else did you feel hung up
about the resulting code? Just wondering.
> In any case, if we see that your changes interact badly with some edge
> cases that we don't currently have on our radar then we can still
> refactor the series and move the value into `struct repo_settings`
> instead, as that structure works alright with different repositories.
>
> Thanks!
>
> Patrick
This sounds reasonable to me. If nothing else, this series might
become good motivation to untangle repo_config_values…
Sounds to me like we might be ready for 'next'?
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread[parent not found: <CALnO6CCNwXC1_PUCTWEU-HXBk+W+sBGqn7Sr8D=ZHW3Mxcu20g@mail.gmail.com>]
* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
[not found] ` <CALnO6CCNwXC1_PUCTWEU-HXBk+W+sBGqn7Sr8D=ZHW3Mxcu20g@mail.gmail.com>
@ 2026-08-31 14:47 ` Patrick Steinhardt
2026-09-01 0:35 ` Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-31 14:47 UTC (permalink / raw)
To: D. Ben Knoble
Cc: Junio C Hamano, git, Olamide Caleb Bello, Todd Zullinger,
Tian Yuchen
On Mon, Aug 31, 2026 at 08:57:49AM -0400, D. Ben Knoble wrote:
> On Mon, Aug 31, 2026 at 5:27 AM Patrick Steinhardt <ps@pks.im> wrote:
> > On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:
> > > On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:
[snip]
> > > I would happily prove that at least none of our existing tests fail
> > > with core.useNanosec=true, but I'm not really sure how to shove
> > > configuration into every test invocation of git. Even if we could, I'm
> > > not sure we necessarily want to add another CI job for that (though
> > > that's a separate matter).
> > >
> > > In particular, (among others) I have not received any concrete comments
> > for
> > >
> > > > Comments welcome: I haven't touched any tests; I saw a bunch of hits
> > for
> > > > "git grep racy t" but wasn't sure how to fit this particular change in,
> > > > especially since it won't be equally valid on all systems? Advice
> > > > welcome.
> > >
> > > so if there's at least a way to exercise this path on all the tests on
> > > my system (which should support it), that would probably be a good
> > > thing.
> >
> > Yeah, I simply don't have a good answer here. It's messy, and I'm not a
> > fan of the current direction of `repo_config_values()` because nobody
> > has yet stepped up to untangle it from `the_repository`. I gave it a
> > quick shot at one point in time, but the result was messy at best
> > because of how we populate it via `repo_config(git_default_config)`.
> >
>
> I took a quick look (being unfamiliar), and yeah, it does seem pretty
> tangled. I suppose one way to go about it would be to have repo_config()
> forward the repository argument through configset_iter to the config_fn_t
> callback? I'm a bit surprised (leaving aside how pervasive the_repository
> is otherwise) to see it doesn't already do that :)
>
> Is that the approach you took? Or, where else did you feel hung up about
> the resulting code? Just wondering.
Yeah, that's what I did. I don't quite remember what was awkward about
it though. It might've been that callers have to be aware whether a repo
is initialized, and whether it has all info to be able to read its own
configuration? Or I was trying to make it auto-lazy-load or something
like that, but because our config subsystem is so fragile that led to
lots of weird edge cases.
Sometimes I really wonder whether that whole caching layer is even worth
it. We already store the configuration as part of the configset, so
caching the parsed values probably does not buy us a lot. For some very
central aspects like the bareness of a repository or the location of the
worktree it probably even makes sense, but for everything else... I
dunno. By now I feel like it would make more sense there to find
localized solutions specific to subsystems instead of having that one
big global struct that has weird semantics.
> > In any case, if we see that your changes interact badly with some edge
> > cases that we don't currently have on our radar then we can still
> > refactor the series and move the value into `struct repo_settings`
> > instead, as that structure works alright with different repositories.
>
> This sounds reasonable to me. If nothing else, this series might become
> good motivation to untangle repo_config_values…
>
> Sounds to me like we might be ready for 'next'?
Works for me.
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 14:47 ` Patrick Steinhardt
@ 2026-09-01 0:35 ` Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: Ben Knoble @ 2026-09-01 0:35 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Junio C Hamano, git, Olamide Caleb Bello, Todd Zullinger,
Yuchen Tian
> Le 31 août 2026 à 18:06, Patrick Steinhardt <ps@pks.im> a écrit :
>
> On Mon, Aug 31, 2026 at 08:57:49AM -0400, D. Ben Knoble wrote:
>>> On Mon, Aug 31, 2026 at 5:27 AM Patrick Steinhardt <ps@pks.im> wrote:
>>> On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:
>>>> On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:
> [snip]
>>>> I would happily prove that at least none of our existing tests fail
>>>> with core.useNanosec=true, but I'm not really sure how to shove
>>>> configuration into every test invocation of git. Even if we could, I'm
>>>> not sure we necessarily want to add another CI job for that (though
>>>> that's a separate matter).
>>>>
>>>> In particular, (among others) I have not received any concrete comments
>>> for
>>>>
>>>>> Comments welcome: I haven't touched any tests; I saw a bunch of hits
>>> for
>>>>> "git grep racy t" but wasn't sure how to fit this particular change in,
>>>>> especially since it won't be equally valid on all systems? Advice
>>>>> welcome.
>>>>
>>>> so if there's at least a way to exercise this path on all the tests on
>>>> my system (which should support it), that would probably be a good
>>>> thing.
>>>
>>> Yeah, I simply don't have a good answer here. It's messy, and I'm not a
>>> fan of the current direction of `repo_config_values()` because nobody
>>> has yet stepped up to untangle it from `the_repository`. I gave it a
>>> quick shot at one point in time, but the result was messy at best
>>> because of how we populate it via `repo_config(git_default_config)`.
>>>
>>
>> I took a quick look (being unfamiliar), and yeah, it does seem pretty
>> tangled. I suppose one way to go about it would be to have repo_config()
>> forward the repository argument through configset_iter to the config_fn_t
>> callback? I'm a bit surprised (leaving aside how pervasive the_repository
>> is otherwise) to see it doesn't already do that :)
>>
>> Is that the approach you took? Or, where else did you feel hung up about
>> the resulting code? Just wondering.
>
> Yeah, that's what I did. I don't quite remember what was awkward about
> it though. It might've been that callers have to be aware whether a repo
> is initialized, and whether it has all info to be able to read its own
> configuration? Or I was trying to make it auto-lazy-load or something
> like that, but because our config subsystem is so fragile that led to
> lots of weird edge cases.
>
> Sometimes I really wonder whether that whole caching layer is even worth
> it. We already store the configuration as part of the configset, so
> caching the parsed values probably does not buy us a lot. For some very
> central aspects like the bareness of a repository or the location of the
> worktree it probably even makes sense, but for everything else... I
> dunno. By now I feel like it would make more sense there to find
> localized solutions specific to subsystems instead of having that one
> big global struct that has weird semantics.
Interesting, yeah. I can’t say I’m too motivated to look into this further, personally, but the config system seems fairly complex…
Maybe I’ll take a tour of it one day though, depending on the next itch I scratch ;)
>>> In any case, if we see that your changes interact badly with some edge
>>> cases that we don't currently have on our radar then we can still
>>> refactor the series and move the value into `struct repo_settings`
>>> instead, as that structure works alright with different repositories.
>>
>> This sounds reasonable to me. If nothing else, this series might become
>> good motivation to untangle repo_config_values…
>>
>> Sounds to me like we might be ready for 'next'?
>
> Works for me.
>
> Patrick
Thanks!
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-29 13:38 ` [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2026-08-30 21:15 ` Junio C Hamano
@ 2026-08-31 9:27 ` Patrick Steinhardt
2026-08-31 15:46 ` Ben Knoble
1 sibling, 1 reply; 68+ messages in thread
From: Patrick Steinhardt @ 2026-08-31 9:27 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Olamide Caleb Bello, Todd Zullinger, Tian Yuchen,
Junio C Hamano
On Sat, Aug 29, 2026 at 09:38:20AM -0400, D. Ben Knoble wrote:
> diff --git a/builtin/update-index.c b/builtin/update-index.c
> index 241abd4332..8e0c25655f 100644
> --- a/builtin/update-index.c
> +++ b/builtin/update-index.c
> @@ -130,7 +130,7 @@ static void xrmdir(const char *path)
> static void avoid_racy(void)
> {
> /*
> - * not use if we could usleep(10) if USE_NSEC is defined. The
> + * not use if we could usleep(10) if core.useNanosec is defined. The
Micronit: s/defined/enabled/
Otherwise I'm happy with this patch. It looks a lot better now that we
use less preprocessor directives. Thanks!
Patrick
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 9:27 ` Patrick Steinhardt
@ 2026-08-31 15:46 ` Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: Ben Knoble @ 2026-08-31 15:46 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: git, Olamide Caleb Bello, Todd Zullinger, Yuchen Tian,
Junio C Hamano
> Le 31 août 2026 à 11:31, Patrick Steinhardt <ps@pks.im> a écrit :
>
> On Sat, Aug 29, 2026 at 09:38:20AM -0400, D. Ben Knoble wrote:
>> diff --git a/builtin/update-index.c b/builtin/update-index.c
>> index 241abd4332..8e0c25655f 100644
>> --- a/builtin/update-index.c
>> +++ b/builtin/update-index.c
>> @@ -130,7 +130,7 @@ static void xrmdir(const char *path)
>> static void avoid_racy(void)
>> {
>> /*
>> - * not use if we could usleep(10) if USE_NSEC is defined. The
>> + * not use if we could usleep(10) if core.useNanosec is defined. The
>
> Micronit: s/defined/enabled/
>
> Otherwise I'm happy with this patch. It looks a lot better now that we
> use less preprocessor directives. Thanks!
>
> Patrick
Thanks, queued locally. Will send out as v6 this evening (~5–6h from now) unless I hear differently from anyone. (That comment is hard to read to begin with!)
^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v6 0/3] Convert USE_NSEC to runtime config
2026-08-20 13:18 ` [PATCH v4 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (3 preceding siblings ...)
2026-08-29 13:38 ` [PATCH v5 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-31 20:01 ` D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
` (3 more replies)
4 siblings, 4 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 20:01 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble
Topic name: dk/use-nsec-runtime (applied)
Topic summary: Expose USE_NSEC as a runtime configuration, since
build-time is too early for distributing Git [1]. As a result, common
index-related options, like git-diff, are less likely to hit "racy git"
problems on supported filesystems.
[1]: https://git.github.io/rev_news/2026/07/31/edition-137/
Built on master (2c78326f81 (The 11th batch, 2026-08-05)).
Changes in v5:
- improve message flow in patch 2
Changes in v4:
- fix message typo
- change #ifdef strategy: only ignore the config variable.
Otherwise, use the use_nanosec member unconditionally. Also clarify
that config might be ignore depending on build options in the docs.
- mention potential platform unsafety directly in config doc in
addition to the link to Racy Git
Changes in v3:
- #ifdef out use_nanosec when NO_NSEC is requested
As I have heard no comments about the "Todo" lines below, which perhaps
could more clearly be marked "RFC"/"RFH", I've added this line to call
them out ;) and renamed them "Comments welcome"
Changes in v2:
- move Best-viewed-with trailer into message body as descriptive
text.
- read core.useNanosec through struct repo instead of parsing
config strings. The test suite passes locally this way, though that
skipped 151 tests.
- CI run: https://github.com/benknoble/git/actions/runs/31701945211
Original cover letter:
Hi all, this series follows up on the previous racy Git/USE_NSEC
conversations.
- The first patch is a mostly-unrelated documentation fix for Meson, but
it came out of something I spotted while reviewing the outputs of the
final (main) patch.
- The second patch is a preliminary no-op reorganization of
repo_config_values_init.
- The third patch is the meat, converting USE_NSEC into core.useNanosec.
There is a small textual and semantic conflict with
'ty/repo-config-cleanups' in 'seen', since that branch removes the
comments in 'struct repo_config_values' which this series adds to. (The
semantic conflict is that, if we drop those comments, we should probably
not add them to repo_config_values_init like I do in patch 2.)
Comments welcome: I haven't touched any tests; I saw a bunch of hits for
"git grep racy t" but wasn't sure how to fit this particular change in,
especially since it won't be equally valid on all systems? Advice
welcome.
Comments welcome: I wonder if "useNanosec" paints us into too much of a
corner; that is (slightly more abstractly), we are using *extended
precision* in the index. Maybe the name and documentation should reflect
that, so we aren't too committed to "nanoseconds"?
- Some platforms could offer extended precision that is not as
precise as nanoseconds
- Some could offer precision _beyond_ nanoseconds
idk.
v1: <cover.1786103607.git.ben.knoble@gmail.com>
v2: <cover.1786710807.git.ben.knoble@gmail.com>
v3: <cover.1787065125.git.ben.knoble@gmail.com>
v4: <cover.1787231825.git.ben.knoble@gmail.com>
v5: <cover.1788010335.git.ben.knoble@gmail.com>
[1/3] meson: expose knob for xmlto relative links in manuals
[2/3] environment: align repo_config_values_init with struct declaration
[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
Documentation/config/core.adoc | 7 +++++++
Documentation/meson.build | 7 ++++++-
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 27 ++++++++++++++++++++-------
environment.h | 1 +
meson_options.txt | 2 ++
read-cache.c | 15 ++++++---------
statinfo.c | 14 +++++++-------
12 files changed, 57 insertions(+), 48 deletions(-)
Diff-intervalle contre v5 :
1: d612de6c2d = 1: d612de6c2d meson: expose knob for xmlto relative links in manuals
2: 12974e07d0 = 2: 12974e07d0 environment: align repo_config_values_init with struct declaration
3: 01cd487cd2 ! 3: 0a611f6140 core: convert build-time USE_NSEC into runtime core.useNanosec
@@ builtin/update-index.c: static void xrmdir(const char *path)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
-+ * not use if we could usleep(10) if core.useNanosec is defined. The
++ * not use if we could usleep(10) if core.useNanosec is enabled. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
base-commit: 2c78326f810173a4f3aefd8021f1e07575412481
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply [flat|nested] 68+ messages in thread* [PATCH v6 1/3] meson: expose knob for xmlto relative links in manuals
2026-08-31 20:01 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
@ 2026-08-31 20:01 ` D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
` (2 subsequent siblings)
3 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 20:01 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Patrick Steinhardt
Makefile-based builds have had this knob for most of the project's life,
since a479a564dc (Documentation/Makefile: allow
man.base.url.for.relative.link to be set from Make, 2009-12-03).
Meson, however, hard-codes the equivalent of $prefix/$mandir, which is
not really where all the HTML docs are stored in most distro builds.
Plus, this value is missing a trailing slash, so links come out broken,
like this in git.1:
1. Git User’s Manual
/usr/share/manuser-manual.html
Of course we can do better:
1. Change the default to match Make: use file://$(htmldir)/ (with
trailing slash!) to form a local URL pointing at the HTML docs. This
is safe because all current uses of link:<relative> point at HTML
docs:
git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http
produces only a single result (Documentation/howto/howto-index.sh)
which can be ignored. Since nothing else [*] in the normal build sets
MAN_BASE_URL, this seems like the right default.
2. Provide a configurable knob, just like the Makefile, so distributions
that build with Meson (like Gentoo) can decide where to make the
links if they need to. Those that set htmldir probably won't need to
tweak this any further, though.
[*]: Well, Git's todo branch has a script dodoc.sh to build and archive
docs for kernel.org; these docs are pulled by Homebrew
installations, for example. It sets MAN_BASE_URL to "git_htmldocs",
so the equivalent note on macOS + Homebrew is
1. Git User’s Manual
git-htmldocs/user-manual.html
which is not functional either, but that's a problem for
downstream. In any case, users can recover the right path with
"git --html-path".
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
This patch is mostly because I noticed the link I added in a later patch
didn't come out right.
I did an internet search for "MAN_BASE_URL" and got no real hits, so I'm
not sure if any distros today actually use it, but that's not a proper
audit in that I didn't look at any distro _code_ besides Gentoo (which,
as noted, uses Meson).
Documentation/meson.build | 7 ++++++-
meson_options.txt | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Documentation/meson.build b/Documentation/meson.build
index f4854f802d..cfa9c67609 100644
--- a/Documentation/meson.build
+++ b/Documentation/meson.build
@@ -379,13 +379,18 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml',
)
+ man_base_url = 'file://' + htmldir + '/'
+ if get_option('man_base_url') != ''
+ man_base_url = get_option('man_base_url')
+ endif
+
doc_targets += custom_target(
command: [
xmlto,
'-m', '@INPUT0@',
'-m', '@INPUT1@',
'--stringparam',
- 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+ 'man.base.url.for.relative.links=' + man_base_url,
'man',
manpage_xml_target,
'-o',
diff --git a/meson_options.txt b/meson_options.txt
index dc88f130d7..d590c21648 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'
description: 'Default format used when executing git-help(1).')
option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',
description: 'Which backend to use to generate documentation.')
+option('man_base_url', type: 'string', value: '',
+ description: 'The base URL to use for relative links in manuals')
# Testing.
option('benchmarks', type: 'feature', value: 'auto',
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v6 2/3] environment: align repo_config_values_init with struct declaration
2026-08-31 20:01 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
@ 2026-08-31 20:01 ` D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2026-08-31 20:06 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
3 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 20:01 UTC (permalink / raw)
To: git; +Cc: D. Ben Knoble, Junio C Hamano, Tian Yuchen, Olamide Caleb Bello
The order of assignments in repo_config_values_init is chaotic and hard
to follow, especially with the definition of 'struct repo_config_values'
to ensure all members are initialized. As new members will be added in
the future, make it easier to validate changes by aligning the two.
Refactor assignment order with no behavioral changes.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
environment.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/environment.c b/environment.c
index 76ee65e62b..6676e6f5ae 100644
--- a/environment.c
+++ b/environment.c
@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,
void repo_config_values_init(struct repo_config_values *cfg)
{
+ /* section "core" config values */
cfg->attributes_file = NULL;
cfg->excludes_file = NULL;
cfg->editor_program = NULL;
@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->autorebase = AUTOREBASE_NEVER;
cfg->object_creation_mode = OBJECT_CREATION_MODE;
cfg->apply_sparse_checkout = 0;
- cfg->protect_hfs = PROTECT_HFS_DEFAULT;
- cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
- cfg->ignore_case = 0;
- cfg->trust_executable_bit = 1;
- cfg->has_symlinks = platform_has_symlinks();
- cfg->branch_track = BRANCH_TRACK_REMOTE;
cfg->trust_ctime = 1;
cfg->check_stat = 1;
cfg->zlib_compression_level = Z_BEST_SPEED;
cfg->pack_compression_level = Z_DEFAULT_COMPRESSION;
cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
cfg->core_sparse_checkout_cone = 0;
- cfg->sparse_expect_files_outside_of_patterns = 0;
cfg->warn_on_object_refname_ambiguity = 1;
+ cfg->protect_hfs = PROTECT_HFS_DEFAULT;
+ cfg->protect_ntfs = PROTECT_NTFS_DEFAULT;
+ cfg->ignore_case = 0;
+ cfg->trust_executable_bit = 1;
+ cfg->has_symlinks = platform_has_symlinks();
+
+ /* section "sparse" config values */
+ cfg->sparse_expect_files_outside_of_patterns = 0;
+
+ /* section "branch" config values */
+ cfg->branch_track = BRANCH_TRACK_REMOTE;
}
void repo_config_values_clear(struct repo_config_values *cfg)
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 20:01 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 1/3] meson: expose knob for xmlto relative links in manuals D. Ben Knoble
2026-08-31 20:01 ` [PATCH v6 2/3] environment: align repo_config_values_init with struct declaration D. Ben Knoble
@ 2026-08-31 20:01 ` D. Ben Knoble
2026-09-01 4:35 ` Junio C Hamano
2026-09-01 4:54 ` Jeff King
2026-08-31 20:06 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
3 siblings, 2 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 20:01 UTC (permalink / raw)
To: git
Cc: D. Ben Knoble, Junio C Hamano, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Tian Yuchen
Racy Git problems persist today, manifesting themselves in the
performance of commands like "git diff" in new worktrees [1]. We have
long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
precision when available, which mitigates most if not all racy issues,
but most builds we know about don't use it. In part, that's because
someone distributing Git can't safely enable it at compile-time if they
don't know exactly what platforms their distribution will be used on.
[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com
These days, most platforms are likely to be safe for the USE_NSEC code.
Regardless, we want to give users the ability to benefit from it. This
requires exposing the compile-time gated code as a runtime option.
In addition, update the Racy Git documentation and other mentions of
USE_NSEC in the code.
Due to the conversion from #ifdef to runtime check, using the flag
"--ignore-space-change" may be particularly helpful when viewing changes
from this patch.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
---
Notes (benknoble/commits):
Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>
CI: <https://github.com/benknoble/git/actions/runs/32365602564>
Documentation/config/core.adoc | 7 +++++++
Documentation/technical/racy-git.adoc | 11 ++++++-----
Makefile | 12 +-----------
builtin/update-index.c | 2 +-
compat/posix.h | 1 -
configure.ac | 6 ------
environment.c | 8 ++++++++
environment.h | 1 +
read-cache.c | 15 ++++++---------
statinfo.c | 14 +++++++-------
10 files changed, 37 insertions(+), 40 deletions(-)
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
index 340329edc3..b793f62e42 100644
--- a/Documentation/config/core.adoc
+++ b/Documentation/config/core.adoc
@@ -118,6 +118,13 @@ core.trustctime::
crawlers and some backup systems).
See linkgit:git-update-index[1]. True by default.
+core.useNanosec::
+ If true, use nanosecond precision for ctime and mtime
+ comparisions between the index and the working tree (if Git
+ was compiled to respect this option).
+ This is unsafe on some platforms;
+ see link:technical/racy-git.html[Racy Git]. False by default.
+
core.splitIndex::
If true, the split-index feature of the index will be used.
See linkgit:git-update-index[1]. False by default.
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
index 59bea66c0f..499231585b 100644
--- a/Documentation/technical/racy-git.adoc
+++ b/Documentation/technical/racy-git.adoc
@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`
timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
With a `USE_STDEV` compile-time option, `st_dev` is also
compared, but this is not enabled by default because this member
-is not stable on network filesystems. With `USE_NSEC`
-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+is not stable on network filesystems. With 'core.useNanosec'
+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
members are also compared. On Linux, this is not enabled by default
because in-core timestamps can have finer granularity than
on-disk timestamps, resulting in meaningless changes when an
@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
([PATCH] Sync in core time granularity with filesystems,
2005-01-04). This patch is included in kernel 2.6.11 and newer, but
only fixes the issue for file systems with exactly 1 ns or 1 s
-resolution. Other file systems are still broken in current Linux
-kernels (e.g. CEPH, CIFS, NTFS, UDF), see
-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/
+resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)
+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT
+has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to
+work, too.
Racy Git
--------
diff --git a/Makefile b/Makefile
index fac3e8879c..b4ebcb9e83 100644
--- a/Makefile
+++ b/Makefile
@@ -197,18 +197,11 @@ include shared.mak
# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
-# Documentation/technical/racy-git.adoc for details.
-#
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available. This automatically turns USE_NSEC off.
+# available.
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
@@ -1935,9 +1928,6 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif
-ifdef USE_NSEC
- BASIC_CFLAGS += -DUSE_NSEC
-endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 241abd4332..a10c07b636 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -130,7 +130,7 @@ static void xrmdir(const char *path)
static void avoid_racy(void)
{
/*
- * not use if we could usleep(10) if USE_NSEC is defined. The
+ * not use if we could usleep(10) if core.useNanosec is enabled. The
* field nsec could be there, but the OS could choose to
* ignore it?
*/
diff --git a/compat/posix.h b/compat/posix.h
index e2e794cad7..51ee03233b 100644
--- a/compat/posix.h
+++ b/compat/posix.h
@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,
} while (0)
#ifdef NO_NSEC
-#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
diff --git a/configure.ac b/configure.ac
index cfb50112bf..fc956776ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
-# Define USE_NSEC below if you want git to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
diff --git a/environment.c b/environment.c
index 6676e6f5ae..c83cf44839 100644
--- a/environment.c
+++ b/environment.c
@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
return 0;
}
+#ifndef NO_NSEC
+ if (!strcmp(var, "core.usenanosec")) {
+ cfg->use_nanosec = git_config_bool(var, value);
+ return 0;
+ }
+#endif
+
/* Add other config variables here and to Documentation/config.adoc. */
return platform_core_config(var, value, ctx, cb);
}
@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->ignore_case = 0;
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
+ cfg->use_nanosec = 0;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index e7ec5b0437..a35534afe5 100644
--- a/environment.h
+++ b/environment.h
@@ -139,6 +139,7 @@ struct repo_config_values {
int ignore_case;
int trust_executable_bit;
int has_symlinks;
+ int use_nanosec;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
diff --git a/read-cache.c b/read-cache.c
index 6c449f393d..b32cfd0ef1 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,
const struct stat_data *sd)
{
return (istate->timestamp.sec &&
-#ifdef USE_NSEC
- /* nanosecond timestamped files can also be racy! */
- (istate->timestamp.sec < sd->sd_mtime.sec ||
- (istate->timestamp.sec == sd->sd_mtime.sec &&
- istate->timestamp.nsec <= sd->sd_mtime.nsec))
-#else
- istate->timestamp.sec <= sd->sd_mtime.sec
-#endif
- );
+ /* nanosecond timestamped files can also be racy! */
+ (repo_config_values(istate->repo)->use_nanosec
+ ? (istate->timestamp.sec < sd->sd_mtime.sec ||
+ (istate->timestamp.sec == sd->sd_mtime.sec &&
+ istate->timestamp.nsec <= sd->sd_mtime.nsec))
+ : istate->timestamp.sec <= sd->sd_mtime.sec));
}
int is_racy_timestamp(const struct index_state *istate,
diff --git a/statinfo.c b/statinfo.c
index 5e00af127d..d9ddcf9382 100644
--- a/statinfo.c
+++ b/statinfo.c
@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
-#ifdef USE_NSEC
- if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
- changed |= MTIME_CHANGED;
- if (cfg->trust_ctime && cfg->check_stat &&
- sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
- changed |= CTIME_CHANGED;
-#endif
+ if (cfg->use_nanosec) {
+ if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (cfg->trust_ctime && cfg->check_stat &&
+ sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+ }
if (cfg->check_stat) {
if (sd->sd_uid != (unsigned int) st->st_uid ||
--
2.55.0.860.g4b6b3295ed.dirty
^ permalink raw reply related [flat|nested] 68+ messages in thread* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 20:01 ` [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-09-01 4:35 ` Junio C Hamano
2026-09-01 12:38 ` D. Ben Knoble
2026-09-01 4:54 ` Jeff King
1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-09-01 4:35 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Patrick Steinhardt, Todd Zullinger, Olamide Caleb Bello,
Tian Yuchen
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> +core.useNanosec::
> + If true, use nanosecond precision for ctime and mtime
> + comparisions between the index and the working tree (if Git
comparisions?
> + was compiled to respect this option).
> + This is unsafe on some platforms;
> + see link:technical/racy-git.html[Racy Git]. False by default.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-01 4:35 ` Junio C Hamano
@ 2026-09-01 12:38 ` D. Ben Knoble
2026-09-01 17:32 ` Junio C Hamano
0 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-09-01 12:38 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Patrick Steinhardt, Todd Zullinger, Olamide Caleb Bello,
Tian Yuchen
On Tue, Sep 1, 2026 at 12:35 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
> > +core.useNanosec::
> > + If true, use nanosecond precision for ctime and mtime
> > + comparisions between the index and the working tree (if Git
>
> comparisions?
>
> > + was compiled to respect this option).
> > + This is unsafe on some platforms;
> > + see link:technical/racy-git.html[Racy Git]. False by default.
Ouch, good eyes. Obviously should be "comparisons"---I've amended
locally but will hold onto the new version for a bit.
As this topic is not in next yet, I presume that sending a new version
with the typofix is the correct thing to do. I'll wait a while today
to see if any other comments trickle in.
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-01 12:38 ` D. Ben Knoble
@ 2026-09-01 17:32 ` Junio C Hamano
0 siblings, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2026-09-01 17:32 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Patrick Steinhardt, Todd Zullinger, Olamide Caleb Bello,
Tian Yuchen
"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> On Tue, Sep 1, 2026 at 12:35 AM Junio C Hamano <gitster@pobox.com> wrote:
>>
>> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>>
>> > +core.useNanosec::
>> > + If true, use nanosecond precision for ctime and mtime
>> > + comparisions between the index and the working tree (if Git
>>
>> comparisions?
>>
>> > + was compiled to respect this option).
>> > + This is unsafe on some platforms;
>> > + see link:technical/racy-git.html[Racy Git]. False by default.
>
> Ouch, good eyes. Obviously should be "comparisons"---I've amended
> locally but will hold onto the new version for a bit.
>
> As this topic is not in next yet, I presume that sending a new version
> with the typofix is the correct thing to do. I'll wait a while today
> to see if any other comments trickle in.
Yeah, and in the meantime I'll locallly amend what I have. If we do
not hear any other issues in a few days perhaps we can do without
the final reroll that way.
Thanks.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-08-31 20:01 ` [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
2026-09-01 4:35 ` Junio C Hamano
@ 2026-09-01 4:54 ` Jeff King
2026-09-01 12:36 ` D. Ben Knoble
1 sibling, 1 reply; 68+ messages in thread
From: Jeff King @ 2026-09-01 4:54 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Junio C Hamano, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Tian Yuchen
On Mon, Aug 31, 2026 at 04:01:37PM -0400, D. Ben Knoble wrote:
> diff --git a/environment.c b/environment.c
> index 6676e6f5ae..c83cf44839 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> return 0;
> }
>
> +#ifndef NO_NSEC
> + if (!strcmp(var, "core.usenanosec")) {
> + cfg->use_nanosec = git_config_bool(var, value);
> + return 0;
> + }
> +#endif
This hunk made me wonder if we even need to do any build-time magic here
at all. If your platform doesn't support nanosecond stat entries, then
you're probably not going to ask for core.usenanosec in the first place.
But if you do, I think the code still works; we fake the entries as "0",
so they'd always yield a racy tie, just as if core.usenanosec was
disabled.
I guess you might be able to get into a funny state, though, if you
build two versions of Git, one with NO_NSEC and one without, on a system
that actually does support nanosecond timestamps. Because IIRC even if
we aren't _using_ the values, we still store them in the index. So an
index generated with the regular build would store the actual nanosec
stamps, which would then get a false comparison using the NO_NSEC
version.
That seems quite unlikely to happen in practice, and there is a certain
amount of "if it hurts, don't do that". But it's not like by dropping
this #ifndef we could get rid of NO_NSEC. So it would not simplify the
code overall, nor the number of build knobs that we expose to the user.
So it probably is reasonable to keep it.
I haven't been following the topic closely, but from my cursory read
everything else looked as I'd expect it to.
-Peff
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-01 4:54 ` Jeff King
@ 2026-09-01 12:36 ` D. Ben Knoble
2026-09-02 7:26 ` Jeff King
0 siblings, 1 reply; 68+ messages in thread
From: D. Ben Knoble @ 2026-09-01 12:36 UTC (permalink / raw)
To: Jeff King
Cc: git, Junio C Hamano, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Tian Yuchen
On Tue, Sep 1, 2026 at 12:54 AM Jeff King <peff@peff.net> wrote:
>
> On Mon, Aug 31, 2026 at 04:01:37PM -0400, D. Ben Knoble wrote:
>
> > diff --git a/environment.c b/environment.c
> > index 6676e6f5ae..c83cf44839 100644
> > --- a/environment.c
> > +++ b/environment.c
> > @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
> > return 0;
> > }
> >
> > +#ifndef NO_NSEC
> > + if (!strcmp(var, "core.usenanosec")) {
> > + cfg->use_nanosec = git_config_bool(var, value);
> > + return 0;
> > + }
> > +#endif
>
> This hunk made me wonder if we even need to do any build-time magic here
> at all. If your platform doesn't support nanosecond stat entries, then
> you're probably not going to ask for core.usenanosec in the first place.
> But if you do, I think the code still works; we fake the entries as "0",
> so they'd always yield a racy tie, just as if core.usenanosec was
> disabled.
At first I thought you meant we fake the cfg->use_nanosec as 0; it
took me a moment to realize you mean that we fake the index entries as
0ns. (That is what you mean, right?)
In that case, yes, I suppose it would work. Might be confusing in a
debugger to see use_nanosec set and checked, though?
> I guess you might be able to get into a funny state, though, if you
> build two versions of Git, one with NO_NSEC and one without, on a system
> that actually does support nanosecond timestamps. Because IIRC even if
> we aren't _using_ the values, we still store them in the index. So an
> index generated with the regular build would store the actual nanosec
> stamps, which would then get a false comparison using the NO_NSEC
> version.
>
> That seems quite unlikely to happen in practice, and there is a certain
> amount of "if it hurts, don't do that".
Hm, yeah. I haven't thought too hard either about the interactions
where you toggle core.usenanosec on and off, but giving it an initial
think they seem fine. Unlike this hypothetical case, when it's off we
don't look at the ns fields, so I don't think we end up with any false
negatives.
And in this hypothetical, by restricting the option parsing we avoid
reading the ns values on unsupported platforms, I think?
The build-time conditional _does_ mean that if your distro (e.g.)
provides a NO_NSEC build, you can't access the core.usenanosec feature
without compiling yourself, even if your platform supports it. But I
haven't thought too hard either about what it looks like to get rid of
NO_NSEC entirely, and I'm not totally sure if that's a good idea.
> But it's not like by dropping
> this #ifndef we could get rid of NO_NSEC. So it would not simplify the
> code overall, nor the number of build knobs that we expose to the user.
> So it probably is reasonable to keep it.
>
> I haven't been following the topic closely, but from my cursory read
> everything else looked as I'd expect it to.
>
> -Peff
Sounds good, thanks!
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-01 12:36 ` D. Ben Knoble
@ 2026-09-02 7:26 ` Jeff King
2026-09-02 11:45 ` Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Jeff King @ 2026-09-02 7:26 UTC (permalink / raw)
To: D. Ben Knoble
Cc: git, Junio C Hamano, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Tian Yuchen
On Tue, Sep 01, 2026 at 08:36:22AM -0400, D. Ben Knoble wrote:
> > This hunk made me wonder if we even need to do any build-time magic here
> > at all. If your platform doesn't support nanosecond stat entries, then
> > you're probably not going to ask for core.usenanosec in the first place.
> > But if you do, I think the code still works; we fake the entries as "0",
> > so they'd always yield a racy tie, just as if core.usenanosec was
> > disabled.
>
> At first I thought you meant we fake the cfg->use_nanosec as 0; it
> took me a moment to realize you mean that we fake the index entries as
> 0ns. (That is what you mean, right?)
Yeah, sorry to be unclear. I meant that we still have this code:
#ifdef NO_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
So we are free to pretend that stat nsecs exist and compare them.
> In that case, yes, I suppose it would work. Might be confusing in a
> debugger to see use_nanosec set and checked, though?
Maybe. Looking at the list of NO_NSEC flags in config.mak.uname, I
suspect it's a pretty small population in the first place.
> Hm, yeah. I haven't thought too hard either about the interactions
> where you toggle core.usenanosec on and off, but giving it an initial
> think they seem fine. Unlike this hypothetical case, when it's off we
> don't look at the ns fields, so I don't think we end up with any false
> negatives.
>
> And in this hypothetical, by restricting the option parsing we avoid
> reading the ns values on unsupported platforms, I think?
I'd have to double check, but I thought that even without USE_NSEC (and
thus even with your new core.usenanosec off) we still read and store the
nanosecond values in the index, as long as the platform supports it (and
if not, then we use those "0" fallback values).
So they are always there in the index. I guess the same odd sequence
applies even today. If you:
1. Build with NO_NSEC and get "fake" 0 values in your index.
2. Re-build without NO_NSEC, and also enable USE_NSEC. Now we get
_real_ values when we stat(), and compare them to the fake values
in the index.
Now the index values appear up to 1-second older than they actually are.
Which could maybe yield a racy miss of an update? Probably not for
stat-freshness (where we want an exact match), but maybe for some index
vs entry racy-git comparison. I didn't think that hard about it, because
at some point this sequence is just kind of insane.
> The build-time conditional _does_ mean that if your distro (e.g.)
> provides a NO_NSEC build, you can't access the core.usenanosec feature
> without compiling yourself, even if your platform supports it. But I
> haven't thought too hard either about what it looks like to get rid of
> NO_NSEC entirely, and I'm not totally sure if that's a good idea.
You couldn't access it even if core.usenanosec is supported in the
build, because your fake nsec values would all be "0" and it's
effectively a noop. ;)
My suggestion wasn't really about supporting more cases, but just about
making the code simpler by having one less #ifdef. But like I said
earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably
not worth worrying about the one #ifdef either way.
-Peff
^ permalink raw reply [flat|nested] 68+ messages in thread* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-02 7:26 ` Jeff King
@ 2026-09-02 11:45 ` Ben Knoble
2026-09-02 21:05 ` Junio C Hamano
0 siblings, 1 reply; 68+ messages in thread
From: Ben Knoble @ 2026-09-02 11:45 UTC (permalink / raw)
To: Jeff King
Cc: git, Junio C Hamano, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Yuchen Tian
> Le 2 sept. 2026 à 03:26, Jeff King <peff@peff.net> a écrit :
>
> On Tue, Sep 01, 2026 at 08:36:22AM -0400, D. Ben Knoble wrote:
>
>>> This hunk made me wonder if we even need to do any build-time magic here
>>> at all. If your platform doesn't support nanosecond stat entries, then
>>> you're probably not going to ask for core.usenanosec in the first place.
>>> But if you do, I think the code still works; we fake the entries as "0",
>>> so they'd always yield a racy tie, just as if core.usenanosec was
>>> disabled.
>>
>> At first I thought you meant we fake the cfg->use_nanosec as 0; it
>> took me a moment to realize you mean that we fake the index entries as
>> 0ns. (That is what you mean, right?)
>
> Yeah, sorry to be unclear. I meant that we still have this code:
>
> #ifdef NO_NSEC
> #define ST_CTIME_NSEC(st) 0
> #define ST_MTIME_NSEC(st) 0
>
> So we are free to pretend that stat nsecs exist and compare them.
>
>> In that case, yes, I suppose it would work. Might be confusing in a
>> debugger to see use_nanosec set and checked, though?
>
> Maybe. Looking at the list of NO_NSEC flags in config.mak.uname, I
> suspect it's a pretty small population in the first place.
>
>> Hm, yeah. I haven't thought too hard either about the interactions
>> where you toggle core.usenanosec on and off, but giving it an initial
>> think they seem fine. Unlike this hypothetical case, when it's off we
>> don't look at the ns fields, so I don't think we end up with any false
>> negatives.
>>
>> And in this hypothetical, by restricting the option parsing we avoid
>> reading the ns values on unsupported platforms, I think?
>
> I'd have to double check, but I thought that even without USE_NSEC (and
> thus even with your new core.usenanosec off) we still read and store the
> nanosecond values in the index, as long as the platform supports it (and
> if not, then we use those "0" fallback values).
>
> So they are always there in the index. I guess the same odd sequence
> applies even today. If you:
>
> 1. Build with NO_NSEC and get "fake" 0 values in your index.
>
> 2. Re-build without NO_NSEC, and also enable USE_NSEC. Now we get
> _real_ values when we stat(), and compare them to the fake values
> in the index.
>
> Now the index values appear up to 1-second older than they actually are.
> Which could maybe yield a racy miss of an update? Probably not for
> stat-freshness (where we want an exact match), but maybe for some index
> vs entry racy-git comparison. I didn't think that hard about it, because
> at some point this sequence is just kind of insane.
>
>> The build-time conditional _does_ mean that if your distro (e.g.)
>> provides a NO_NSEC build, you can't access the core.usenanosec feature
>> without compiling yourself, even if your platform supports it. But I
>> haven't thought too hard either about what it looks like to get rid of
>> NO_NSEC entirely, and I'm not totally sure if that's a good idea.
>
> You couldn't access it even if core.usenanosec is supported in the
> build, because your fake nsec values would all be "0" and it's
> effectively a noop. ;)
>
> My suggestion wasn't really about supporting more cases, but just about
> making the code simpler by having one less #ifdef. But like I said
> earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably
> not worth worrying about the one #ifdef either way.
>
> -Peff
Right on. Always good to find myself nodding along with your explanations :)
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-02 11:45 ` Ben Knoble
@ 2026-09-02 21:05 ` Junio C Hamano
2026-09-03 1:00 ` Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-09-02 21:05 UTC (permalink / raw)
To: Ben Knoble
Cc: Jeff King, git, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Yuchen Tian
Ben Knoble <ben.knoble@gmail.com> writes:
>> My suggestion wasn't really about supporting more cases, but just about
>> making the code simpler by having one less #ifdef. But like I said
>> earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably
>> not worth worrying about the one #ifdef either way.
>>
>> -Peff
>
> Right on. Always good to find myself nodding along with your explanations :)
OK. So will we see a hopefully small and final reroll that takes
advantage of the fact that ST_XTIME_NSEC(st) would usefully hide the
NO_NSEC build-time differences?
I still am worried that something that sits this deep in the
callchain can easily BUG() when working on a repository that is not
the_repository due to the use of repo_config_values(), and we might
be better off adopting safe default when istate->repo is different
from the_repository, but other than that, I think the series is in
great shape.
Thanks.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-02 21:05 ` Junio C Hamano
@ 2026-09-03 1:00 ` Ben Knoble
2026-09-03 15:56 ` Junio C Hamano
0 siblings, 1 reply; 68+ messages in thread
From: Ben Knoble @ 2026-09-03 1:00 UTC (permalink / raw)
To: Junio C Hamano
Cc: Jeff King, git, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Yuchen Tian
> Le 2 sept. 2026 à 17:05, Junio C Hamano <gitster@pobox.com> a écrit :
>
> Ben Knoble <ben.knoble@gmail.com> writes:
>
>>> My suggestion wasn't really about supporting more cases, but just about
>>> making the code simpler by having one less #ifdef. But like I said
>>> earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably
>>> not worth worrying about the one #ifdef either way.
>>>
>>> -Peff
>>
>> Right on. Always good to find myself nodding along with your explanations :)
>
> OK. So will we see a hopefully small and final reroll that takes
> advantage of the fact that ST_XTIME_NSEC(st) would usefully hide the
> NO_NSEC build-time differences?
Ah, no: I wasn’t planning on removing this ifdef, as I think Peff and I agree that it’s not worth the hassle (at least for now).
> I still am worried that something that sits this deep in the
> callchain can easily BUG() when working on a repository that is not
> the_repository due to the use of repo_config_values(), and we might
> be better off adopting safe default when istate->repo is different
> from the_repository, but other than that, I think the series is in
> great shape.
>
> Thanks.
Yea. See previous messages re: convincing the test apparatus to set this globally. If I could run it that way at least locally, it would go a little ways towards scaring those BUGs out into the light.
Absent suggestions, though, I’m afraid my time is limited to explore the guts of yet another subsystem ;)
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-03 1:00 ` Ben Knoble
@ 2026-09-03 15:56 ` Junio C Hamano
2026-09-03 18:16 ` Ben Knoble
0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2026-09-03 15:56 UTC (permalink / raw)
To: Ben Knoble
Cc: Jeff King, git, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Yuchen Tian
Ben Knoble <ben.knoble@gmail.com> writes:
>> I still am worried that something that sits this deep in the
>> callchain can easily BUG() when working on a repository that is not
>> the_repository due to the use of repo_config_values(), and we might
>> be better off adopting safe default when istate->repo is different
>> from the_repository, but other than that, I think the series is in
>> great shape.
>>
>> Thanks.
[administrivia: wrap overly long lines]
> Yea. See previous messages re: convincing the test apparatus to
> set this globally. If I could run it that way at least locally, it
> would go a little ways towards scaring those BUGs out into the
> light.
I am not worried too much about the current code. I am more worried
about how much this will hinder future development of new features,
e.g., diff or status recursively going into submodules without
spawning subprocesses, which is done for grep already. Testing and
seeing 'git grep --recurse-submodule' not hitting a BUG() does not
assure us all that much, as I do not think it needs to deal with
racily clean entries any specially.
Thanks.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec
2026-09-03 15:56 ` Junio C Hamano
@ 2026-09-03 18:16 ` Ben Knoble
0 siblings, 0 replies; 68+ messages in thread
From: Ben Knoble @ 2026-09-03 18:16 UTC (permalink / raw)
To: Junio C Hamano
Cc: Jeff King, git, Patrick Steinhardt, Todd Zullinger,
Olamide Caleb Bello, Yuchen Tian
> Le 3 sept. 2026 à 11:56, Junio C Hamano <gitster@pobox.com> a écrit :
>
> Ben Knoble <ben.knoble@gmail.com> writes:
>
>>> I still am worried that something that sits this deep in the
>>> callchain can easily BUG() when working on a repository that is not
>>> the_repository due to the use of repo_config_values(), and we might
>>> be better off adopting safe default when istate->repo is different
>>> from the_repository, but other than that, I think the series is in
>>> great shape.
>>>
>>> Thanks.
>
>> Yea. See previous messages re: convincing the test apparatus to
>> set this globally. If I could run it that way at least locally, it
>> would go a little ways towards scaring those BUGs out into the
>> light.
>
> I am not worried too much about the current code. I am more worried
> about how much this will hinder future development of new features,
> e.g., diff or status recursively going into submodules without
> spawning subprocesses, which is done for grep already.
Sure. Some kind of safe default could alleviate that.
But seeing recent work in these areas convinces me that
we should use this as impetus to lift the restriction, and
I worry that papering over it will remove that impetus.
Still, if a later series needs such a band-aid, I suppose it
can add the safe fallback. And that’s where testing would
be nice for automatic feedback on new such interactions.
> Testing and
> seeing 'git grep --recurse-submodule' not hitting a BUG() does not
> assure us all that much, as I do not think it needs to deal with
> racily clean entries any specially.
A prior reply of mine to Patrick specifically mentioned diff
with submodules, I believe. But I agree that positive evidence
is probably better than negative evidence.
All-in-all, I’m not inclined to change the shape of this series
at the present point in this discussion, but if you (or others)
feel strongly about this « safe default » being a requirement,
I will find some time eventually.
^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 0/3] Convert USE_NSEC to runtime config
2026-08-31 20:01 ` [PATCH v6 0/3] Convert USE_NSEC to runtime config D. Ben Knoble
` (2 preceding siblings ...)
2026-08-31 20:01 ` [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec D. Ben Knoble
@ 2026-08-31 20:06 ` D. Ben Knoble
3 siblings, 0 replies; 68+ messages in thread
From: D. Ben Knoble @ 2026-08-31 20:06 UTC (permalink / raw)
To: git
Erm, woops
On Mon, Aug 31, 2026 at 4:02 PM D. Ben Knoble <ben.knoble@gmail.com> wrote:
>
> Topic name: dk/use-nsec-runtime (applied)
>
> Topic summary: Expose USE_NSEC as a runtime configuration, since
> build-time is too early for distributing Git [1]. As a result, common
> index-related options, like git-diff, are less likely to hit "racy git"
> problems on supported filesystems.
>
> [1]: https://git.github.io/rev_news/2026/07/31/edition-137/
>
> Built on master (2c78326f81 (The 11th batch, 2026-08-05)).
Changes in v6: slight comment tweak
> Changes in v5:
>
> - improve message flow in patch 2
[snip]
> Diff-intervalle contre v5 :
> 1: d612de6c2d = 1: d612de6c2d meson: expose knob for xmlto relative links in manuals
> 2: 12974e07d0 = 2: 12974e07d0 environment: align repo_config_values_init with struct declaration
> 3: 01cd487cd2 ! 3: 0a611f6140 core: convert build-time USE_NSEC into runtime core.useNanosec
> @@ builtin/update-index.c: static void xrmdir(const char *path)
> {
> /*
> - * not use if we could usleep(10) if USE_NSEC is defined. The
> -+ * not use if we could usleep(10) if core.useNanosec is defined. The
> ++ * not use if we could usleep(10) if core.useNanosec is enabled. The
> * field nsec could be there, but the OS could choose to
> * ignore it?
> */
>
> base-commit: 2c78326f810173a4f3aefd8021f1e07575412481
> --
> 2.55.0.860.g4b6b3295ed.dirty
Thanks
--
D. Ben Knoble
^ permalink raw reply [flat|nested] 68+ messages in thread