{"thread":{"id":"66138","subject":"[PATCH 0/3] Convert USE_NSEC to runtime config","startedAt":"2026-08-07T12:00:47Z","lastAt":"2026-09-11T20:16:41Z","messageCount":74,"participants":["D. Ben Knoble","Junio C Hamano","SZEDER Gábor","Patrick Steinhardt","Ben Knoble","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"549987","messageId":"cover.1786103607.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":null,"subject":"[PATCH 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-07T11:56:23Z","receivedAt":"2026-08-07T12:00:47Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n- The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n- The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n- The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nTodo: I haven't touched any tests; I saw a bunch of hits for \"git grep\nracy t\" but wasn't sure how to fit this particular change in, especially\nsince it won't be equally valid on all systems? Advice welcome.\n\nTodo: I wonder if \"useNanosec\" paints us into too much of a corner; that\nis (slightly more abstractly), we are using *extended precision* in the\nindex. Maybe the name and documentation should reflect that, so we\naren't too committed to \"nanoseconds\"?\n    - Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    - Some could offer precision _beyond_ nanoseconds\nidk.\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  6 ++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 25 ++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 17 +++++++++--------\n statinfo.c                            | 14 +++++++-------\n 12 files changed, 57 insertions(+), 47 deletions(-)\n\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.340.g8e2bf96aa5.dirty\n\n"},{"id":"549988","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1786103607.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786103607.git.ben.knoble@gmail.com","subject":"[PATCH 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-07T11:56:24Z","receivedAt":"2026-08-07T12:01:03Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.340.g8e2bf96aa5.dirty\n\n"},{"id":"549990","messageId":"5693baa9923afd20333c0eb016cc5949f8dfc423.1786103607.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786103607.git.ben.knoble@gmail.com","subject":"[PATCH 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-07T11:56:25Z","receivedAt":"2026-08-07T12:01:25Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially when comparing with the struct definition to\nensure all members are initialized. As new members will be added in the\nfuture, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.340.g8e2bf96aa5.dirty\n\n"},{"id":"549989","messageId":"dbbd96d50811e4c2decb6f754b56dc1f7ee0944a.1786103607.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786103607.git.ben.knoble@gmail.com","subject":"[PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-07T11:56:26Z","receivedAt":"2026-08-07T12:01:31Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about it don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nBest-viewed-with: --ignore-space-change\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Repeating the benchmark from my original mail [1] shows an improvement\n    \n    # git worktree add -d ../perf-test HEAD\n    # hyperfine -N --warmup=10 './build/bin-wrappers/git diff'\n    Benchmark 1: ./build/bin-wrappers/git diff\n      Time (mean ± σ):       3.8 ms ±   0.4 ms    [User: 4.7 ms, System: 4.4 ms]\n      Range (min … max):     3.2 ms …   5.6 ms    780 runs\n    # (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git diff')\n    Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git diff\n      Time (mean ± σ):     217.5 ms ±   2.9 ms    [User: 202.1 ms, System: 23.4 ms]\n      Range (min … max):   213.9 ms … 223.3 ms    13 runs\n    # (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git -c core.useNanosec=true diff')\n    Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git -c core.useNanosec=true diff\n      Time (mean ± σ):       3.8 ms ±   0.4 ms    [User: 5.3 ms, System: 4.2 ms]\n      Range (min … max):     3.2 ms …   6.9 ms    541 runs\n    \n    [1]: <CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com>\n    \n    Passing CI: https://github.com/benknoble/git/actions/runs/31104581195\n\n Documentation/config/core.adoc        |  6 ++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         |  6 ++++++\n environment.h                         |  1 +\n read-cache.c                          | 17 +++++++++--------\n statinfo.c                            | 14 +++++++-------\n 10 files changed, 37 insertions(+), 39 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..33104444ab 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,12 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisions between the index and the working tree (if Git\n+\twas compiled to store it).\n+\tSee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..8e0c25655f 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is defined. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..e6a50060e8 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +774,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+\tcfg->use_nanosec = 0;\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..297646c357 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n+\tint use_nsec = 0;\n+\trepo_config_get_bool(the_repository, \"core.useNanosec\", &use_nsec);\n+\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n-#else\n-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n-#endif\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\tuse_nsec\n+\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n \t\t);\n }\n \ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..d9ddcf9382 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n-#endif\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n \n \tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n-- \n2.55.0.340.g8e2bf96aa5.dirty\n\n"},{"id":"550053","messageId":"xmqqv79ld40c.fsf@gitster.g","threadId":"66138","inReplyTo":"dbbd96d50811e4c2decb6f754b56dc1f7ee0944a.1786103607.git.ben.knoble@gmail.com","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-07T21:17:39Z","receivedAt":"2026-08-07T21:17:41Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> Racy Git problems persist today, manifesting themselves in the\n> performance of commands like \"git diff\" in new worktrees [1]. We have\n> long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n> precision when available, which mitigates most if not all racy issues,\n> but most builds we know about it don't use it. In part, that's because\n> someone distributing Git can't safely enable it at compile-time if they\n> don't know exactly what platforms their distribution will be used on.\n>\n> [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n>\n> These days, most platforms are likely to be safe for the USE_NSEC code.\n> Regardless, we want to give users the ability to benefit from it. This\n> requires exposing the compile-time gated code as a runtime option.\n>\n> In addition, update the Racy Git documentation and other mentions of\n> USE_NSEC in the code.\n>\n> Best-viewed-with: --ignore-space-change\n\nDon't do this.  It probably is helpful to have something like that\nbelow the three-dash lines, though.\n\n> Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n> ---\n\n> diff --git a/environment.c b/environment.c\n> index 6676e6f5ae..e6a50060e8 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\treturn 0;\n>  \t}\n>  \n> +\tif (!strcmp(var, \"core.usenanosec\")) {\n> +\t\tcfg->use_nanosec = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n\nOK.\n\n> diff --git a/read-cache.c b/read-cache.c\n> index 6c449f393d..297646c357 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n>  static int is_racy_stat(const struct index_state *istate,\n>  \t\t\tconst struct stat_data *sd)\n>  {\n> +\tint use_nsec = 0;\n> +\trepo_config_get_bool(the_repository, \"core.useNanosec\", &use_nsec);\n\nYeek.  Isn't this a relatively hot code path?  If it is, it is\ncriminal to force string parsing and matching like this, every time\nsomebody calls the function.\n\nDoesn't istate know what repository it is working with and in there\nyou should be able find its repo_settings struct cheaply, no?\n\n"},{"id":"550099","messageId":"andZ2eIe6RXifor4@szeder.dev","threadId":"66138","inReplyTo":"xmqqv79ld40c.fsf@gitster.g","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2026-08-08T16:31:21Z","receivedAt":"2026-08-08T16:31:26Z","isPatch":true,"body":"On Fri, Aug 07, 2026 at 02:17:39PM -0700, Junio C Hamano wrote:\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n> \n> > Racy Git problems persist today, manifesting themselves in the\n> > performance of commands like \"git diff\" in new worktrees [1]. We have\n> > long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n> > precision when available, which mitigates most if not all racy issues,\n> > but most builds we know about it don't use it. In part, that's because\n> > someone distributing Git can't safely enable it at compile-time if they\n> > don't know exactly what platforms their distribution will be used on.\n> >\n> > [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n> >\n> > These days, most platforms are likely to be safe for the USE_NSEC code.\n> > Regardless, we want to give users the ability to benefit from it. This\n> > requires exposing the compile-time gated code as a runtime option.\n> >\n> > In addition, update the Racy Git documentation and other mentions of\n> > USE_NSEC in the code.\n> >\n> > Best-viewed-with: --ignore-space-change\n> \n> Don't do this.  It probably is helpful to have something like that\n> below the three-dash lines, though.\n\nIncluding this hint in the commit message could be useful for anyone\nwho stumbles upon this commit in a couple of months or years time.\nWhether it should be a trailer or not is another question.\n\n"},{"id":"550168","messageId":"CALnO6CBqJT6uHTXvgffB9rW458THr5LjzL=NZSt81PPfBATPyA@mail.gmail.com","threadId":"66138","inReplyTo":"andZ2eIe6RXifor4@szeder.dev","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-10T12:27:46Z","receivedAt":"2026-08-10T12:27:58Z","isPatch":true,"body":"On Sat, Aug 8, 2026 at 12:31 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n>\n> On Fri, Aug 07, 2026 at 02:17:39PM -0700, Junio C Hamano wrote:\n> > \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n> >\n> > > Racy Git problems persist today, manifesting themselves in the\n> > > performance of commands like \"git diff\" in new worktrees [1]. We have\n> > > long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n> > > precision when available, which mitigates most if not all racy issues,\n> > > but most builds we know about it don't use it. In part, that's because\n> > > someone distributing Git can't safely enable it at compile-time if they\n> > > don't know exactly what platforms their distribution will be used on.\n> > >\n> > > [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n> > >\n> > > These days, most platforms are likely to be safe for the USE_NSEC code.\n> > > Regardless, we want to give users the ability to benefit from it. This\n> > > requires exposing the compile-time gated code as a runtime option.\n> > >\n> > > In addition, update the Racy Git documentation and other mentions of\n> > > USE_NSEC in the code.\n> > >\n> > > Best-viewed-with: --ignore-space-change\n> >\n> > Don't do this.  It probably is helpful to have something like that\n> > below the three-dash lines, though.\n>\n> Including this hint in the commit message could be useful for anyone\n> who stumbles upon this commit in a couple of months or years time.\n> Whether it should be a trailer or not is another question.\n\nYep, the trailer is a force-of-habit for me. I'll move it into the\ncommit message body in the next version.\n\nI do find it helpful when the author of a patch---who presumably knows\nthe changes best---provides some guidance on making sense of the diff.\nIn this case, some code is re-indented as '#ifdef's change to runtime\n'if's, so ignoring whitespace changes makes it easier to see there was\nno change there.\n\n-- \nD. Ben Knoble\n"},{"id":"550169","messageId":"CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com","threadId":"66138","inReplyTo":"xmqqv79ld40c.fsf@gitster.g","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-10T12:27:51Z","receivedAt":"2026-08-10T12:28:04Z","isPatch":true,"body":"On Fri, Aug 7, 2026 at 5:17 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> > Racy Git problems persist today, manifesting themselves in the\n> > performance of commands like \"git diff\" in new worktrees [1]. We have\n> > long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n> > precision when available, which mitigates most if not all racy issues,\n> > but most builds we know about it don't use it. In part, that's because\n> > someone distributing Git can't safely enable it at compile-time if they\n> > don't know exactly what platforms their distribution will be used on.\n> >\n> > [1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n> >\n> > These days, most platforms are likely to be safe for the USE_NSEC code.\n> > Regardless, we want to give users the ability to benefit from it. This\n> > requires exposing the compile-time gated code as a runtime option.\n> >\n> > In addition, update the Racy Git documentation and other mentions of\n> > USE_NSEC in the code.\n> >\n> > Best-viewed-with: --ignore-space-change\n>\n> Don't do this.  It probably is helpful to have something like that\n> below the three-dash lines, though.\n\n[replied to SZEDER down-thread]\n\n>\n> > Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n> > ---\n>\n> > diff --git a/environment.c b/environment.c\n> > index 6676e6f5ae..e6a50060e8 100644\n> > --- a/environment.c\n> > +++ b/environment.c\n> > @@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,\n> >               return 0;\n> >       }\n> >\n> > +     if (!strcmp(var, \"core.usenanosec\")) {\n> > +             cfg->use_nanosec = git_config_bool(var, value);\n> > +             return 0;\n> > +     }\n>\n> OK.\n>\n> > diff --git a/read-cache.c b/read-cache.c\n> > index 6c449f393d..297646c357 100644\n> > --- a/read-cache.c\n> > +++ b/read-cache.c\n> > @@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n> >  static int is_racy_stat(const struct index_state *istate,\n> >                       const struct stat_data *sd)\n> >  {\n> > +     int use_nsec = 0;\n> > +     repo_config_get_bool(the_repository, \"core.useNanosec\", &use_nsec);\n>\n> Yeek.  Isn't this a relatively hot code path?  If it is, it is\n> criminal to force string parsing and matching like this, every time\n> somebody calls the function.\n>\n> Doesn't istate know what repository it is working with and in there\n> you should be able find its repo_settings struct cheaply, no?\n\nTL;DR yes, but the patch series doesn't currently put the member in\nrepo_settings (repo_config_values). End of mail contains some\ncommentary there; folks from <anlmwaEtwcCPse1N@pks.im> cc'd.\n\nI did some benchmarking on linux.git @ 848acc8ffe1b7cd5f1bf427b93069becfebc2c9d.\n\nBrand-new worktree, without refreshing the index:\n\nhyperfine -N --warmup=10 \\\n-n core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \\\n-n core.useNanosec=true  ~c/'git/build/bin-wrappers/git -c\ncore.useNanosec=true diff' \\\n-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'\nBenchmark 1: core.useNanosec=false\n  Time (mean ± σ):     853.7 ms ±  23.2 ms    [User: 823.2 ms, System: 159.3 ms]\n  Range (min … max):   839.5 ms … 904.7 ms    10 runs\n\n  Warning: Statistical outliers were detected. Consider re-running\nthis benchmark on a quiet system without any interferences from other\nprograms. It might help to use the '--warmup' or '--prepare' options.\n\nBenchmark 2: core.useNanosec=true\n  Time (mean ± σ):      20.4 ms ±   1.5 ms    [User: 41.0 ms, System: 102.2 ms]\n  Range (min … max):    17.6 ms …  24.8 ms    122 runs\n\nBenchmark 3: v2.55.0_USE_NSEC_disabled\n  Time (mean ± σ):     839.2 ms ±  12.7 ms    [User: 796.8 ms, System: 158.8 ms]\n  Range (min … max):   830.5 ms … 864.4 ms    10 runs\n\n  Warning: Statistical outliers were detected. Consider re-running\nthis benchmark on a quiet system without any interferences from other\nprograms. It might help to use the '--warmup' or '--prepare' options.\n\nSummary\n  core.useNanosec=true ran\n   41.06 ± 3.03 times faster than v2.55.0_USE_NSEC_disabled\n   41.77 ± 3.22 times faster than core.useNanosec=false\n\nSame worktree after \"git update-index --refresh\":\n\nhyperfine -N --warmup=10 \\\n-n core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \\\n-n core.useNanosec=true  ~c/'git/build/bin-wrappers/git -c\ncore.useNanosec=true diff' \\\n-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'\nBenchmark 1: core.useNanosec=false\n  Time (mean ± σ):      20.8 ms ±   2.1 ms    [User: 41.8 ms, System: 102.9 ms]\n  Range (min … max):    17.4 ms …  26.4 ms    126 runs\n\nBenchmark 2: core.useNanosec=true\n  Time (mean ± σ):      20.0 ms ±   1.0 ms    [User: 40.4 ms, System: 101.8 ms]\n  Range (min … max):    18.0 ms …  23.6 ms    158 runs\n\nBenchmark 3: v2.55.0_USE_NSEC_disabled\n  Time (mean ± σ):      19.2 ms ±   1.1 ms    [User: 27.3 ms, System: 100.2 ms]\n  Range (min … max):    16.9 ms …  23.4 ms    160 runs\n\nSummary\n  v2.55.0_USE_NSEC_disabled ran\n    1.04 ± 0.08 times faster than core.useNanosec=true\n    1.08 ± 0.13 times faster than core.useNanosec=false\n\nSo yeah, when we don't need the nanosec timings, this ends up minutely\nslower than without it. When I apply the attached patch (sorry, GMail)\non top to poke through\nistate->repo->config_values_private_.use_nanosec:\n\nNew worktree, no index refresh:\n\nhyperfine -N --warmup=10 \\\n-n v2_core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \\\n-n v2_core.useNanosec=true  ~c/'git/build/bin-wrappers/git -c\ncore.useNanosec=true diff' \\\n-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'\nBenchmark 1: v2_core.useNanosec=false\n  Time (mean ± σ):     148.0 ms ±   2.8 ms    [User: 142.5 ms, System: 124.0 ms]\n  Range (min … max):   144.3 ms … 155.3 ms    20 runs\n\nBenchmark 2: v2_core.useNanosec=true\n  Time (mean ± σ):      21.2 ms ±   2.0 ms    [User: 27.6 ms, System: 101.4 ms]\n  Range (min … max):    17.5 ms …  28.8 ms    123 runs\n\nBenchmark 3: v2.55.0_USE_NSEC_disabled\n  Time (mean ± σ):     148.4 ms ±   8.6 ms    [User: 141.0 ms, System: 122.8 ms]\n  Range (min … max):   140.9 ms … 179.6 ms    21 runs\n\nSummary\n  v2_core.useNanosec=true ran\n    7.00 ± 0.67 times faster than v2_core.useNanosec=false\n    7.01 ± 0.77 times faster than v2.55.0_USE_NSEC_disabled\n\n(We can see the raciness in the variability of the timings, neat)\n\nAfter \"git update-index --refresh\":\n\nhyperfine -N --warmup=10 \\\n-n v2_core.useNanosec=false ~c/'git/build/bin-wrappers/git diff' \\\n-n v2_core.useNanosec=true  ~c/'git/build/bin-wrappers/git -c\ncore.useNanosec=true diff' \\\n-n v2.55.0_USE_NSEC_disabled ~c/'perf-test/build/bin-wrappers/git diff'\nBenchmark 1: v2_core.useNanosec=false\n  Time (mean ± σ):      20.8 ms ±   2.6 ms    [User: 27.9 ms, System: 103.8 ms]\n  Range (min … max):    17.2 ms …  29.1 ms    132 runs\n\nBenchmark 2: v2_core.useNanosec=true\n  Time (mean ± σ):      19.7 ms ±   1.5 ms    [User: 29.2 ms, System: 100.0 ms]\n  Range (min … max):    17.0 ms …  28.2 ms    170 runs\n\nBenchmark 3: v2.55.0_USE_NSEC_disabled\n  Time (mean ± σ):      19.7 ms ±   1.6 ms    [User: 27.8 ms, System: 99.1 ms]\n  Range (min … max):    16.8 ms …  25.0 ms    154 runs\n\nSummary\n  v2_core.useNanosec=true ran\n    1.00 ± 0.11 times faster than v2.55.0_USE_NSEC_disabled\n    1.05 ± 0.15 times faster than v2_core.useNanosec=false\n\nBack down to being on-par with original code. So that's good. The next\nversion will include some variant that reads a struct member instead\nof going through repo_config_get_bool().\n\nBut which? Reading the private_ member is obviously wrong; I suppose\nI'm supposed to use repo_config_values() there. Or, rework the series\nto put this member in repo_settings. I think I originally assumed that\nstruct is for things that are settings that aren't configured by\ngit-config, but… now I'm not sure. Looking at prepare_repo_settings()\nshows lots of repo_cfg_*() calls. So I think I see how to adapt to\nusing repo_settings,\n\nPatrick, Junio, and Tian had a brief discussion in\n<anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't\nreally want to wait for it to settle to land this change, but we might\nwant to work together on identifying the best path forward for\ncore.useNanosec :)\n\nI don't suppose it really matters to me which struct I put the member\nin. As I said, v2 will definitely fix the hot path lookup here. Just a\nmatter of input on which struct we want to use this time, I guess.\n\n-- \nD. Ben Knoble\n\n\ndiff --git i/read-cache.c w/read-cache.c\nindex 297646c357..4bb5f466a1 100644\n--- i/read-cache.c\n+++ w/read-cache.c\n@@ -353,8 +353,9 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n-\tint use_nsec = 0;\n-\trepo_config_get_bool(the_repository, \"core.useNanosec\", &use_nsec);\n+\t/* supposed to use repo_config_values(), probably?\n+\t * or we should move this member to struct repo_settings */\n+\tint use_nsec = istate->repo->config_values_private_.use_nanosec;\n \n \treturn (istate->timestamp.sec &&\n \t\t/* nanosecond timestamped files can also be racy! */\n"},{"id":"550171","messageId":"annHlFwu4NKwmcLr@pks.im","threadId":"66138","inReplyTo":"CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-10T12:44:04Z","receivedAt":"2026-08-10T12:44:12Z","isPatch":true,"body":"On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:\n[snip]\n> Back down to being on-par with original code. So that's good. The next\n> version will include some variant that reads a struct member instead\n> of going through repo_config_get_bool().\n> \n> But which? Reading the private_ member is obviously wrong; I suppose\n> I'm supposed to use repo_config_values() there. Or, rework the series\n> to put this member in repo_settings. I think I originally assumed that\n> struct is for things that are settings that aren't configured by\n> git-config, but… now I'm not sure. Looking at prepare_repo_settings()\n> shows lots of repo_cfg_*() calls. So I think I see how to adapt to\n> using repo_settings,\n> \n> Patrick, Junio, and Tian had a brief discussion in\n> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't\n> really want to wait for it to settle to land this change, but we might\n> want to work together on identifying the best path forward for\n> core.useNanosec :)\n> \n> I don't suppose it really matters to me which struct I put the member\n> in. As I said, v2 will definitely fix the hot path lookup here. Just a\n> matter of input on which struct we want to use this time, I guess.\n\nI think `repo_config_values()` is the modern variant that we're slowly\nmigrating stuff into. But that struct only works with `the_repository`,\nso the question is whether we ever use \"core.useNsec\" for a different\nrepository. My hunch would be yes, for example when recusing into\nsubmodules, but I'm not sure.\n\nPatrick\n"},{"id":"550173","messageId":"annJEmkSoRIrhbpx@pks.im","threadId":"66138","inReplyTo":"dbbd96d50811e4c2decb6f754b56dc1f7ee0944a.1786103607.git.ben.knoble@gmail.com","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-10T12:50:26Z","receivedAt":"2026-08-10T12:50:33Z","isPatch":true,"body":"On Fri, Aug 07, 2026 at 07:56:26AM -0400, D. Ben Knoble wrote:\n> diff --git a/compat/posix.h b/compat/posix.h\n> index e2e794cad7..51ee03233b 100644\n> --- a/compat/posix.h\n> +++ b/compat/posix.h\n> @@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n>  } while (0)\n>  \n>  #ifdef NO_NSEC\n> -#undef USE_NSEC\n>  #define ST_CTIME_NSEC(st) 0\n>  #define ST_MTIME_NSEC(st) 0\n>  #else\n\nAh, I was about to ask whether all platforms even support nanoseconds.\nBut I wasn't aware that we have both NO_NSEC and USE_NSEC, so we still\nknow to not use nanoseconds if unsupported by the platform.\n\nPatrick\n"},{"id":"550174","messageId":"annJGNtPnC_iA_9y@pks.im","threadId":"66138","inReplyTo":"d612de6c2de615f368b5985f200c5ea8e3116c08.1786103607.git.ben.knoble@gmail.com","subject":"Re: [PATCH 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-10T12:50:32Z","receivedAt":"2026-08-10T12:50:37Z","isPatch":true,"body":"On Fri, Aug 07, 2026 at 07:56:24AM -0400, D. Ben Knoble wrote:\n> diff --git a/Documentation/meson.build b/Documentation/meson.build\n> index f4854f802d..cfa9c67609 100644\n> --- a/Documentation/meson.build\n> +++ b/Documentation/meson.build\n> @@ -379,13 +379,18 @@ foreach manpage, category : manpages\n>        output: fs.stem(manpage) + '.xml',\n>      )\n>  \n> +    man_base_url = 'file://' + htmldir + '/'\n> +    if get_option('man_base_url') != ''\n> +      man_base_url = get_option('man_base_url')\n> +    endif\n> +\n>      doc_targets += custom_target(\n>        command: [\n>          xmlto,\n>          '-m', '@INPUT0@',\n>          '-m', '@INPUT1@',\n>          '--stringparam',\n> -        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n> +        'man.base.url.for.relative.links=' + man_base_url,\n>          'man',\n>          manpage_xml_target,\n>          '-o',\n> diff --git a/meson_options.txt b/meson_options.txt\n> index dc88f130d7..d590c21648 100644\n> --- a/meson_options.txt\n> +++ b/meson_options.txt\n> @@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n>    description: 'Default format used when executing git-help(1).')\n>  option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n>    description: 'Which backend to use to generate documentation.')\n> +option('man_base_url', type: 'string', value: '',\n> +  description: 'The base URL to use for relative links in manuals')\n\nMakes sense. I also verified that we indeed use the \"file://\" prefix by\ndefault in our Makefile.\n\nPatrick\n"},{"id":"550295","messageId":"59E4039A-C9BA-4EFD-8022-77C73EB51ED0@gmail.com","threadId":"66138","inReplyTo":"annHlFwu4NKwmcLr@pks.im","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-11T16:26:42Z","receivedAt":"2026-08-11T16:26:56Z","isPatch":true,"body":"\n> Le 10 août 2026 à 08:44, Patrick Steinhardt <ps@pks.im> a écrit :\n> \n> ﻿On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:\n> [snip]\n>> Back down to being on-par with original code. So that's good. The next\n>> version will include some variant that reads a struct member instead\n>> of going through repo_config_get_bool().\n>> \n>> But which? Reading the private_ member is obviously wrong; I suppose\n>> I'm supposed to use repo_config_values() there. Or, rework the series\n>> to put this member in repo_settings. I think I originally assumed that\n>> struct is for things that are settings that aren't configured by\n>> git-config, but… now I'm not sure. Looking at prepare_repo_settings()\n>> shows lots of repo_cfg_*() calls. So I think I see how to adapt to\n>> using repo_settings,\n>> \n>> Patrick, Junio, and Tian had a brief discussion in\n>> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't\n>> really want to wait for it to settle to land this change, but we might\n>> want to work together on identifying the best path forward for\n>> core.useNanosec :)\n>> \n>> I don't suppose it really matters to me which struct I put the member\n>> in. As I said, v2 will definitely fix the hot path lookup here. Just a\n>> matter of input on which struct we want to use this time, I guess.\n> \n> I think `repo_config_values()` is the modern variant that we're slowly\n> migrating stuff into. But that struct only works with `the_repository`,\n> so the question is whether we ever use \"core.useNsec\" for a different\n> repository. My hunch would be yes, for example when recusing into\n> submodules, but I'm not sure.\n> \n> Patrick\n\nThanks. 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. "},{"id":"550581","messageId":"CALnO6CA5LdL74SqC9V_wJWi=Pf7+cHBDkuUFAJ7jCOVWZjBOzA@mail.gmail.com","threadId":"66138","inReplyTo":"59E4039A-C9BA-4EFD-8022-77C73EB51ED0@gmail.com","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-13T21:40:31Z","receivedAt":"2026-08-13T21:40:43Z","isPatch":true,"body":"On Tue, Aug 11, 2026 at 12:26 PM Ben Knoble <ben.knoble@gmail.com> wrote:\n>\n>\n> > Le 10 août 2026 à 08:44, Patrick Steinhardt <ps@pks.im> a écrit :\n> >\n> > ﻿On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:\n> > [snip]\n> >> Back down to being on-par with original code. So that's good. The next\n> >> version will include some variant that reads a struct member instead\n> >> of going through repo_config_get_bool().\n> >>\n> >> But which? Reading the private_ member is obviously wrong; I suppose\n> >> I'm supposed to use repo_config_values() there. Or, rework the series\n> >> to put this member in repo_settings. I think I originally assumed that\n> >> struct is for things that are settings that aren't configured by\n> >> git-config, but… now I'm not sure. Looking at prepare_repo_settings()\n> >> shows lots of repo_cfg_*() calls. So I think I see how to adapt to\n> >> using repo_settings,\n> >>\n> >> Patrick, Junio, and Tian had a brief discussion in\n> >> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't\n> >> really want to wait for it to settle to land this change, but we might\n> >> want to work together on identifying the best path forward for\n> >> core.useNanosec :)\n> >>\n> >> I don't suppose it really matters to me which struct I put the member\n> >> in. As I said, v2 will definitely fix the hot path lookup here. Just a\n> >> matter of input on which struct we want to use this time, I guess.\n> >\n> > I think `repo_config_values()` is the modern variant that we're slowly\n> > migrating stuff into. But that struct only works with `the_repository`,\n> > so the question is whether we ever use \"core.useNsec\" for a different\n> > repository. My hunch would be yes, for example when recusing into\n> > submodules, but I'm not sure.\n> >\n> > Patrick\n>\n> 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.\n\nOk, CI run: https://github.com/benknoble/git/actions/runs/31701945211.\nThis demonstrates that nothing our test suite does across the many CI\nconfigurations ends up where with a non-the_repository-repository\n(ahem).\n\nI have been working on control-flow analysis by hand in my Git time\nthis week. It's of the form \"Z calls Y calls X …\" until we can see\nwhat the repository that's (eventually) fed to repo_config_values()\nhere in is_racy_stat() is. My notes are one node per line, which\nindentation showing callee relationships. Some lines are pointers to\nother nodes to avoid duplicating work.\n\nWith that in mind, filtering out the pointer nodes, I've analyzed 214\nnodes in the graph. If I'm lucky, I'm approaching the halfway mark,\nbut I somewhat doubt it.\n\nBut since CI shows things work… I'd rather not continue the analysis\nif we're satisfied for now. (Esp. since that will give me more Git\ntime back for reviewing ;) It being outside-of-work time, I only have\nso much of it.)\n\nA few other related things:\n- Some of the edges of the graph appear to be public libgit.a\ninterfaces. That means we can't guarantee that only the_repository is\nused.\n- On a related note, I don't know how large the current \"must only use\nthe_repository\" (e.g., via repo_config_values()) surface area is right\nnow. Based on the partial analysis I mentioned above, this feels like\nit's introducing (or at least contributing to) a rather large surface\narea. So, this change might make it more critical to resolve the\nlimitation mentioned in the other thread. OTOH, I don't think this\nchange is likely to represent the only pervasive the_repository-only\nlimitation, and I'm afraid it will never land if it must be\nthe_repository clean (unless repo_settings is the_repository clean and\nwe decide that's an acceptable place for this member).\n\nSo, idk. If we're happy with the CI run + use of repo_config_values()\noverall, I can send a v2 shortly (in next 24h), I think.\n\nThoughts? Strong opinions?\n\n-- \nD. Ben Knoble\n"},{"id":"550605","messageId":"an720tZnot07HYiK@pks.im","threadId":"66138","inReplyTo":"CALnO6CA5LdL74SqC9V_wJWi=Pf7+cHBDkuUFAJ7jCOVWZjBOzA@mail.gmail.com","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-14T11:06:58Z","receivedAt":"2026-08-14T11:07:09Z","isPatch":true,"body":"On Thu, Aug 13, 2026 at 05:40:31PM -0400, D. Ben Knoble wrote:\n> On Tue, Aug 11, 2026 at 12:26 PM Ben Knoble <ben.knoble@gmail.com> wrote:\n> > > Le 10 août 2026 à 08:44, Patrick Steinhardt <ps@pks.im> a écrit :\n> > > ﻿On Mon, Aug 10, 2026 at 08:27:51AM -0400, D. Ben Knoble wrote:\n> > > [snip]\n> > >> Back down to being on-par with original code. So that's good. The next\n> > >> version will include some variant that reads a struct member instead\n> > >> of going through repo_config_get_bool().\n> > >>\n> > >> But which? Reading the private_ member is obviously wrong; I suppose\n> > >> I'm supposed to use repo_config_values() there. Or, rework the series\n> > >> to put this member in repo_settings. I think I originally assumed that\n> > >> struct is for things that are settings that aren't configured by\n> > >> git-config, but… now I'm not sure. Looking at prepare_repo_settings()\n> > >> shows lots of repo_cfg_*() calls. So I think I see how to adapt to\n> > >> using repo_settings,\n> > >>\n> > >> Patrick, Junio, and Tian had a brief discussion in\n> > >> <anlmwaEtwcCPse1N@pks.im> about the split creating confusion. I don't\n> > >> really want to wait for it to settle to land this change, but we might\n> > >> want to work together on identifying the best path forward for\n> > >> core.useNanosec :)\n> > >>\n> > >> I don't suppose it really matters to me which struct I put the member\n> > >> in. As I said, v2 will definitely fix the hot path lookup here. Just a\n> > >> matter of input on which struct we want to use this time, I guess.\n> > >\n> > > I think `repo_config_values()` is the modern variant that we're slowly\n> > > migrating stuff into. But that struct only works with `the_repository`,\n> > > so the question is whether we ever use \"core.useNsec\" for a different\n> > > repository. My hunch would be yes, for example when recusing into\n> > > submodules, but I'm not sure.\n> > >\n> > > Patrick\n> >\n> > 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.\n> \n> Ok, CI run: https://github.com/benknoble/git/actions/runs/31701945211.\n> This demonstrates that nothing our test suite does across the many CI\n> configurations ends up where with a non-the_repository-repository\n> (ahem).\n> \n> I have been working on control-flow analysis by hand in my Git time\n> this week. It's of the form \"Z calls Y calls X …\" until we can see\n> what the repository that's (eventually) fed to repo_config_values()\n> here in is_racy_stat() is. My notes are one node per line, which\n> indentation showing callee relationships. Some lines are pointers to\n> other nodes to avoid duplicating work.\n> \n> With that in mind, filtering out the pointer nodes, I've analyzed 214\n> nodes in the graph. If I'm lucky, I'm approaching the halfway mark,\n> but I somewhat doubt it.\n> \n> But since CI shows things work… I'd rather not continue the analysis\n> if we're satisfied for now. (Esp. since that will give me more Git\n> time back for reviewing ;) It being outside-of-work time, I only have\n> so much of it.)\n> \n> A few other related things:\n> - Some of the edges of the graph appear to be public libgit.a\n> interfaces. That means we can't guarantee that only the_repository is\n> used.\n> - On a related note, I don't know how large the current \"must only use\n> the_repository\" (e.g., via repo_config_values()) surface area is right\n> now. Based on the partial analysis I mentioned above, this feels like\n> it's introducing (or at least contributing to) a rather large surface\n> area. So, this change might make it more critical to resolve the\n> limitation mentioned in the other thread. OTOH, I don't think this\n> change is likely to represent the only pervasive the_repository-only\n> limitation, and I'm afraid it will never land if it must be\n> the_repository clean (unless repo_settings is the_repository clean and\n> we decide that's an acceptable place for this member).\n> \n> So, idk. If we're happy with the CI run + use of repo_config_values()\n> overall, I can send a v2 shortly (in next 24h), I think.\n> \n> Thoughts? Strong opinions?\n\nNo strong opinions from my side, other than that we should stop\nconverting everything to `repo_config_values()` until we have a plan for\nhow to make it work with repositories other than `the_repository`.\n\nI don't feel like holding this series in hostage though, so if your\nanalysis and the test suite both say that this is probably fine then we\nmay want to pursue it. Or we just use a global variable for it for the\ntime being and then wait until the `repo_config_values()` dust has\nsettled.\n\nPatrick\n"},{"id":"550606","messageId":"6767F13B-622A-4988-AE61-373C25599F45@gmail.com","threadId":"66138","inReplyTo":"an720tZnot07HYiK@pks.im","subject":"Re: [PATCH 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-14T11:29:22Z","receivedAt":"2026-08-14T11:29:35Z","isPatch":true,"body":"\n> Le 14 août 2026 à 07:07, Patrick Steinhardt <ps@pks.im> a écrit :\n> \n> ﻿On Thu, Aug 13, 2026 at 05:40:31PM -0400, D. Ben Knoble wrote:\n>> \n>> \n>> Ok, CI run: https://github.com/benknoble/git/actions/runs/31701945211.\n>> This demonstrates that nothing our test suite does across the many CI\n>> configurations ends up where with a non-the_repository-repository\n>> (ahem).\n>> \n>> I have been working on control-flow analysis by hand in my Git time\n>> this week. It's of the form \"Z calls Y calls X …\" until we can see\n>> what the repository that's (eventually) fed to repo_config_values()\n>> here in is_racy_stat() is. My notes are one node per line, which\n>> indentation showing callee relationships. Some lines are pointers to\n>> other nodes to avoid duplicating work.\n>> \n>> With that in mind, filtering out the pointer nodes, I've analyzed 214\n>> nodes in the graph. If I'm lucky, I'm approaching the halfway mark,\n>> but I somewhat doubt it.\n>> \n>> But since CI shows things work… I'd rather not continue the analysis\n>> if we're satisfied for now. (Esp. since that will give me more Git\n>> time back for reviewing ;) It being outside-of-work time, I only have\n>> so much of it.)\n>> \n>> A few other related things:\n>> - Some of the edges of the graph appear to be public libgit.a\n>> interfaces. That means we can't guarantee that only the_repository is\n>> used.\n>> - On a related note, I don't know how large the current \"must only use\n>> the_repository\" (e.g., via repo_config_values()) surface area is right\n>> now. Based on the partial analysis I mentioned above, this feels like\n>> it's introducing (or at least contributing to) a rather large surface\n>> area. So, this change might make it more critical to resolve the\n>> limitation mentioned in the other thread. OTOH, I don't think this\n>> change is likely to represent the only pervasive the_repository-only\n>> limitation, and I'm afraid it will never land if it must be\n>> the_repository clean (unless repo_settings is the_repository clean and\n>> we decide that's an acceptable place for this member).\n>> \n>> So, idk. If we're happy with the CI run + use of repo_config_values()\n>> overall, I can send a v2 shortly (in next 24h), I think.\n>> \n>> Thoughts? Strong opinions?\n> \n> No strong opinions from my side, other than that we should stop\n> converting everything to `repo_config_values()` until we have a plan for\n> how to make it work with repositories other than `the_repository`.\n> \n> I don't feel like holding this series in hostage though, so if your\n> analysis and the test suite both say that this is probably fine then we\n> may want to pursue it. Or we just use a global variable for it for the\n> time being and then wait until the `repo_config_values()` dust has\n> settled.\n> \n> Patrick\n\nMakes 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)."},{"id":"550608","messageId":"cover.1786710807.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786103607.git.ben.knoble@gmail.com","subject":"[PATCH v2 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-14T12:33:59Z","receivedAt":"2026-08-14T12:34:24Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime (applied)\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v2:\n\n- move Best-viewed-with trailer into message body as descriptive\n  text.\n- read core.useNanosec through struct repo instead of parsing\n  config strings. The test suite passes locally this way, though that\n  skipped 151 tests.\n    - CI run: https://github.com/benknoble/git/actions/runs/31701945211\n\nOriginal cover letter:\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n- The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n- The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n- The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nTodo: I haven't touched any tests; I saw a bunch of hits for \"git grep\nracy t\" but wasn't sure how to fit this particular change in, especially\nsince it won't be equally valid on all systems? Advice welcome.\n\nTodo: I wonder if \"useNanosec\" paints us into too much of a corner; that\nis (slightly more abstractly), we are using *extended precision* in the\nindex. Maybe the name and documentation should reflect that, so we\naren't too committed to \"nanoseconds\"?\n    - Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    - Some could offer precision _beyond_ nanoseconds\nidk.\n\nv1: <cover.1786103607.git.ben.knoble@gmail.com>\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  6 ++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 25 ++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 16 ++++++++--------\n statinfo.c                            | 14 +++++++-------\n 12 files changed, 56 insertions(+), 47 deletions(-)\n\nDiff-intervalle contre v1 :\n1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n2:  5693baa992 = 2:  5693baa992 environment: align repo_config_values_init with struct declaration\n3:  dbbd96d508 ! 3:  2d1424732a core: convert build-time USE_NSEC into runtime core.useNanosec\n    @@ Commit message\n         In addition, update the Racy Git documentation and other mentions of\n         USE_NSEC in the code.\n     \n    -    Best-viewed-with: --ignore-space-change\n    +    Due to the conversion from #ifdef to runtime check, using the flag\n    +    \"--ignore-space-change\" may be particularly helpful when viewing changes\n    +    from this patch.\n     \n     \n      ## Notes (benknoble/commits) ##\n    -    Repeating the benchmark from my original mail [1] shows an improvement\n    -\n    -    # git worktree add -d ../perf-test HEAD\n    -    # hyperfine -N --warmup=10 './build/bin-wrappers/git diff'\n    -    Benchmark 1: ./build/bin-wrappers/git diff\n    -      Time (mean ± σ):       3.8 ms ±   0.4 ms    [User: 4.7 ms, System: 4.4 ms]\n    -      Range (min … max):     3.2 ms …   5.6 ms    780 runs\n    -    # (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git diff')\n    -    Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git diff\n    -      Time (mean ± σ):     217.5 ms ±   2.9 ms    [User: 202.1 ms, System: 23.4 ms]\n    -      Range (min … max):   213.9 ms … 223.3 ms    13 runs\n    -    # (pushd ../perf-test && hyperfine -N --warmup=10 $OLDPWD/'./build/bin-wrappers/git -c core.useNanosec=true diff')\n    -    Benchmark 1: /home/benknoble/code/git/./build/bin-wrappers/git -c core.useNanosec=true diff\n    -      Time (mean ± σ):       3.8 ms ±   0.4 ms    [User: 5.3 ms, System: 4.2 ms]\n    -      Range (min … max):     3.2 ms …   6.9 ms    541 runs\n    -\n    -    [1]: <CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com>\n    -\n    -    Passing CI: https://github.com/benknoble/git/actions/runs/31104581195\n    +    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    +    CI: <https://github.com/benknoble/git/actions/runs/31701945211>\n     \n      ## Documentation/config/core.adoc ##\n     @@ Documentation/config/core.adoc: core.trustctime::\n    @@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struc\n      static int is_racy_stat(const struct index_state *istate,\n      \t\t\tconst struct stat_data *sd)\n      {\n    -+\tint use_nsec = 0;\n    -+\trepo_config_get_bool(the_repository, \"core.useNanosec\", &use_nsec);\n    ++\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n     +\n      \treturn (istate->timestamp.sec &&\n     -#ifdef USE_NSEC\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.699.gb54405d56f.dirty\n\n"},{"id":"550609","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1786710807.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786710807.git.ben.knoble@gmail.com","subject":"[PATCH v2 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-14T12:34:00Z","receivedAt":"2026-08-14T12:34:56Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.699.gb54405d56f.dirty\n\n"},{"id":"550610","messageId":"5693baa9923afd20333c0eb016cc5949f8dfc423.1786710807.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786710807.git.ben.knoble@gmail.com","subject":"[PATCH v2 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-14T12:34:01Z","receivedAt":"2026-08-14T12:35:06Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially when comparing with the struct definition to\nensure all members are initialized. As new members will be added in the\nfuture, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.699.gb54405d56f.dirty\n\n"},{"id":"550611","messageId":"2d1424732af6af9c82c775e8256ea914204e8e43.1786710807.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786710807.git.ben.knoble@gmail.com","subject":"[PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-14T12:34:02Z","receivedAt":"2026-08-14T12:35:23Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about it don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nDue to the conversion from #ifdef to runtime check, using the flag\n\"--ignore-space-change\" may be particularly helpful when viewing changes\nfrom this patch.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    CI: <https://github.com/benknoble/git/actions/runs/31701945211>\n\n Documentation/config/core.adoc        |  6 ++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         |  6 ++++++\n environment.h                         |  1 +\n read-cache.c                          | 16 ++++++++--------\n statinfo.c                            | 14 +++++++-------\n 10 files changed, 36 insertions(+), 39 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..33104444ab 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,12 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisions between the index and the working tree (if Git\n+\twas compiled to store it).\n+\tSee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..8e0c25655f 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is defined. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..e6a50060e8 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +774,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+\tcfg->use_nanosec = 0;\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..abecdf0342 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -353,15 +353,15 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n+\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n+\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n-#else\n-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n-#endif\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\tuse_nsec\n+\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n \t\t);\n }\n \ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..d9ddcf9382 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n-#endif\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n \n \tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n-- \n2.55.0.699.gb54405d56f.dirty\n\n"},{"id":"550622","messageId":"xmqqzeyoodxk.fsf@gitster.g","threadId":"66138","inReplyTo":"2d1424732af6af9c82c775e8256ea914204e8e43.1786710807.git.ben.knoble@gmail.com","subject":"Re: [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-14T16:38:15Z","receivedAt":"2026-08-14T16:38:17Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> -#ifdef USE_NSEC\n> -\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n> -\t\tchanged |= MTIME_CHANGED;\n> -\tif (cfg->trust_ctime && cfg->check_stat &&\n> -\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n> -\t\tchanged |= CTIME_CHANGED;\n> -#endif\n> +\tif (cfg->use_nanosec) {\n> +\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n> +\t\t\tchanged |= MTIME_CHANGED;\n> +\t\tif (cfg->trust_ctime && cfg->check_stat &&\n> +\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n> +\t\t\tchanged |= CTIME_CHANGED;\n> +\t}\n>  \n>  \tif (cfg->check_stat) {\n>  \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n\nThis is iffy.\n\nIf you have core.usenanosec=true in a networked $HOME/.gitconfig\nmounted on both USE_NSEC-capable and incapable platforms, what would\nST_CTIME_NSEC() yield on the latter?  I wonder if cfg's\n'.use_nanosec' should be force-disabled in NO_NSEC builds, or\nsomething similar?\n"},{"id":"550639","messageId":"CALnO6CA96y0g9iy+GRMV1v86zk3eKpCKxeJWid=097sFNXEknA@mail.gmail.com","threadId":"66138","inReplyTo":"xmqqzeyoodxk.fsf@gitster.g","subject":"Re: [PATCH v2 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-14T19:03:54Z","receivedAt":"2026-08-14T19:04:07Z","isPatch":true,"body":"On Fri, Aug 14, 2026 at 12:38 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> > -#ifdef USE_NSEC\n> > -     if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n> > -             changed |= MTIME_CHANGED;\n> > -     if (cfg->trust_ctime && cfg->check_stat &&\n> > -         sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n> > -             changed |= CTIME_CHANGED;\n> > -#endif\n> > +     if (cfg->use_nanosec) {\n> > +             if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n> > +                     changed |= MTIME_CHANGED;\n> > +             if (cfg->trust_ctime && cfg->check_stat &&\n> > +                 sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n> > +                     changed |= CTIME_CHANGED;\n> > +     }\n> >\n> >       if (cfg->check_stat) {\n> >               if (sd->sd_uid != (unsigned int) st->st_uid ||\n>\n> This is iffy.\n>\n> If you have core.usenanosec=true in a networked $HOME/.gitconfig\n> mounted on both USE_NSEC-capable and incapable platforms, what would\n> ST_CTIME_NSEC() yield on the latter?\n\nPerhaps \"if it hurts, don't do that\"? This config is definitely about\nexposing the underlying system's capabilities to Git, so if you cannot\nconfidently do so globally, you probably shouldn't. That might limit\nthe usefulness of the optimization for folks that share filesystems\nbetween multiple machines in this way, I suppose. Or maybe it will\nincentivize folks to be nsec-compatible in more places ;) Either way,\nusers that can benefit from it will have the option.\n\n> I wonder if cfg's\n> '.use_nanosec' should be force-disabled in NO_NSEC builds, or\n> something similar?\n\nThis does, however, make some sense to me:\n\n- Git today with NO_NSEC doesn't bother with the USE_NSEC paths, since\nwe #undef USE_NSEC in that case.\n- Git \"tomorrow\" should probably say \"I was built with NO_NSEC, so I\nwill (continue) ignoring platform-specific nanosecond optimizations.\"\n\nI'll queue this change locally until I send out the next version,\nunless someone objects.\n\n-- \nD. Ben Knoble\n"},{"id":"550759","messageId":"cover.1787065125.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786103607.git.ben.knoble@gmail.com","subject":"[PATCH v3 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-18T14:59:44Z","receivedAt":"2026-08-18T15:00:22Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime (applied)\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v3:\n\n- #ifdef out use_nanosec when NO_NSEC is requested\n\nAs I have heard no comments about the \"Todo\" lines below, which perhaps\ncould more clearly be marked \"RFC\"/\"RFH\", I've added this line to call\nthem out ;) and renamed them \"Comments welcome\"\n\nChanges in v2:\n\n- move Best-viewed-with trailer into message body as descriptive\n  text.\n- read core.useNanosec through struct repo instead of parsing\n  config strings. The test suite passes locally this way, though that\n  skipped 151 tests.\n    - CI run: https://github.com/benknoble/git/actions/runs/31701945211\n\nOriginal cover letter:\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n- The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n- The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n- The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nComments welcome: I haven't touched any tests; I saw a bunch of hits for\n\"git grep racy t\" but wasn't sure how to fit this particular change in,\nespecially since it won't be equally valid on all systems? Advice\nwelcome.\n\nComments welcome: I wonder if \"useNanosec\" paints us into too much of a\ncorner; that is (slightly more abstractly), we are using *extended\nprecision* in the index. Maybe the name and documentation should reflect\nthat, so we aren't too committed to \"nanoseconds\"?\n    - Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    - Some could offer precision _beyond_ nanoseconds\n\nidk.\n\nv1: <cover.1786103607.git.ben.knoble@gmail.com>\nv2: <cover.1786710807.git.ben.knoble@gmail.com>\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  6 ++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 +++++-----\n Makefile                              | 12 +----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 29 ++++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 16 ++++++++++-----\n statinfo.c                            | 14 +++++++------\n 12 files changed, 64 insertions(+), 43 deletions(-)\n\nDiff-intervalle contre v2 :\n1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n2:  5693baa992 = 2:  5693baa992 environment: align repo_config_values_init with struct declaration\n3:  2d1424732a ! 3:  48fceb4b57 core: convert build-time USE_NSEC into runtime core.useNanosec\n    @@ Commit message\n     \n      ## Notes (benknoble/commits) ##\n         Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    -    CI: <https://github.com/benknoble/git/actions/runs/31701945211>\n    +    CI: <https://github.com/benknoble/git/actions/runs/32137191115>\n    +\n    +    v3:\n    +        We could perhaps be cute in read-cache.c:is_racy_stat() by writing\n    +        the preprocessor directive like\n    +\n    +    \t\treturn (istate->timestamp.sec &&\n    +    \t#ifndef NO_NSEC\n    +    \t\t\t/* nanosecond timestamped files can also be racy! */\n    +    \t\t\tuse_nsec\n    +    \t\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n    +    \t\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n    +    \t\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    +    \t\t\t:\n    +    \t#endif\n    +    \t\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    +\n    +        but that seemed maybe too clever?\n     \n      ## Documentation/config/core.adoc ##\n     @@ Documentation/config/core.adoc: core.trustctime::\n    @@ environment.c: int git_default_core_config(const char *var, const char *value,\n      \t\treturn 0;\n      \t}\n      \n    ++#ifndef NO_NSEC\n     +\tif (!strcmp(var, \"core.usenanosec\")) {\n     +\t\tcfg->use_nanosec = git_config_bool(var, value);\n     +\t\treturn 0;\n     +\t}\n    ++#endif\n     +\n      \t/* Add other config variables here and to Documentation/config.adoc. */\n      \treturn platform_core_config(var, value, ctx, cb);\n    @@ environment.c: void repo_config_values_init(struct repo_config_values *cfg)\n      \tcfg->ignore_case = 0;\n      \tcfg->trust_executable_bit = 1;\n      \tcfg->has_symlinks = platform_has_symlinks();\n    ++#ifndef NO_NSEC\n     +\tcfg->use_nanosec = 0;\n    ++#endif\n      \n      \t/* section \"sparse\" config values */\n      \tcfg->sparse_expect_files_outside_of_patterns = 0;\n    @@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struc\n      static int is_racy_stat(const struct index_state *istate,\n      \t\t\tconst struct stat_data *sd)\n      {\n    ++#ifndef NO_NSEC\n     +\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n    ++#endif\n     +\n      \treturn (istate->timestamp.sec &&\n     -#ifdef USE_NSEC\n    @@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struc\n     -\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n     -\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n     -\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    --#else\n    --\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    --#endif\n    ++#ifndef NO_NSEC\n     +\t\t/* nanosecond timestamped files can also be racy! */\n     +\t\tuse_nsec\n     +\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n     +\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n     +\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n     +\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n    - \t\t);\n    - }\n    - \n    + #else\n    + \t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    + #endif\n     \n      ## statinfo.c ##\n     @@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)\n    @@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)\n     -\tif (cfg->trust_ctime && cfg->check_stat &&\n     -\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n     -\t\tchanged |= CTIME_CHANGED;\n    --#endif\n    ++#ifndef NO_NSEC\n     +\tif (cfg->use_nanosec) {\n     +\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n     +\t\t\tchanged |= MTIME_CHANGED;\n    @@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)\n     +\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n     +\t\t\tchanged |= CTIME_CHANGED;\n     +\t}\n    + #endif\n      \n      \tif (cfg->check_stat) {\n    - \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550760","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1787065125.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787065125.git.ben.knoble@gmail.com","subject":"[PATCH v3 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-18T14:59:45Z","receivedAt":"2026-08-18T15:00:29Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550761","messageId":"5693baa9923afd20333c0eb016cc5949f8dfc423.1787065125.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787065125.git.ben.knoble@gmail.com","subject":"[PATCH v3 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-18T14:59:46Z","receivedAt":"2026-08-18T15:00:31Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially when comparing with the struct definition to\nensure all members are initialized. As new members will be added in the\nfuture, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550762","messageId":"48fceb4b575ca39346cf2f59f621584a19049008.1787065125.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787065125.git.ben.knoble@gmail.com","subject":"[PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-18T14:59:47Z","receivedAt":"2026-08-18T15:00:37Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about it don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nDue to the conversion from #ifdef to runtime check, using the flag\n\"--ignore-space-change\" may be particularly helpful when viewing changes\nfrom this patch.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    CI: <https://github.com/benknoble/git/actions/runs/32137191115>\n    \n    v3:\n        We could perhaps be cute in read-cache.c:is_racy_stat() by writing\n        the preprocessor directive like\n    \n    \t\treturn (istate->timestamp.sec &&\n    \t#ifndef NO_NSEC\n    \t\t\t/* nanosecond timestamped files can also be racy! */\n    \t\t\tuse_nsec\n    \t\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n    \t\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n    \t\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    \t\t\t:\n    \t#endif\n    \t\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    \n        but that seemed maybe too clever?\n\n Documentation/config/core.adoc        |  6 ++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 10 ++++++++++\n environment.h                         |  1 +\n read-cache.c                          | 16 +++++++++++-----\n statinfo.c                            | 14 ++++++++------\n 10 files changed, 44 insertions(+), 35 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..33104444ab 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,12 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisions between the index and the working tree (if Git\n+\twas compiled to store it).\n+\tSee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..8e0c25655f 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is defined. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..c7f6b801f4 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+#ifndef NO_NSEC\n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+#endif\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+#ifndef NO_NSEC\n+\tcfg->use_nanosec = 0;\n+#endif\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..31888f77ee 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n+#ifndef NO_NSEC\n+\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n+#endif\n+\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+#ifndef NO_NSEC\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\tuse_nsec\n+\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n #else\n \t\tistate->timestamp.sec <= sd->sd_mtime.sec\n #endif\ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..2f2cec6282 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,12 +72,14 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n+#ifndef NO_NSEC\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n #endif\n \n \tif (cfg->check_stat) {\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550772","messageId":"xmqqh5krxnwd.fsf@gitster.g","threadId":"66138","inReplyTo":"48fceb4b575ca39346cf2f59f621584a19049008.1787065125.git.ben.knoble@gmail.com","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-18T18:51:46Z","receivedAt":"2026-08-18T18:51:48Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> diff --git a/environment.c b/environment.c\n> index 6676e6f5ae..c7f6b801f4 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\treturn 0;\n>  \t}\n>  \n> +#ifndef NO_NSEC\n> +\tif (!strcmp(var, \"core.usenanosec\")) {\n> +\t\tcfg->use_nanosec = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n> +#endif\n\nWhat this hunk tells us: At build time, you could choose to ignore\ncore.usenanosec configuration variable, preventing cfg->use_nanosec\nfrom getting flipped to true by the configured value.\n\n> @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>  \tcfg->ignore_case = 0;\n>  \tcfg->trust_executable_bit = 1;\n>  \tcfg->has_symlinks = platform_has_symlinks();\n> +#ifndef NO_NSEC\n> +\tcfg->use_nanosec = 0;\n> +#endif\n\nI think we want to unconditionally initialize it to 0, unless the\ndefinition of the .use_nanosec member itself in the structure is\nconditional on NO_NSEC.  And ...\n\n>  \n>  \t/* section \"sparse\" config values */\n>  \tcfg->sparse_expect_files_outside_of_patterns = 0;\n> diff --git a/environment.h b/environment.h\n> index e7ec5b0437..a35534afe5 100644\n> --- a/environment.h\n> +++ b/environment.h\n> @@ -139,6 +139,7 @@ struct repo_config_values {\n>  \tint ignore_case;\n>  \tint trust_executable_bit;\n>  \tint has_symlinks;\n> +\tint use_nanosec;\n\n... that is not the case.  \n\nWhich means that git_default_core_config() does keep the initial\nvalue of the member without getting affected by the configuration,\nbut it does not necessarily be keeping \"false\".  It may be keeping\nthe uninitialized state instead ;-).\n\n> diff --git a/read-cache.c b/read-cache.c\n> index 6c449f393d..31888f77ee 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n>  static int is_racy_stat(const struct index_state *istate,\n>  \t\t\tconst struct stat_data *sd)\n>  {\n> +#ifndef NO_NSEC\n> +\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n> +#endif\n> +\n>  \treturn (istate->timestamp.sec &&\n> -#ifdef USE_NSEC\n> -\t\t /* nanosecond timestamped files can also be racy! */\n> -\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n> -\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n> -\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> +#ifndef NO_NSEC\n> +\t\t/* nanosecond timestamped files can also be racy! */\n> +\t\tuse_nsec\n> +\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> +\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n> +\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> +\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n>  #else\n>  \t\tistate->timestamp.sec <= sd->sd_mtime.sec\n>  #endif\n\nUgly.  How about getting rid of the latter #ifndef/#else/#endif and\ninstead keeping the \"if use_nsec, pay attention to nsec, otherwise\nonly the seconds part\" ternary?  As to the early part, as you can\narrange cfg's '.use_nanosec' to always hold a sensible value, the\nfunction can become\n\n        return (istate->timestamp.sec &&\n                (repo_config_values(istate->repo)->use_nanosec\n                 ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n                   (istate->timestamp.sec == sd->sd_mtime.sec &&\n                    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n                 : istate->timestamp.sec <= sd->sd_mtime.sec));\n\nI think.\n\nThe code you presented here for is_racy_stat() sprinkled with\n#ifndef/#else/#endif would be sensible if repo_config_values struct\ndefined the '.use_nanosec' member conditionally.  But that is not\nwhat is happening here.\n"},{"id":"550791","messageId":"aoVoJ3Ijoaj3u64e@pks.im","threadId":"66138","inReplyTo":"48fceb4b575ca39346cf2f59f621584a19049008.1787065125.git.ben.knoble@gmail.com","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-19T08:24:07Z","receivedAt":"2026-08-19T08:24:15Z","isPatch":true,"body":"On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:\n> Racy Git problems persist today, manifesting themselves in the\n> performance of commands like \"git diff\" in new worktrees [1]. We have\n> long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n> precision when available, which mitigates most if not all racy issues,\n> but most builds we know about it don't use it. In part, that's because\n\ns/about it/about/\n\n> diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\n> index 340329edc3..33104444ab 100644\n> --- a/Documentation/config/core.adoc\n> +++ b/Documentation/config/core.adoc\n> @@ -118,6 +118,12 @@ core.trustctime::\n>  \tcrawlers and some backup systems).\n>  \tSee linkgit:git-update-index[1]. True by default.\n>  \n> +core.useNanosec::\n> +\tIf true, use nanosecond precision for ctime and mtime\n> +\tcomparisions between the index and the working tree (if Git\n> +\twas compiled to store it).\n> +\tSee link:technical/racy-git.html[Racy Git]. False by default.\n\nShould we mentino here that this may not be safe on all platforms and/or\nfilesystems, in addition to linking to racy-hit?\n\nAnd do we really want to link to the HTML page here? The user may be\nreading a manpage, so doing so feels a bit weird to me.\n\n> diff --git a/environment.c b/environment.c\n> index 6676e6f5ae..c7f6b801f4 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\treturn 0;\n>  \t}\n>  \n> +#ifndef NO_NSEC\n> +\tif (!strcmp(var, \"core.usenanosec\")) {\n> +\t\tcfg->use_nanosec = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n> +#endif\n\nDo we want to omit a warning in case the config is enabled and we have\nNO_SEC set? Or would that be too obnoxious?\n\n> @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>  \tcfg->ignore_case = 0;\n>  \tcfg->trust_executable_bit = 1;\n>  \tcfg->has_symlinks = platform_has_symlinks();\n> +#ifndef NO_NSEC\n> +\tcfg->use_nanosec = 0;\n> +#endif\n\nCan't we set this unconditionally? The respective field exists\nunconditionally, too.\n\n> diff --git a/read-cache.c b/read-cache.c\n> index 6c449f393d..31888f77ee 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n>  static int is_racy_stat(const struct index_state *istate,\n>  \t\t\tconst struct stat_data *sd)\n>  {\n> +#ifndef NO_NSEC\n> +\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n> +#endif\n> +\n>  \treturn (istate->timestamp.sec &&\n> -#ifdef USE_NSEC\n> -\t\t /* nanosecond timestamped files can also be racy! */\n> -\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n> -\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n> -\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> +#ifndef NO_NSEC\n> +\t\t/* nanosecond timestamped files can also be racy! */\n> +\t\tuse_nsec\n> +\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> +\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n> +\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> +\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n>  #else\n>  \t\tistate->timestamp.sec <= sd->sd_mtime.sec\n>  #endif\n\nI think this would be a bit more readable if we had a single NO_NSEC\nblock.\n\n> diff --git a/statinfo.c b/statinfo.c\n> index 5e00af127d..2f2cec6282 100644\n> --- a/statinfo.c\n> +++ b/statinfo.c\n> @@ -72,12 +72,14 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n>  \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n>  \t\tchanged |= CTIME_CHANGED;\n>  \n> -#ifdef USE_NSEC\n> -\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n> -\t\tchanged |= MTIME_CHANGED;\n> -\tif (cfg->trust_ctime && cfg->check_stat &&\n> -\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n> -\t\tchanged |= CTIME_CHANGED;\n> +#ifndef NO_NSEC\n> +\tif (cfg->use_nanosec) {\n> +\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n> +\t\t\tchanged |= MTIME_CHANGED;\n> +\t\tif (cfg->trust_ctime && cfg->check_stat &&\n> +\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n> +\t\t\tchanged |= CTIME_CHANGED;\n> +\t}\n>  #endif\n\nThere's one more site in \"builtin/update-index.c\" where we mention\nUSE_NSEC that wasn't updated as part of this patch.\n\nThanks!\n\nPatrick\n"},{"id":"550812","messageId":"CALnO6CAZ-_k=+xTZwi-+s2aeKwgkoY5Z_iJjF6_sBDreKEsTaw@mail.gmail.com","threadId":"66138","inReplyTo":"xmqqh5krxnwd.fsf@gitster.g","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-19T12:53:18Z","receivedAt":"2026-08-19T12:53:32Z","isPatch":true,"body":"[Patrick, the below probably helps answer some of your questions as well.]\n\nOn Tue, Aug 18, 2026 at 2:51 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> > diff --git a/environment.c b/environment.c\n> > index 6676e6f5ae..c7f6b801f4 100644\n> > --- a/environment.c\n> > +++ b/environment.c\n> > @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n> >               return 0;\n> >       }\n> >\n> > +#ifndef NO_NSEC\n> > +     if (!strcmp(var, \"core.usenanosec\")) {\n> > +             cfg->use_nanosec = git_config_bool(var, value);\n> > +             return 0;\n> > +     }\n> > +#endif\n>\n> What this hunk tells us: At build time, you could choose to ignore\n> core.usenanosec configuration variable, preventing cfg->use_nanosec\n> from getting flipped to true by the configured value.\n>\n> > @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)\n> >       cfg->ignore_case = 0;\n> >       cfg->trust_executable_bit = 1;\n> >       cfg->has_symlinks = platform_has_symlinks();\n> > +#ifndef NO_NSEC\n> > +     cfg->use_nanosec = 0;\n> > +#endif\n>\n> I think we want to unconditionally initialize it to 0, unless the\n> definition of the .use_nanosec member itself in the structure is\n> conditional on NO_NSEC.  And ...\n>\n> >\n> >       /* section \"sparse\" config values */\n> >       cfg->sparse_expect_files_outside_of_patterns = 0;\n> > diff --git a/environment.h b/environment.h\n> > index e7ec5b0437..a35534afe5 100644\n> > --- a/environment.h\n> > +++ b/environment.h\n> > @@ -139,6 +139,7 @@ struct repo_config_values {\n> >       int ignore_case;\n> >       int trust_executable_bit;\n> >       int has_symlinks;\n> > +     int use_nanosec;\n>\n> ... that is not the case.\n\nDoh! I actually intended to send this version with a compiled-out\nmember when NO_NSEC, since that was the only path I had come up with.\nNo point in running around with code that's been asked to be ignored,\neh? However…\n\n> Which means that git_default_core_config() does keep the initial\n> value of the member without getting affected by the configuration,\n> but it does not necessarily be keeping \"false\".  It may be keeping\n> the uninitialized state instead ;-).\n\n[ugly #ifdef trimmed]\n\n> Ugly.  How about getting rid of the latter #ifndef/#else/#endif and\n> instead keeping the \"if use_nsec, pay attention to nsec, otherwise\n> only the seconds part\" ternary?  As to the early part, as you can\n> arrange cfg's '.use_nanosec' to always hold a sensible value, the\n> function can become\n>\n>         return (istate->timestamp.sec &&\n>                 (repo_config_values(istate->repo)->use_nanosec\n>                  ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n>                    (istate->timestamp.sec == sd->sd_mtime.sec &&\n>                     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n>                  : istate->timestamp.sec <= sd->sd_mtime.sec));\n>\n> I think.\n>\n> The code you presented here for is_racy_stat() sprinkled with\n> #ifndef/#else/#endif would be sensible if repo_config_values struct\n> defined the '.use_nanosec' member conditionally.  But that is not\n> what is happening here.\n\n…I now see a world where we could avoid quite a bit of headache:\n\n- use #if[n]def NO_NSEC to ignore the config variable, but otherwise\n- unconditionally compile the cfg->use_nanosec checks\n\nThat is, future readers/writers won't have to remember that they can\nonly use the use_nanosec member under compiler conditionals; it will\nalways be initialized to a safe value (either always false or from\nconfig). If we're lucky, the compiler will optimize the checks away in\nNO_NSEC builds ;)\n\nI think this is what you are suggesting Junio, so let me see what I\ncan come up with.\n\n-- \nD. Ben Knoble\n"},{"id":"550814","messageId":"CALnO6CDgfT+VXaBqSmStB8vNOwBpr5XMjvmxhMdc7v-ma-YwXg@mail.gmail.com","threadId":"66138","inReplyTo":"aoVoJ3Ijoaj3u64e@pks.im","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-19T13:09:59Z","receivedAt":"2026-08-19T13:10:12Z","isPatch":true,"body":"On Wed, Aug 19, 2026 at 4:24 AM Patrick Steinhardt <ps@pks.im> wrote:\n>\n> On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:\n> > Racy Git problems persist today, manifesting themselves in the\n> > performance of commands like \"git diff\" in new worktrees [1]. We have\n> > long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n> > precision when available, which mitigates most if not all racy issues,\n> > but most builds we know about it don't use it. In part, that's because\n>\n> s/about it/about/\n\nThanks; fixed locally.\n\n> > diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\n> > index 340329edc3..33104444ab 100644\n> > --- a/Documentation/config/core.adoc\n> > +++ b/Documentation/config/core.adoc\n> > @@ -118,6 +118,12 @@ core.trustctime::\n> >       crawlers and some backup systems).\n> >       See linkgit:git-update-index[1]. True by default.\n> >\n> > +core.useNanosec::\n> > +     If true, use nanosecond precision for ctime and mtime\n> > +     comparisions between the index and the working tree (if Git\n> > +     was compiled to store it).\n> > +     See link:technical/racy-git.html[Racy Git]. False by default.\n>\n> Should we mentino here that this may not be safe on all platforms and/or\n> filesystems, in addition to linking to racy-hit?\n\nYeah, a brief mention here is probably warranted.\n\n> And do we really want to link to the HTML page here? The user may be\n> reading a manpage, so doing so feels a bit weird to me.\n\nSee a variation on the grep done in patch 1; we link lots of HTML\ndocumentation in our manuals (including when rendered to manpage\nformat).\n\nAFAICT, the idea is that we produce manual pages for commands and a\nfew other \"special\" documents; we produce HTML of everything. So there\nisn't a good non-HTML link target for, e.g., the Racy Git document. In\nparticular, even \"git help\" doesn't know about Racy Git. I have a\nscript [1] that opens files out of \"git --html-path\", so that provides\none way to access the Racy Git document (aside: neither of my\nsystems---Homebrew macOS or Portage Gentoo---install anything into\n\"git --info-path\", so that would not make a good link target even if I\nknew how to write it). Patch 1/3 makes it easier to get the correct\nlink in the manual for folks who can click links in their terminal\nemulators (or copy-paste).\n\n[1]: https://github.com/benknoble/Dotfiles/tree/master/links/bin/git-doc\n(with completion!\nhttps://github.com/benknoble/Dotfiles/tree/master/links/zshfns/_git_doc)\n\nTBH, I am not sure what other folks do for these HTML links in\nmanuals. As I mention in patch 1, the Homebrew links are broken. If\nyou know about \"git --html-path\" you can find the documents, or use\nthe Git SCM website's rendered versions.\n\nAnyway, this is the current \"normal\" style for linking, I think.\n\n> > diff --git a/environment.c b/environment.c\n> > index 6676e6f5ae..c7f6b801f4 100644\n> > --- a/environment.c\n> > +++ b/environment.c\n> > @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n> >               return 0;\n> >       }\n> >\n> > +#ifndef NO_NSEC\n> > +     if (!strcmp(var, \"core.usenanosec\")) {\n> > +             cfg->use_nanosec = git_config_bool(var, value);\n> > +             return 0;\n> > +     }\n> > +#endif\n>\n> Do we want to omit a warning in case the config is enabled and we have\n> NO_SEC set? Or would that be too obnoxious?\n\nI would say that can always be done later ;) Perhaps it should be\nbetter documented, though, so let me try that, too.\n\n>\n> > @@ -769,6 +776,9 @@ void repo_config_values_init(struct repo_config_values *cfg)\n> >       cfg->ignore_case = 0;\n> >       cfg->trust_executable_bit = 1;\n> >       cfg->has_symlinks = platform_has_symlinks();\n> > +#ifndef NO_NSEC\n> > +     cfg->use_nanosec = 0;\n> > +#endif\n>\n> Can't we set this unconditionally? The respective field exists\n> unconditionally, too.\n\nYep, see reply to Junio.\n\n> > diff --git a/read-cache.c b/read-cache.c\n> > index 6c449f393d..31888f77ee 100644\n> > --- a/read-cache.c\n> > +++ b/read-cache.c\n> > @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n> >  static int is_racy_stat(const struct index_state *istate,\n> >                       const struct stat_data *sd)\n> >  {\n> > +#ifndef NO_NSEC\n> > +     int use_nsec = repo_config_values(istate->repo)->use_nanosec;\n> > +#endif\n> > +\n> >       return (istate->timestamp.sec &&\n> > -#ifdef USE_NSEC\n> > -              /* nanosecond timestamped files can also be racy! */\n> > -             (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > -              (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > -               istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > +#ifndef NO_NSEC\n> > +             /* nanosecond timestamped files can also be racy! */\n> > +             use_nsec\n> > +             ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > +                (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > +                 istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > +             : istate->timestamp.sec <= sd->sd_mtime.sec\n> >  #else\n> >               istate->timestamp.sec <= sd->sd_mtime.sec\n> >  #endif\n>\n> I think this would be a bit more readable if we had a single NO_NSEC\n> block.\n\nI'm not sure what \"single block\" means here, but I think the plan (see\nreply to Junio) is to make this more readable by not needing\npre-processor directives at all.\n\n[snip]\n\n> There's one more site in \"builtin/update-index.c\" where we mention\n> USE_NSEC that wasn't updated as part of this patch.\n\nOh, did I miss one? The only spot I saw in builtin/update-index.c that\nmentions USE_NSEC is a comment that I'm sure patch 3 updated. Maybe\nyou were thinking of that, or maybe you know of something I left out?\n(That is, locally on this branch, \"git grep USE_NSEC\" returns one hit\nin Documentation/RelNotes/2.5.0.adoc.)\n\nThanks!\n\n-- \nD. Ben Knoble\n"},{"id":"550827","messageId":"xmqq8q62w0gf.fsf@gitster.g","threadId":"66138","inReplyTo":"aoVoJ3Ijoaj3u64e@pks.im","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-19T16:15:44Z","receivedAt":"2026-08-19T16:15:47Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n>> diff --git a/environment.c b/environment.c\n>> index 6676e6f5ae..c7f6b801f4 100644\n>> --- a/environment.c\n>> +++ b/environment.c\n>> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n>>  \t\treturn 0;\n>>  \t}\n>>  \n>> +#ifndef NO_NSEC\n>> +\tif (!strcmp(var, \"core.usenanosec\")) {\n>> +\t\tcfg->use_nanosec = git_config_bool(var, value);\n>> +\t\treturn 0;\n>> +\t}\n>> +#endif\n>\n> Do we want to omit a warning in case the config is enabled and we have\n> NO_SEC set? Or would that be too obnoxious?\n\nThose who use a $HOME/.gitconfig shared across two machines with\ndifferent builds would be annoyed with one of them constantly\ncomplaining, I am afraid.\n"},{"id":"550856","messageId":"CALnO6CBmJ3AyaSmHNmOm=aKC5Atp+VWGRTxCpN=ztmvU_xbBMA@mail.gmail.com","threadId":"66138","inReplyTo":"xmqq8q62w0gf.fsf@gitster.g","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-19T22:56:57Z","receivedAt":"2026-08-19T22:57:09Z","isPatch":true,"body":"On Wed, Aug 19, 2026 at 12:15 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Patrick Steinhardt <ps@pks.im> writes:\n>\n> >> diff --git a/environment.c b/environment.c\n> >> index 6676e6f5ae..c7f6b801f4 100644\n> >> --- a/environment.c\n> >> +++ b/environment.c\n> >> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n> >>              return 0;\n> >>      }\n> >>\n> >> +#ifndef NO_NSEC\n> >> +    if (!strcmp(var, \"core.usenanosec\")) {\n> >> +            cfg->use_nanosec = git_config_bool(var, value);\n> >> +            return 0;\n> >> +    }\n> >> +#endif\n> >\n> > Do we want to omit a warning in case the config is enabled and we have\n> > NO_SEC set? Or would that be too obnoxious?\n>\n> Those who use a $HOME/.gitconfig shared across two machines with\n> different builds would be annoyed with one of them constantly\n> complaining, I am afraid.\n\nAh, that reminds me; my shared ~/.gitconfig includes a \"site-local\"\nconfig path, which could then be used to set this option (or not) only\nwhere supported.\n\n-- \nD. Ben Knoble\n"},{"id":"550860","messageId":"aoaPn0gaHIa9Utwu@pks.im","threadId":"66138","inReplyTo":"CALnO6CDgfT+VXaBqSmStB8vNOwBpr5XMjvmxhMdc7v-ma-YwXg@mail.gmail.com","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-20T05:24:47Z","receivedAt":"2026-08-20T05:24:55Z","isPatch":true,"body":"On Wed, Aug 19, 2026 at 09:09:59AM -0400, D. Ben Knoble wrote:\n> On Wed, Aug 19, 2026 at 4:24 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:\n> > > diff --git a/read-cache.c b/read-cache.c\n> > > index 6c449f393d..31888f77ee 100644\n> > > --- a/read-cache.c\n> > > +++ b/read-cache.c\n> > > @@ -353,12 +353,18 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n> > >  static int is_racy_stat(const struct index_state *istate,\n> > >                       const struct stat_data *sd)\n> > >  {\n> > > +#ifndef NO_NSEC\n> > > +     int use_nsec = repo_config_values(istate->repo)->use_nanosec;\n> > > +#endif\n> > > +\n> > >       return (istate->timestamp.sec &&\n> > > -#ifdef USE_NSEC\n> > > -              /* nanosecond timestamped files can also be racy! */\n> > > -             (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > > -              (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > > -               istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > > +#ifndef NO_NSEC\n> > > +             /* nanosecond timestamped files can also be racy! */\n> > > +             use_nsec\n> > > +             ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > > +                (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > > +                 istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > > +             : istate->timestamp.sec <= sd->sd_mtime.sec\n> > >  #else\n> > >               istate->timestamp.sec <= sd->sd_mtime.sec\n> > >  #endif\n> >\n> > I think this would be a bit more readable if we had a single NO_NSEC\n> > block.\n> \n> I'm not sure what \"single block\" means here, but I think the plan (see\n> reply to Junio) is to make this more readable by not needing\n> pre-processor directives at all.\n\nThat'd be quite welcome indeed. The less ifdeffery the bettery. :)\n\n> > There's one more site in \"builtin/update-index.c\" where we mention\n> > USE_NSEC that wasn't updated as part of this patch.\n> \n> Oh, did I miss one? The only spot I saw in builtin/update-index.c that\n> mentions USE_NSEC is a comment that I'm sure patch 3 updated. Maybe\n> you were thinking of that, or maybe you know of something I left out?\n> (That is, locally on this branch, \"git grep USE_NSEC\" returns one hit\n> in Documentation/RelNotes/2.5.0.adoc.)\n\nOh, I guess I just missed it because I already trimmed context of this\nmail. Never mind then.\n\nPatrick\n"},{"id":"550862","messageId":"aoaP7oIrR_Bpvx34@pks.im","threadId":"66138","inReplyTo":"xmqq8q62w0gf.fsf@gitster.g","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-20T05:26:06Z","receivedAt":"2026-08-20T05:26:12Z","isPatch":true,"body":"On Wed, Aug 19, 2026 at 09:15:44AM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> >> diff --git a/environment.c b/environment.c\n> >> index 6676e6f5ae..c7f6b801f4 100644\n> >> --- a/environment.c\n> >> +++ b/environment.c\n> >> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n> >>  \t\treturn 0;\n> >>  \t}\n> >>  \n> >> +#ifndef NO_NSEC\n> >> +\tif (!strcmp(var, \"core.usenanosec\")) {\n> >> +\t\tcfg->use_nanosec = git_config_bool(var, value);\n> >> +\t\treturn 0;\n> >> +\t}\n> >> +#endif\n> >\n> > Do we want to omit a warning in case the config is enabled and we have\n> > NO_SEC set? Or would that be too obnoxious?\n> \n> Those who use a $HOME/.gitconfig shared across two machines with\n> different builds would be annoyed with one of them constantly\n> complaining, I am afraid.\n\nYeah, that's what I was hinting at with \"too obnovious\". So I agree,\nlet's not add one.\n\nPatrick\n"},{"id":"550895","messageId":"CALnO6CAa0HKsKoytzfXvEmps4NLtx5qFkP9B4PZzW_Rfun+CNQ@mail.gmail.com","threadId":"66138","inReplyTo":"aoaPn0gaHIa9Utwu@pks.im","subject":"Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-20T11:50:58Z","receivedAt":"2026-08-20T11:51:10Z","isPatch":true,"body":"On Thu, Aug 20, 2026 at 1:24 AM Patrick Steinhardt <ps@pks.im> wrote:\n>\n> That'd be quite welcome indeed. The less ifdeffery the bettery. :)\n\nAgreed!\n\n> On Wed, Aug 19, 2026 at 09:09:59AM -0400, D. Ben Knoble wrote:\n> > On Wed, Aug 19, 2026 at 4:24 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > > There's one more site in \"builtin/update-index.c\" where we mention\n> > > USE_NSEC that wasn't updated as part of this patch.\n> >\n> > Oh, did I miss one? The only spot I saw in builtin/update-index.c that\n> > mentions USE_NSEC is a comment that I'm sure patch 3 updated. Maybe\n> > you were thinking of that, or maybe you know of something I left out?\n> > (That is, locally on this branch, \"git grep USE_NSEC\" returns one hit\n> > in Documentation/RelNotes/2.5.0.adoc.)\n>\n> Oh, I guess I just missed it because I already trimmed context of this\n> mail. Never mind then.\n>\n> Patrick\n\nNo worries, I appreciate the careful read!\n\n-- \nD. Ben Knoble\n"},{"id":"550899","messageId":"cover.1787231825.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1786103607.git.ben.knoble@gmail.com","subject":"[PATCH v4 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-20T13:18:06Z","receivedAt":"2026-08-20T13:18:33Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime (applied)\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v4:\n\n- fix message typo\n- change #ifdef strategy: only ignore the config variable.\n  Otherwise, use the use_nanosec member unconditionally. Also clarify\n  that config might be ignore depending on build options in the docs.\n- mention potential platform unsafety directly in config doc in\n  addition to the link to Racy Git\n\nChanges in v3:\n\n- #ifdef out use_nanosec when NO_NSEC is requested\n\nAs I have heard no comments about the \"Todo\" lines below, which perhaps\ncould more clearly be marked \"RFC\"/\"RFH\", I've added this line to call\nthem out ;) and renamed them \"Comments welcome\"\n\nChanges in v2:\n\n- move Best-viewed-with trailer into message body as descriptive\n  text.\n- read core.useNanosec through struct repo instead of parsing\n  config strings. The test suite passes locally this way, though that\n  skipped 151 tests.\n    - CI run: https://github.com/benknoble/git/actions/runs/31701945211\n\nOriginal cover letter:\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n- The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n- The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n- The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nComments welcome: I haven't touched any tests; I saw a bunch of hits for\n\"git grep racy t\" but wasn't sure how to fit this particular change in,\nespecially since it won't be equally valid on all systems? Advice\nwelcome.\n\nComments welcome: I wonder if \"useNanosec\" paints us into too much of a\ncorner; that is (slightly more abstractly), we are using *extended\nprecision* in the index. Maybe the name and documentation should reflect\nthat, so we aren't too committed to \"nanoseconds\"?\n    - Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    - Some could offer precision _beyond_ nanoseconds\n\nidk.\n\nv1: <cover.1786103607.git.ben.knoble@gmail.com>\nv2: <cover.1786710807.git.ben.knoble@gmail.com>\nv3: <cover.1787065125.git.ben.knoble@gmail.com>\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 27 ++++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 12 files changed, 57 insertions(+), 48 deletions(-)\n\nDiff-intervalle contre v3 :\n1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n2:  5693baa992 = 2:  5693baa992 environment: align repo_config_values_init with struct declaration\n3:  48fceb4b57 ! 3:  0aa0e9fc17 core: convert build-time USE_NSEC into runtime core.useNanosec\n    @@ Commit message\n         performance of commands like \"git diff\" in new worktrees [1]. We have\n         long had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\n         precision when available, which mitigates most if not all racy issues,\n    -    but most builds we know about it don't use it. In part, that's because\n    +    but most builds we know about don't use it. In part, that's because\n         someone distributing Git can't safely enable it at compile-time if they\n         don't know exactly what platforms their distribution will be used on.\n     \n    @@ Commit message\n     \n      ## Notes (benknoble/commits) ##\n         Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    -    CI: <https://github.com/benknoble/git/actions/runs/32137191115>\n    -\n    -    v3:\n    -        We could perhaps be cute in read-cache.c:is_racy_stat() by writing\n    -        the preprocessor directive like\n    -\n    -    \t\treturn (istate->timestamp.sec &&\n    -    \t#ifndef NO_NSEC\n    -    \t\t\t/* nanosecond timestamped files can also be racy! */\n    -    \t\t\tuse_nsec\n    -    \t\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n    -    \t\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n    -    \t\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    -    \t\t\t:\n    -    \t#endif\n    -    \t\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    -\n    -        but that seemed maybe too clever?\n    +    CI: <https://github.com/benknoble/git/actions/runs/32365602564>\n     \n      ## Documentation/config/core.adoc ##\n     @@ Documentation/config/core.adoc: core.trustctime::\n    @@ Documentation/config/core.adoc: core.trustctime::\n     +core.useNanosec::\n     +\tIf true, use nanosecond precision for ctime and mtime\n     +\tcomparisions between the index and the working tree (if Git\n    -+\twas compiled to store it).\n    -+\tSee link:technical/racy-git.html[Racy Git]. False by default.\n    ++\twas compiled to respect this option).\n    ++\tThis is unsafe on some platforms;\n    ++\tsee link:technical/racy-git.html[Racy Git]. False by default.\n     +\n      core.splitIndex::\n      \tIf true, the split-index feature of the index will be used.\n    @@ environment.c: void repo_config_values_init(struct repo_config_values *cfg)\n      \tcfg->ignore_case = 0;\n      \tcfg->trust_executable_bit = 1;\n      \tcfg->has_symlinks = platform_has_symlinks();\n    -+#ifndef NO_NSEC\n     +\tcfg->use_nanosec = 0;\n    -+#endif\n      \n      \t/* section \"sparse\" config values */\n      \tcfg->sparse_expect_files_outside_of_patterns = 0;\n    @@ environment.h: struct repo_config_values {\n      \tint sparse_expect_files_outside_of_patterns;\n     \n      ## read-cache.c ##\n    -@@ read-cache.c: static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)\n    - static int is_racy_stat(const struct index_state *istate,\n    +@@ read-cache.c: static int is_racy_stat(const struct index_state *istate,\n      \t\t\tconst struct stat_data *sd)\n      {\n    -+#ifndef NO_NSEC\n    -+\tint use_nsec = repo_config_values(istate->repo)->use_nanosec;\n    -+#endif\n    -+\n      \treturn (istate->timestamp.sec &&\n     -#ifdef USE_NSEC\n     -\t\t /* nanosecond timestamped files can also be racy! */\n     -\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n     -\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n     -\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    -+#ifndef NO_NSEC\n    +-#else\n    +-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    +-#endif\n    +-\t\t);\n     +\t\t/* nanosecond timestamped files can also be racy! */\n    -+\t\tuse_nsec\n    -+\t\t? (istate->timestamp.sec < sd->sd_mtime.sec ||\n    -+\t\t   (istate->timestamp.sec == sd->sd_mtime.sec &&\n    -+\t\t    istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    -+\t\t: istate->timestamp.sec <= sd->sd_mtime.sec\n    - #else\n    - \t\tistate->timestamp.sec <= sd->sd_mtime.sec\n    - #endif\n    ++\t\t(repo_config_values(istate->repo)->use_nanosec\n    ++\t\t ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n    ++\t\t    (istate->timestamp.sec == sd->sd_mtime.sec &&\n    ++\t\t     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n    ++\t\t : istate->timestamp.sec <= sd->sd_mtime.sec));\n    + }\n    + \n    + int is_racy_timestamp(const struct index_state *istate,\n     \n      ## statinfo.c ##\n     @@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)\n    @@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)\n     -\tif (cfg->trust_ctime && cfg->check_stat &&\n     -\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n     -\t\tchanged |= CTIME_CHANGED;\n    -+#ifndef NO_NSEC\n    +-#endif\n     +\tif (cfg->use_nanosec) {\n     +\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n     +\t\t\tchanged |= MTIME_CHANGED;\n    @@ statinfo.c: int match_stat_data(const struct stat_data *sd, struct stat *st)\n     +\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n     +\t\t\tchanged |= CTIME_CHANGED;\n     +\t}\n    - #endif\n      \n      \tif (cfg->check_stat) {\n    + \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550900","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1787231825.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787231825.git.ben.knoble@gmail.com","subject":"[PATCH v4 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-20T13:18:07Z","receivedAt":"2026-08-20T13:18:34Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550901","messageId":"5693baa9923afd20333c0eb016cc5949f8dfc423.1787231825.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787231825.git.ben.knoble@gmail.com","subject":"[PATCH v4 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-20T13:18:08Z","receivedAt":"2026-08-20T13:18:35Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially when comparing with the struct definition to\nensure all members are initialized. As new members will be added in the\nfuture, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550902","messageId":"0aa0e9fc17a2b6ced3d12043091fe0d0e9b69cc3.1787231825.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787231825.git.ben.knoble@gmail.com","subject":"[PATCH v4 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-20T13:18:09Z","receivedAt":"2026-08-20T13:18:37Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nDue to the conversion from #ifdef to runtime check, using the flag\n\"--ignore-space-change\" may be particularly helpful when viewing changes\nfrom this patch.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    CI: <https://github.com/benknoble/git/actions/runs/32365602564>\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         |  8 ++++++++\n environment.h                         |  1 +\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 10 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..b793f62e42 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,13 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisions between the index and the working tree (if Git\n+\twas compiled to respect this option).\n+\tThis is unsafe on some platforms;\n+\tsee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..8e0c25655f 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is defined. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..c83cf44839 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+#ifndef NO_NSEC\n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+#endif\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+\tcfg->use_nanosec = 0;\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..b32cfd0ef1 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n-#else\n-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n-#endif\n-\t\t);\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\t(repo_config_values(istate->repo)->use_nanosec\n+\t\t ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t    (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t : istate->timestamp.sec <= sd->sd_mtime.sec));\n }\n \n int is_racy_timestamp(const struct index_state *istate,\ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..d9ddcf9382 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n-#endif\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n \n \tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"550923","messageId":"xmqqa4qgsn20.fsf@gitster.g","threadId":"66138","inReplyTo":"5693baa9923afd20333c0eb016cc5949f8dfc423.1787231825.git.ben.knoble@gmail.com","subject":"Re: [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-20T17:45:43Z","receivedAt":"2026-08-20T17:45:46Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> The order of assignments in repo_config_values_init is chaotic and hard\n> to follow, especially when comparing with the struct definition to\n> ensure all members are initialized. As new members will be added in the\n> future, make it easier to validate changes by aligning the two.\n>\n> Refactor assignment order with no behavioral changes.\n\nAfter reading the above three times, I am tempted to slightly tweak\nthe above:\n\n    ... comparing with the definition of 'struct repo_config_values' to\n    ensure ...\n\nOther than that, great improvement.\n\nThanks.\n\n\n\n>\n> Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n> ---\n>  environment.c | 19 ++++++++++++-------\n>  1 file changed, 12 insertions(+), 7 deletions(-)\n>\n> diff --git a/environment.c b/environment.c\n> index 76ee65e62b..6676e6f5ae 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n>  \n>  void repo_config_values_init(struct repo_config_values *cfg)\n>  {\n> +\t/* section \"core\" config values */\n>  \tcfg->attributes_file = NULL;\n>  \tcfg->excludes_file = NULL;\n>  \tcfg->editor_program = NULL;\n> @@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n>  \tcfg->autorebase = AUTOREBASE_NEVER;\n>  \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n>  \tcfg->apply_sparse_checkout = 0;\n> -\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n> -\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n> -\tcfg->ignore_case = 0;\n> -\tcfg->trust_executable_bit = 1;\n> -\tcfg->has_symlinks = platform_has_symlinks();\n> -\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n>  \tcfg->trust_ctime = 1;\n>  \tcfg->check_stat = 1;\n>  \tcfg->zlib_compression_level = Z_BEST_SPEED;\n>  \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n>  \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n>  \tcfg->core_sparse_checkout_cone = 0;\n> -\tcfg->sparse_expect_files_outside_of_patterns = 0;\n>  \tcfg->warn_on_object_refname_ambiguity = 1;\n> +\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n> +\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n> +\tcfg->ignore_case = 0;\n> +\tcfg->trust_executable_bit = 1;\n> +\tcfg->has_symlinks = platform_has_symlinks();\n> +\n> +\t/* section \"sparse\" config values */\n> +\tcfg->sparse_expect_files_outside_of_patterns = 0;\n> +\n> +\t/* section \"branch\" config values */\n> +\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n>  }\n>  \n>  void repo_config_values_clear(struct repo_config_values *cfg)\n"},{"id":"551003","messageId":"CALnO6CC-=0X2r6USab=6MBG-yWYrwrA6zEXnDC91P8q4WDeY8Q@mail.gmail.com","threadId":"66138","inReplyTo":"xmqqa4qgsn20.fsf@gitster.g","subject":"Re: [PATCH v4 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-21T12:10:22Z","receivedAt":"2026-08-21T12:10:36Z","isPatch":true,"body":"On Thu, Aug 20, 2026 at 1:45 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> > The order of assignments in repo_config_values_init is chaotic and hard\n> > to follow, especially when comparing with the struct definition to\n> > ensure all members are initialized. As new members will be added in the\n> > future, make it easier to validate changes by aligning the two.\n> >\n> > Refactor assignment order with no behavioral changes.\n>\n> After reading the above three times, I am tempted to slightly tweak\n> the above:\n>\n>     ... comparing with the definition of 'struct repo_config_values' to\n>     ensure ...\n>\n> Other than that, great improvement.\n>\n> Thanks.\n\nYep, that flows much better. Amended locally.\n\n-- \nD. Ben Knoble\n"},{"id":"551463","messageId":"cover.1788010335.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787231825.git.ben.knoble@gmail.com","subject":"[PATCH v5 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-29T13:38:17Z","receivedAt":"2026-08-29T13:38:30Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime (applied)\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v5:\n\n- improve message flow in patch 2\n\n    Junio: my apologies. I missed that the \"What's cooking\" changed from \"Needs\n    review\" (#10) to \"expecting a small (hopefully final) reroll\" (#11, #12),\n    since I was expecting to see Patrick's review. This just tweaks the commit\n    message as you suggested.\n\nChanges in v4:\n\n- fix message typo\n- change #ifdef strategy: only ignore the config variable.\n  Otherwise, use the use_nanosec member unconditionally. Also clarify\n  that config might be ignore depending on build options in the docs.\n- mention potential platform unsafety directly in config doc in\n  addition to the link to Racy Git\n\nChanges in v3:\n\n- #ifdef out use_nanosec when NO_NSEC is requested\n\nAs I have heard no comments about the \"Todo\" lines below, which perhaps\ncould more clearly be marked \"RFC\"/\"RFH\", I've added this line to call\nthem out ;) and renamed them \"Comments welcome\"\n\nChanges in v2:\n\n- move Best-viewed-with trailer into message body as descriptive\n  text.\n- read core.useNanosec through struct repo instead of parsing\n  config strings. The test suite passes locally this way, though that\n  skipped 151 tests.\n    - CI run: https://github.com/benknoble/git/actions/runs/31701945211\n\nOriginal cover letter:\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n- The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n- The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n- The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nComments welcome: I haven't touched any tests; I saw a bunch of hits for\n\"git grep racy t\" but wasn't sure how to fit this particular change in,\nespecially since it won't be equally valid on all systems? Advice\nwelcome.\n\nComments welcome: I wonder if \"useNanosec\" paints us into too much of a\ncorner; that is (slightly more abstractly), we are using *extended\nprecision* in the index. Maybe the name and documentation should reflect\nthat, so we aren't too committed to \"nanoseconds\"?\n    - Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    - Some could offer precision _beyond_ nanoseconds\n\nidk.\n\nv1: <cover.1786103607.git.ben.knoble@gmail.com>\nv2: <cover.1786710807.git.ben.knoble@gmail.com>\nv3: <cover.1787065125.git.ben.knoble@gmail.com>\nv4: <cover.1787231825.git.ben.knoble@gmail.com>\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 27 ++++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 12 files changed, 57 insertions(+), 48 deletions(-)\n\nDiff-intervalle contre v4 :\n1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n2:  5693baa992 ! 2:  12974e07d0 environment: align repo_config_values_init with struct declaration\n    @@ Commit message\n         environment: align repo_config_values_init with struct declaration\n     \n         The order of assignments in repo_config_values_init is chaotic and hard\n    -    to follow, especially when comparing with the struct definition to\n    -    ensure all members are initialized. As new members will be added in the\n    -    future, make it easier to validate changes by aligning the two.\n    +    to follow, especially with the definition of 'struct repo_config_values'\n    +    to ensure all members are initialized. As new members will be added in\n    +    the future, make it easier to validate changes by aligning the two.\n     \n         Refactor assignment order with no behavioral changes.\n     \n3:  0aa0e9fc17 = 3:  01cd487cd2 core: convert build-time USE_NSEC into runtime core.useNanosec\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551464","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1788010335.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1788010335.git.ben.knoble@gmail.com","subject":"[PATCH v5 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-29T13:38:18Z","receivedAt":"2026-08-29T13:38:36Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551465","messageId":"12974e07d088c1621248296d08b6583c568ba4cf.1788010335.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1788010335.git.ben.knoble@gmail.com","subject":"[PATCH v5 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-29T13:38:19Z","receivedAt":"2026-08-29T13:38:39Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially with the definition of 'struct repo_config_values'\nto ensure all members are initialized. As new members will be added in\nthe future, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551466","messageId":"01cd487cd23f23b1d18359b86fbcf18e25039e6d.1788010335.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1788010335.git.ben.knoble@gmail.com","subject":"[PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-29T13:38:20Z","receivedAt":"2026-08-29T13:38:44Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nDue to the conversion from #ifdef to runtime check, using the flag\n\"--ignore-space-change\" may be particularly helpful when viewing changes\nfrom this patch.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    CI: <https://github.com/benknoble/git/actions/runs/32365602564>\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         |  8 ++++++++\n environment.h                         |  1 +\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 10 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..b793f62e42 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,13 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisions between the index and the working tree (if Git\n+\twas compiled to respect this option).\n+\tThis is unsafe on some platforms;\n+\tsee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..8e0c25655f 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is defined. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..c83cf44839 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+#ifndef NO_NSEC\n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+#endif\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+\tcfg->use_nanosec = 0;\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..b32cfd0ef1 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n-#else\n-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n-#endif\n-\t\t);\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\t(repo_config_values(istate->repo)->use_nanosec\n+\t\t ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t    (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t : istate->timestamp.sec <= sd->sd_mtime.sec));\n }\n \n int is_racy_timestamp(const struct index_state *istate,\ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..d9ddcf9382 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n-#endif\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n \n \tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551487","messageId":"xmqq8q5n1fa2.fsf@gitster.g","threadId":"66138","inReplyTo":"01cd487cd23f23b1d18359b86fbcf18e25039e6d.1788010335.git.ben.knoble@gmail.com","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-30T21:15:17Z","receivedAt":"2026-08-30T21:15:20Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> +\t\t/* nanosecond timestamped files can also be racy! */\n> +\t\t(repo_config_values(istate->repo)->use_nanosec\n> +\t\t ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> +\t\t    (istate->timestamp.sec == sd->sd_mtime.sec &&\n> +\t\t     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> +\t\t : istate->timestamp.sec <= sd->sd_mtime.sec));\n>  }\n\nCurrently this is probably fine, but the use of repo_config_values()\nhere means that the order in which we can transition/libify two\nunrelated things are forced on us:\n\n * We'd first need to make sure repo_config_values() can work on an\n   instance of repository that is not the_repository,\n\n * And until the above happens, we cannot do a --recurse-submodule\n   option that loads the index in a submodule and operate on it in\n   the same process (e.g., \"git diff --resurse-submodules\"),\n   because immediately at this step, istate taken from a submodule\n   would have its .repo member pointing at something that is not\n   the_repository and we will hit a BUG().\n\nAnd after writing all of the above, I realized that I am mostly\nrepeating what Patric already said in the upstream, e.g.,\n\n    https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/\n\nOther than that, this looks good to me.\n"},{"id":"551491","messageId":"CALnO6CBejkZTgPM9tK6TEGeNYSRfi9r2-xi7R4ckTsRm4ZGaQw@mail.gmail.com","threadId":"66138","inReplyTo":"xmqq8q5n1fa2.fsf@gitster.g","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T00:27:13Z","receivedAt":"2026-08-31T00:27:25Z","isPatch":true,"body":"On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> > +             /* nanosecond timestamped files can also be racy! */\n> > +             (repo_config_values(istate->repo)->use_nanosec\n> > +              ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > +                 (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > +                  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > +              : istate->timestamp.sec <= sd->sd_mtime.sec));\n> >  }\n>\n> Currently this is probably fine, but the use of repo_config_values()\n> here means that the order in which we can transition/libify two\n> unrelated things are forced on us:\n>\n>  * We'd first need to make sure repo_config_values() can work on an\n>    instance of repository that is not the_repository,\n>\n>  * And until the above happens, we cannot do a --recurse-submodule\n>    option that loads the index in a submodule and operate on it in\n>    the same process (e.g., \"git diff --resurse-submodules\"),\n>    because immediately at this step, istate taken from a submodule\n>    would have its .repo member pointing at something that is not\n>    the_repository and we will hit a BUG().\n>\n> And after writing all of the above, I realized that I am mostly\n> repeating what Patric already said in the upstream, e.g.,\n>\n>     https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/\n\nYep---just so I'm clear, we don't currently have such an option,\nright? I mean, there is no --recurse-submodules for git-diff(1), and I\ntweaked t4060 to run \"git -c core.useNanosec=true diff\n--submodule=diff\" without any issue.\n\nI would happily prove that at least none of our existing tests fail\nwith core.useNanosec=true, but I'm not really sure how to shove\nconfiguration into every test invocation of git. Even if we could, I'm\nnot sure we necessarily want to add another CI job for that (though\nthat's a separate matter).\n\nIn particular, (among others) I have not received any concrete comments for\n\n> Comments welcome: I haven't touched any tests; I saw a bunch of hits for\n> \"git grep racy t\" but wasn't sure how to fit this particular change in,\n> especially since it won't be equally valid on all systems? Advice\n> welcome.\n\nso if there's at least a way to exercise this path on all the tests on\nmy system (which should support it), that would probably be a good\nthing.\n\n> Other than that, this looks good to me.\n\nThank\n\n--\nD. Ben Knoble\n"},{"id":"551527","messageId":"apVJAzddTPPCI7kA@pks.im","threadId":"66138","inReplyTo":"CALnO6CBejkZTgPM9tK6TEGeNYSRfi9r2-xi7R4ckTsRm4ZGaQw@mail.gmail.com","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-31T09:27:31Z","receivedAt":"2026-08-31T09:27:41Z","isPatch":true,"body":"On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:\n> On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:\n> >\n> > \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n> >\n> > > +             /* nanosecond timestamped files can also be racy! */\n> > > +             (repo_config_values(istate->repo)->use_nanosec\n> > > +              ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > > +                 (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > > +                  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > > +              : istate->timestamp.sec <= sd->sd_mtime.sec));\n> > >  }\n> >\n> > Currently this is probably fine, but the use of repo_config_values()\n> > here means that the order in which we can transition/libify two\n> > unrelated things are forced on us:\n> >\n> >  * We'd first need to make sure repo_config_values() can work on an\n> >    instance of repository that is not the_repository,\n> >\n> >  * And until the above happens, we cannot do a --recurse-submodule\n> >    option that loads the index in a submodule and operate on it in\n> >    the same process (e.g., \"git diff --resurse-submodules\"),\n> >    because immediately at this step, istate taken from a submodule\n> >    would have its .repo member pointing at something that is not\n> >    the_repository and we will hit a BUG().\n> >\n> > And after writing all of the above, I realized that I am mostly\n> > repeating what Patric already said in the upstream, e.g.,\n> >\n> >     https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/\n> \n> Yep---just so I'm clear, we don't currently have such an option,\n> right? I mean, there is no --recurse-submodules for git-diff(1), and I\n> tweaked t4060 to run \"git -c core.useNanosec=true diff\n> --submodule=diff\" without any issue.\n\nI do have a patch series coming up where we start to rely more on\nsub-repositories when recursing. The motivation behind that series is\nthat it allows us to get rid of registering submodule object databases\nwith the main ODB. But I just double-checked, and your series luckily\ndoesn't break it.\n\n> I would happily prove that at least none of our existing tests fail\n> with core.useNanosec=true, but I'm not really sure how to shove\n> configuration into every test invocation of git. Even if we could, I'm\n> not sure we necessarily want to add another CI job for that (though\n> that's a separate matter).\n> \n> In particular, (among others) I have not received any concrete comments for\n> \n> > Comments welcome: I haven't touched any tests; I saw a bunch of hits for\n> > \"git grep racy t\" but wasn't sure how to fit this particular change in,\n> > especially since it won't be equally valid on all systems? Advice\n> > welcome.\n> \n> so if there's at least a way to exercise this path on all the tests on\n> my system (which should support it), that would probably be a good\n> thing.\n\nYeah, I simply don't have a good answer here. It's messy, and I'm not a\nfan of the current direction of `repo_config_values()` because nobody\nhas yet stepped up to untangle it from `the_repository`. I gave it a\nquick shot at one point in time, but the result was messy at best\nbecause of how we populate it via `repo_config(git_default_config)`.\n\nIn any case, if we see that your changes interact badly with some edge\ncases that we don't currently have on our radar then we can still\nrefactor the series and move the value into `struct repo_settings`\ninstead, as that structure works alright with different repositories.\n\nThanks!\n\nPatrick\n"},{"id":"551528","messageId":"apVJCt4prIi2GgXp@pks.im","threadId":"66138","inReplyTo":"01cd487cd23f23b1d18359b86fbcf18e25039e6d.1788010335.git.ben.knoble@gmail.com","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-31T09:27:38Z","receivedAt":"2026-08-31T09:27:44Z","isPatch":true,"body":"On Sat, Aug 29, 2026 at 09:38:20AM -0400, D. Ben Knoble wrote:\n> diff --git a/builtin/update-index.c b/builtin/update-index.c\n> index 241abd4332..8e0c25655f 100644\n> --- a/builtin/update-index.c\n> +++ b/builtin/update-index.c\n> @@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n>  static void avoid_racy(void)\n>  {\n>  \t/*\n> -\t * not use if we could usleep(10) if USE_NSEC is defined. The\n> +\t * not use if we could usleep(10) if core.useNanosec is defined. The\n\nMicronit: s/defined/enabled/\n\nOtherwise I'm happy with this patch. It looks a lot better now that we\nuse less preprocessor directives. Thanks!\n\nPatrick\n"},{"id":"551547","messageId":"CALnO6CAbnv4iKpv5TbtnrX_i6Kp1H6wOgh6ARO0ds6kXK9m3PA@mail.gmail.com","threadId":"66138","inReplyTo":"apVJAzddTPPCI7kA@pks.im","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T13:00:39Z","receivedAt":"2026-08-31T13:00:53Z","isPatch":true,"body":"[Apologies for duplicates; Gmail switched out of plain-text mode\nwithout permission. I've yet to finish setting up aerc…]\n\nHi Patrick,\n\nOn Mon, Aug 31, 2026 at 5:27 AM Patrick Steinhardt <ps@pks.im> wrote:\n>\n> On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:\n> > On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:\n> > >\n> > > \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n> > >\n> > > > +             /* nanosecond timestamped files can also be racy! */\n> > > > +             (repo_config_values(istate->repo)->use_nanosec\n> > > > +              ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n> > > > +                 (istate->timestamp.sec == sd->sd_mtime.sec &&\n> > > > +                  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n> > > > +              : istate->timestamp.sec <= sd->sd_mtime.sec));\n> > > >  }\n> > >\n> > > Currently this is probably fine, but the use of repo_config_values()\n> > > here means that the order in which we can transition/libify two\n> > > unrelated things are forced on us:\n> > >\n> > >  * We'd first need to make sure repo_config_values() can work on an\n> > >    instance of repository that is not the_repository,\n> > >\n> > >  * And until the above happens, we cannot do a --recurse-submodule\n> > >    option that loads the index in a submodule and operate on it in\n> > >    the same process (e.g., \"git diff --resurse-submodules\"),\n> > >    because immediately at this step, istate taken from a submodule\n> > >    would have its .repo member pointing at something that is not\n> > >    the_repository and we will hit a BUG().\n> > >\n> > > And after writing all of the above, I realized that I am mostly\n> > > repeating what Patric already said in the upstream, e.g.,\n> > >\n> > >     https://lore.kernel.org/git/an720tZnot07HYiK@pks.im/\n> >\n> > Yep---just so I'm clear, we don't currently have such an option,\n> > right? I mean, there is no --recurse-submodules for git-diff(1), and I\n> > tweaked t4060 to run \"git -c core.useNanosec=true diff\n> > --submodule=diff\" without any issue.\n>\n> I do have a patch series coming up where we start to rely more on\n> sub-repositories when recursing. The motivation behind that series is\n> that it allows us to get rid of registering submodule object databases\n> with the main ODB. But I just double-checked, and your series luckily\n> doesn't break it.\n\nGlad it worked out ;)\n\n> > I would happily prove that at least none of our existing tests fail\n> > with core.useNanosec=true, but I'm not really sure how to shove\n> > configuration into every test invocation of git. Even if we could, I'm\n> > not sure we necessarily want to add another CI job for that (though\n> > that's a separate matter).\n> >\n> > In particular, (among others) I have not received any concrete comments for\n> >\n> > > Comments welcome: I haven't touched any tests; I saw a bunch of hits for\n> > > \"git grep racy t\" but wasn't sure how to fit this particular change in,\n> > > especially since it won't be equally valid on all systems? Advice\n> > > welcome.\n> >\n> > so if there's at least a way to exercise this path on all the tests on\n> > my system (which should support it), that would probably be a good\n> > thing.\n>\n> Yeah, I simply don't have a good answer here. It's messy, and I'm not a\n> fan of the current direction of `repo_config_values()` because nobody\n> has yet stepped up to untangle it from `the_repository`. I gave it a\n> quick shot at one point in time, but the result was messy at best\n> because of how we populate it via `repo_config(git_default_config)`.\n\n\nI took a quick look (being unfamiliar), and yeah, it does seem pretty\ntangled. I suppose one way to go about it would be to have\nrepo_config() forward the repository argument through configset_iter\nto the config_fn_t callback? I'm a bit surprised (leaving aside how\npervasive the_repository is otherwise) to see it doesn't already do\nthat :)\n\nIs that the approach you took? Or, where else did you feel hung up\nabout the resulting code? Just wondering.\n\n> In any case, if we see that your changes interact badly with some edge\n> cases that we don't currently have on our radar then we can still\n> refactor the series and move the value into `struct repo_settings`\n> instead, as that structure works alright with different repositories.\n>\n> Thanks!\n>\n> Patrick\n\nThis sounds reasonable to me. If nothing else, this series might\nbecome good motivation to untangle repo_config_values…\n\nSounds to me like we might be ready for 'next'?\n\n-- \nD. Ben Knoble\n"},{"id":"551562","messageId":"apWUGfzQxx7vArpo@pks.im","threadId":"66138","inReplyTo":"CALnO6CCNwXC1_PUCTWEU-HXBk+W+sBGqn7Sr8D=ZHW3Mxcu20g@mail.gmail.com","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-31T14:47:53Z","receivedAt":"2026-08-31T14:48:01Z","isPatch":true,"body":"On Mon, Aug 31, 2026 at 08:57:49AM -0400, D. Ben Knoble wrote:\n> On Mon, Aug 31, 2026 at 5:27 AM Patrick Steinhardt <ps@pks.im> wrote:\n> > On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:\n> > > On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:\n[snip]\n> > > I would happily prove that at least none of our existing tests fail\n> > > with core.useNanosec=true, but I'm not really sure how to shove\n> > > configuration into every test invocation of git. Even if we could, I'm\n> > > not sure we necessarily want to add another CI job for that (though\n> > > that's a separate matter).\n> > >\n> > > In particular, (among others) I have not received any concrete comments\n> > for\n> > >\n> > > > Comments welcome: I haven't touched any tests; I saw a bunch of hits\n> > for\n> > > > \"git grep racy t\" but wasn't sure how to fit this particular change in,\n> > > > especially since it won't be equally valid on all systems? Advice\n> > > > welcome.\n> > >\n> > > so if there's at least a way to exercise this path on all the tests on\n> > > my system (which should support it), that would probably be a good\n> > > thing.\n> >\n> > Yeah, I simply don't have a good answer here. It's messy, and I'm not a\n> > fan of the current direction of `repo_config_values()` because nobody\n> > has yet stepped up to untangle it from `the_repository`. I gave it a\n> > quick shot at one point in time, but the result was messy at best\n> > because of how we populate it via `repo_config(git_default_config)`.\n> >\n> \n> I took a quick look (being unfamiliar), and yeah, it does seem pretty\n> tangled. I suppose one way to go about it would be to have repo_config()\n> forward the repository argument through configset_iter to the config_fn_t\n> callback? I'm a bit surprised (leaving aside how pervasive the_repository\n> is otherwise) to see it doesn't already do that :)\n> \n> Is that the approach you took? Or, where else did you feel hung up about\n> the resulting code? Just wondering.\n\nYeah, that's what I did. I don't quite remember what was awkward about\nit though. It might've been that callers have to be aware whether a repo\nis initialized, and whether it has all info to be able to read its own\nconfiguration? Or I was trying to make it auto-lazy-load or something\nlike that, but because our config subsystem is so fragile that led to\nlots of weird edge cases.\n\nSometimes I really wonder whether that whole caching layer is even worth\nit. We already store the configuration as part of the configset, so\ncaching the parsed values probably does not buy us a lot. For some very\ncentral aspects like the bareness of a repository or the location of the\nworktree it probably even makes sense, but for everything else... I\ndunno. By now I feel like it would make more sense there to find\nlocalized solutions specific to subsystems instead of having that one\nbig global struct that has weird semantics.\n\n> > In any case, if we see that your changes interact badly with some edge\n> > cases that we don't currently have on our radar then we can still\n> > refactor the series and move the value into `struct repo_settings`\n> > instead, as that structure works alright with different repositories.\n> \n> This sounds reasonable to me. If nothing else, this series might become\n> good motivation to untangle repo_config_values…\n> \n> Sounds to me like we might be ready for 'next'?\n\nWorks for me.\n\nPatrick\n"},{"id":"551572","messageId":"40419516-56A6-4AA6-B0C9-4F15EA61480E@gmail.com","threadId":"66138","inReplyTo":"apVJCt4prIi2GgXp@pks.im","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T15:46:29Z","receivedAt":"2026-08-31T15:46:41Z","isPatch":true,"body":"\n> Le 31 août 2026 à 11:31, Patrick Steinhardt <ps@pks.im> a écrit :\n> \n> ﻿On Sat, Aug 29, 2026 at 09:38:20AM -0400, D. Ben Knoble wrote:\n>> diff --git a/builtin/update-index.c b/builtin/update-index.c\n>> index 241abd4332..8e0c25655f 100644\n>> --- a/builtin/update-index.c\n>> +++ b/builtin/update-index.c\n>> @@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n>> static void avoid_racy(void)\n>> {\n>>    /*\n>> -     * not use if we could usleep(10) if USE_NSEC is defined. The\n>> +     * not use if we could usleep(10) if core.useNanosec is defined. The\n> \n> Micronit: s/defined/enabled/\n> \n> Otherwise I'm happy with this patch. It looks a lot better now that we\n> use less preprocessor directives. Thanks!\n> \n> Patrick\n\nThanks, 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!)"},{"id":"551601","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1788206466.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1788206466.git.ben.knoble@gmail.com","subject":"[PATCH v6 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T20:01:35Z","receivedAt":"2026-08-31T20:02:03Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551602","messageId":"12974e07d088c1621248296d08b6583c568ba4cf.1788206466.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1788206466.git.ben.knoble@gmail.com","subject":"[PATCH v6 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T20:01:36Z","receivedAt":"2026-08-31T20:02:05Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially with the definition of 'struct repo_config_values'\nto ensure all members are initialized. As new members will be added in\nthe future, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551603","messageId":"0a611f614041b165140da7f2546c058178cdbfce.1788206466.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1788206466.git.ben.knoble@gmail.com","subject":"[PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T20:01:37Z","receivedAt":"2026-08-31T20:02:05Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nDue to the conversion from #ifdef to runtime check, using the flag\n\"--ignore-space-change\" may be particularly helpful when viewing changes\nfrom this patch.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    CI: <https://github.com/benknoble/git/actions/runs/32365602564>\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         |  8 ++++++++\n environment.h                         |  1 +\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 10 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..b793f62e42 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,13 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisions between the index and the working tree (if Git\n+\twas compiled to respect this option).\n+\tThis is unsafe on some platforms;\n+\tsee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..a10c07b636 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is enabled. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..c83cf44839 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+#ifndef NO_NSEC\n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+#endif\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+\tcfg->use_nanosec = 0;\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..b32cfd0ef1 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n-#else\n-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n-#endif\n-\t\t);\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\t(repo_config_values(istate->repo)->use_nanosec\n+\t\t ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t    (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t : istate->timestamp.sec <= sd->sd_mtime.sec));\n }\n \n int is_racy_timestamp(const struct index_state *istate,\ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..d9ddcf9382 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n-#endif\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n \n \tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551604","messageId":"cover.1788206466.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787231825.git.ben.knoble@gmail.com","subject":"[PATCH v6 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T20:01:34Z","receivedAt":"2026-08-31T20:02:30Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime (applied)\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v5:\n\n- improve message flow in patch 2\n\nChanges in v4:\n\n- fix message typo\n- change #ifdef strategy: only ignore the config variable.\n  Otherwise, use the use_nanosec member unconditionally. Also clarify\n  that config might be ignore depending on build options in the docs.\n- mention potential platform unsafety directly in config doc in\n  addition to the link to Racy Git\n\nChanges in v3:\n\n- #ifdef out use_nanosec when NO_NSEC is requested\n\nAs I have heard no comments about the \"Todo\" lines below, which perhaps\ncould more clearly be marked \"RFC\"/\"RFH\", I've added this line to call\nthem out ;) and renamed them \"Comments welcome\"\n\nChanges in v2:\n\n- move Best-viewed-with trailer into message body as descriptive\n  text.\n- read core.useNanosec through struct repo instead of parsing\n  config strings. The test suite passes locally this way, though that\n  skipped 151 tests.\n    - CI run: https://github.com/benknoble/git/actions/runs/31701945211\n\nOriginal cover letter:\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n- The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n- The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n- The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nComments welcome: I haven't touched any tests; I saw a bunch of hits for\n\"git grep racy t\" but wasn't sure how to fit this particular change in,\nespecially since it won't be equally valid on all systems? Advice\nwelcome.\n\nComments welcome: I wonder if \"useNanosec\" paints us into too much of a\ncorner; that is (slightly more abstractly), we are using *extended\nprecision* in the index. Maybe the name and documentation should reflect\nthat, so we aren't too committed to \"nanoseconds\"?\n    - Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    - Some could offer precision _beyond_ nanoseconds\n\nidk.\n\nv1: <cover.1786103607.git.ben.knoble@gmail.com>\nv2: <cover.1786710807.git.ben.knoble@gmail.com>\nv3: <cover.1787065125.git.ben.knoble@gmail.com>\nv4: <cover.1787231825.git.ben.knoble@gmail.com>\nv5: <cover.1788010335.git.ben.knoble@gmail.com>\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 27 ++++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 12 files changed, 57 insertions(+), 48 deletions(-)\n\nDiff-intervalle contre v5 :\n1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n2:  12974e07d0 = 2:  12974e07d0 environment: align repo_config_values_init with struct declaration\n3:  01cd487cd2 ! 3:  0a611f6140 core: convert build-time USE_NSEC into runtime core.useNanosec\n    @@ builtin/update-index.c: static void xrmdir(const char *path)\n      {\n      \t/*\n     -\t * not use if we could usleep(10) if USE_NSEC is defined. The\n    -+\t * not use if we could usleep(10) if core.useNanosec is defined. The\n    ++\t * not use if we could usleep(10) if core.useNanosec is enabled. The\n      \t * field nsec could be there, but the OS could choose to\n      \t * ignore it?\n      \t */\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.860.g4b6b3295ed.dirty\n\n"},{"id":"551605","messageId":"CALnO6CDCqACYpR=GoaNR28wwxYOEQUJBA1U9sX-xDhO8-4_n+g@mail.gmail.com","threadId":"66138","inReplyTo":"cover.1788206466.git.ben.knoble@gmail.com","subject":"Re: [PATCH v6 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-08-31T20:06:14Z","receivedAt":"2026-08-31T20:06:28Z","isPatch":true,"body":"Erm, woops\n\nOn Mon, Aug 31, 2026 at 4:02 PM D. Ben Knoble <ben.knoble@gmail.com> wrote:\n>\n> Topic name: dk/use-nsec-runtime (applied)\n>\n> Topic summary: Expose USE_NSEC as a runtime configuration, since\n> build-time is too early for distributing Git [1]. As a result, common\n> index-related options, like git-diff, are less likely to hit \"racy git\"\n> problems on supported filesystems.\n>\n> [1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n>\n> Built on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v6: slight comment tweak\n\n> Changes in v5:\n>\n> - improve message flow in patch 2\n\n[snip]\n\n> Diff-intervalle contre v5 :\n> 1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n> 2:  12974e07d0 = 2:  12974e07d0 environment: align repo_config_values_init with struct declaration\n> 3:  01cd487cd2 ! 3:  0a611f6140 core: convert build-time USE_NSEC into runtime core.useNanosec\n>     @@ builtin/update-index.c: static void xrmdir(const char *path)\n>       {\n>         /*\n>      -   * not use if we could usleep(10) if USE_NSEC is defined. The\n>     -+   * not use if we could usleep(10) if core.useNanosec is defined. The\n>     ++   * not use if we could usleep(10) if core.useNanosec is enabled. The\n>          * field nsec could be there, but the OS could choose to\n>          * ignore it?\n>          */\n>\n> base-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n> --\n> 2.55.0.860.g4b6b3295ed.dirty\n\nThanks\n\n-- \nD. Ben Knoble\n"},{"id":"551615","messageId":"B48D3D3E-E5C5-47DE-AD67-C8C6CB11E27C@gmail.com","threadId":"66138","inReplyTo":"apWUGfzQxx7vArpo@pks.im","subject":"Re: [PATCH v5 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-01T00:35:20Z","receivedAt":"2026-09-01T00:35:33Z","isPatch":true,"body":"\n> Le 31 août 2026 à 18:06, Patrick Steinhardt <ps@pks.im> a écrit :\n> \n> ﻿On Mon, Aug 31, 2026 at 08:57:49AM -0400, D. Ben Knoble wrote:\n>>> On Mon, Aug 31, 2026 at 5:27 AM Patrick Steinhardt <ps@pks.im> wrote:\n>>> On Sun, Aug 30, 2026 at 08:27:13PM -0400, D. Ben Knoble wrote:\n>>>> On Sun, Aug 30, 2026 at 5:15 PM Junio C Hamano <gitster@pobox.com> wrote:\n> [snip]\n>>>> I would happily prove that at least none of our existing tests fail\n>>>> with core.useNanosec=true, but I'm not really sure how to shove\n>>>> configuration into every test invocation of git. Even if we could, I'm\n>>>> not sure we necessarily want to add another CI job for that (though\n>>>> that's a separate matter).\n>>>> \n>>>> In particular, (among others) I have not received any concrete comments\n>>> for\n>>>> \n>>>>> Comments welcome: I haven't touched any tests; I saw a bunch of hits\n>>> for\n>>>>> \"git grep racy t\" but wasn't sure how to fit this particular change in,\n>>>>> especially since it won't be equally valid on all systems? Advice\n>>>>> welcome.\n>>>> \n>>>> so if there's at least a way to exercise this path on all the tests on\n>>>> my system (which should support it), that would probably be a good\n>>>> thing.\n>>> \n>>> Yeah, I simply don't have a good answer here. It's messy, and I'm not a\n>>> fan of the current direction of `repo_config_values()` because nobody\n>>> has yet stepped up to untangle it from `the_repository`. I gave it a\n>>> quick shot at one point in time, but the result was messy at best\n>>> because of how we populate it via `repo_config(git_default_config)`.\n>>> \n>> \n>> I took a quick look (being unfamiliar), and yeah, it does seem pretty\n>> tangled. I suppose one way to go about it would be to have repo_config()\n>> forward the repository argument through configset_iter to the config_fn_t\n>> callback? I'm a bit surprised (leaving aside how pervasive the_repository\n>> is otherwise) to see it doesn't already do that :)\n>> \n>> Is that the approach you took? Or, where else did you feel hung up about\n>> the resulting code? Just wondering.\n> \n> Yeah, that's what I did. I don't quite remember what was awkward about\n> it though. It might've been that callers have to be aware whether a repo\n> is initialized, and whether it has all info to be able to read its own\n> configuration? Or I was trying to make it auto-lazy-load or something\n> like that, but because our config subsystem is so fragile that led to\n> lots of weird edge cases.\n> \n> Sometimes I really wonder whether that whole caching layer is even worth\n> it. We already store the configuration as part of the configset, so\n> caching the parsed values probably does not buy us a lot. For some very\n> central aspects like the bareness of a repository or the location of the\n> worktree it probably even makes sense, but for everything else... I\n> dunno. By now I feel like it would make more sense there to find\n> localized solutions specific to subsystems instead of having that one\n> big global struct that has weird semantics.\n\nInteresting, yeah. I can’t say I’m too motivated to look into this further, personally, but the config system seems fairly complex…\n\nMaybe I’ll take a tour of it one day though, depending on the next itch I scratch ;)\n\n>>> In any case, if we see that your changes interact badly with some edge\n>>> cases that we don't currently have on our radar then we can still\n>>> refactor the series and move the value into `struct repo_settings`\n>>> instead, as that structure works alright with different repositories.\n>> \n>> This sounds reasonable to me. If nothing else, this series might become\n>> good motivation to untangle repo_config_values…\n>> \n>> Sounds to me like we might be ready for 'next'?\n> \n> Works for me.\n> \n> Patrick\n\nThanks!"},{"id":"551617","messageId":"xmqq4ig9vbb8.fsf@gitster.g","threadId":"66138","inReplyTo":"0a611f614041b165140da7f2546c058178cdbfce.1788206466.git.ben.knoble@gmail.com","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-01T04:35:07Z","receivedAt":"2026-09-01T04:35:10Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> +core.useNanosec::\n> +\tIf true, use nanosecond precision for ctime and mtime\n> +\tcomparisions between the index and the working tree (if Git\n\ncomparisions?\n\n> +\twas compiled to respect this option).\n> +\tThis is unsafe on some platforms;\n> +\tsee link:technical/racy-git.html[Racy Git]. False by default.\n"},{"id":"551619","messageId":"20260901045403.GA1075462@coredump.intra.peff.net","threadId":"66138","inReplyTo":"0a611f614041b165140da7f2546c058178cdbfce.1788206466.git.ben.knoble@gmail.com","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-09-01T04:54:03Z","receivedAt":"2026-09-01T04:54:05Z","isPatch":true,"body":"On Mon, Aug 31, 2026 at 04:01:37PM -0400, D. Ben Knoble wrote:\n\n> diff --git a/environment.c b/environment.c\n> index 6676e6f5ae..c83cf44839 100644\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n>  \t\treturn 0;\n>  \t}\n>  \n> +#ifndef NO_NSEC\n> +\tif (!strcmp(var, \"core.usenanosec\")) {\n> +\t\tcfg->use_nanosec = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n> +#endif\n\nThis hunk made me wonder if we even need to do any build-time magic here\nat all. If your platform doesn't support nanosecond stat entries, then\nyou're probably not going to ask for core.usenanosec in the first place.\nBut if you do, I think the code still works; we fake the entries as \"0\",\nso they'd always yield a racy tie, just as if core.usenanosec was\ndisabled.\n\nI guess you might be able to get into a funny state, though, if you\nbuild two versions of Git, one with NO_NSEC and one without, on a system\nthat actually does support nanosecond timestamps. Because IIRC even if\nwe aren't _using_ the values, we still store them in the index. So an\nindex generated with the regular build would store the actual nanosec\nstamps, which would then get a false comparison using the NO_NSEC\nversion.\n\nThat seems quite unlikely to happen in practice, and there is a certain\namount of \"if it hurts, don't do that\". But it's not like by dropping\nthis #ifndef we could get rid of NO_NSEC. So it would not simplify the\ncode overall, nor the number of build knobs that we expose to the user.\nSo it probably is reasonable to keep it.\n\nI haven't been following the topic closely, but from my cursory read\neverything else looked as I'd expect it to.\n\n-Peff\n"},{"id":"551663","messageId":"CALnO6CAZYvnv3fMWkU0pqY+XN3ncBqVav49ZEvzV0LMtmkYO0Q@mail.gmail.com","threadId":"66138","inReplyTo":"20260901045403.GA1075462@coredump.intra.peff.net","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-01T12:36:22Z","receivedAt":"2026-09-01T12:36:36Z","isPatch":true,"body":"On Tue, Sep 1, 2026 at 12:54 AM Jeff King <peff@peff.net> wrote:\n>\n> On Mon, Aug 31, 2026 at 04:01:37PM -0400, D. Ben Knoble wrote:\n>\n> > diff --git a/environment.c b/environment.c\n> > index 6676e6f5ae..c83cf44839 100644\n> > --- a/environment.c\n> > +++ b/environment.c\n> > @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n> >               return 0;\n> >       }\n> >\n> > +#ifndef NO_NSEC\n> > +     if (!strcmp(var, \"core.usenanosec\")) {\n> > +             cfg->use_nanosec = git_config_bool(var, value);\n> > +             return 0;\n> > +     }\n> > +#endif\n>\n> This hunk made me wonder if we even need to do any build-time magic here\n> at all. If your platform doesn't support nanosecond stat entries, then\n> you're probably not going to ask for core.usenanosec in the first place.\n> But if you do, I think the code still works; we fake the entries as \"0\",\n> so they'd always yield a racy tie, just as if core.usenanosec was\n> disabled.\n\nAt first I thought you meant we fake the cfg->use_nanosec as 0; it\ntook me a moment to realize you mean that we fake the index entries as\n0ns. (That is what you mean, right?)\n\nIn that case, yes, I suppose it would work. Might be confusing in a\ndebugger to see use_nanosec set and checked, though?\n\n> I guess you might be able to get into a funny state, though, if you\n> build two versions of Git, one with NO_NSEC and one without, on a system\n> that actually does support nanosecond timestamps. Because IIRC even if\n> we aren't _using_ the values, we still store them in the index. So an\n> index generated with the regular build would store the actual nanosec\n> stamps, which would then get a false comparison using the NO_NSEC\n> version.\n>\n> That seems quite unlikely to happen in practice, and there is a certain\n> amount of \"if it hurts, don't do that\".\n\nHm, yeah. I haven't thought too hard either about the interactions\nwhere you toggle core.usenanosec on and off, but giving it an initial\nthink they seem fine. Unlike this hypothetical case, when it's off we\ndon't look at the ns fields, so I don't think we end up with any false\nnegatives.\n\nAnd in this hypothetical, by restricting the option parsing we avoid\nreading the ns values on unsupported platforms, I think?\n\nThe build-time conditional _does_ mean that if your distro (e.g.)\nprovides a NO_NSEC build, you can't access the core.usenanosec feature\nwithout compiling yourself, even if your platform supports it. But I\nhaven't thought too hard either about what it looks like to get rid of\nNO_NSEC entirely, and I'm not totally sure if that's a good idea.\n\n> But it's not like by dropping\n> this #ifndef we could get rid of NO_NSEC. So it would not simplify the\n> code overall, nor the number of build knobs that we expose to the user.\n> So it probably is reasonable to keep it.\n>\n> I haven't been following the topic closely, but from my cursory read\n> everything else looked as I'd expect it to.\n>\n> -Peff\n\nSounds good, thanks!\n\n-- \nD. Ben Knoble\n"},{"id":"551664","messageId":"CALnO6CBKWpmTZW+Z74JsTQvr864vFsvwvRJeKAu3LfXZJK-1Yg@mail.gmail.com","threadId":"66138","inReplyTo":"xmqq4ig9vbb8.fsf@gitster.g","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-01T12:38:45Z","receivedAt":"2026-09-01T12:38:57Z","isPatch":true,"body":"On Tue, Sep 1, 2026 at 12:35 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>\n> > +core.useNanosec::\n> > +     If true, use nanosecond precision for ctime and mtime\n> > +     comparisions between the index and the working tree (if Git\n>\n> comparisions?\n>\n> > +     was compiled to respect this option).\n> > +     This is unsafe on some platforms;\n> > +     see link:technical/racy-git.html[Racy Git]. False by default.\n\nOuch, good eyes. Obviously should be \"comparisons\"---I've amended\nlocally but will hold onto the new version for a bit.\n\nAs this topic is not in next yet, I presume that sending a new version\nwith the typofix is the correct thing to do. I'll wait a while today\nto see if any other comments trickle in.\n\n-- \nD. Ben Knoble\n"},{"id":"551691","messageId":"xmqqpkywswqr.fsf@gitster.g","threadId":"66138","inReplyTo":"CALnO6CBKWpmTZW+Z74JsTQvr864vFsvwvRJeKAu3LfXZJK-1Yg@mail.gmail.com","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-01T17:32:44Z","receivedAt":"2026-09-01T17:32:46Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> On Tue, Sep 1, 2026 at 12:35 AM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> \"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n>>\n>> > +core.useNanosec::\n>> > +     If true, use nanosecond precision for ctime and mtime\n>> > +     comparisions between the index and the working tree (if Git\n>>\n>> comparisions?\n>>\n>> > +     was compiled to respect this option).\n>> > +     This is unsafe on some platforms;\n>> > +     see link:technical/racy-git.html[Racy Git]. False by default.\n>\n> Ouch, good eyes. Obviously should be \"comparisons\"---I've amended\n> locally but will hold onto the new version for a bit.\n>\n> As this topic is not in next yet, I presume that sending a new version\n> with the typofix is the correct thing to do. I'll wait a while today\n> to see if any other comments trickle in.\n\nYeah, and in the meantime I'll locallly amend what I have.  If we do\nnot hear any other issues in a few days perhaps we can do without\nthe final reroll that way.\n\nThanks.\n"},{"id":"551731","messageId":"20260902072646.GB70165@coredump.intra.peff.net","threadId":"66138","inReplyTo":"CALnO6CAZYvnv3fMWkU0pqY+XN3ncBqVav49ZEvzV0LMtmkYO0Q@mail.gmail.com","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2026-09-02T07:26:46Z","receivedAt":"2026-09-02T07:26:48Z","isPatch":true,"body":"On Tue, Sep 01, 2026 at 08:36:22AM -0400, D. Ben Knoble wrote:\n\n> > This hunk made me wonder if we even need to do any build-time magic here\n> > at all. If your platform doesn't support nanosecond stat entries, then\n> > you're probably not going to ask for core.usenanosec in the first place.\n> > But if you do, I think the code still works; we fake the entries as \"0\",\n> > so they'd always yield a racy tie, just as if core.usenanosec was\n> > disabled.\n> \n> At first I thought you meant we fake the cfg->use_nanosec as 0; it\n> took me a moment to realize you mean that we fake the index entries as\n> 0ns. (That is what you mean, right?)\n\nYeah, sorry to be unclear. I meant that we still have this code:\n\n  #ifdef NO_NSEC\n  #define ST_CTIME_NSEC(st) 0\n  #define ST_MTIME_NSEC(st) 0\n\nSo we are free to pretend that stat nsecs exist and compare them.\n\n> In that case, yes, I suppose it would work. Might be confusing in a\n> debugger to see use_nanosec set and checked, though?\n\nMaybe. Looking at the list of NO_NSEC flags in config.mak.uname, I\nsuspect it's a pretty small population in the first place.\n\n> Hm, yeah. I haven't thought too hard either about the interactions\n> where you toggle core.usenanosec on and off, but giving it an initial\n> think they seem fine. Unlike this hypothetical case, when it's off we\n> don't look at the ns fields, so I don't think we end up with any false\n> negatives.\n> \n> And in this hypothetical, by restricting the option parsing we avoid\n> reading the ns values on unsupported platforms, I think?\n\nI'd have to double check, but I thought that even without USE_NSEC (and\nthus even with your new core.usenanosec off) we still read and store the\nnanosecond values in the index, as long as the platform supports it (and\nif not, then we use those \"0\" fallback values).\n\nSo they are always there in the index. I guess the same odd sequence\napplies even today. If you:\n\n  1. Build with NO_NSEC and get \"fake\" 0 values in your index.\n\n  2. Re-build without NO_NSEC, and also enable USE_NSEC. Now we get\n     _real_ values when we stat(), and compare them to the fake values\n     in the index.\n\nNow the index values appear up to 1-second older than they actually are.\nWhich could maybe yield a racy miss of an update? Probably not for\nstat-freshness (where we want an exact match), but maybe for some index\nvs entry racy-git comparison. I didn't think that hard about it, because\nat some point this sequence is just kind of insane.\n\n> The build-time conditional _does_ mean that if your distro (e.g.)\n> provides a NO_NSEC build, you can't access the core.usenanosec feature\n> without compiling yourself, even if your platform supports it. But I\n> haven't thought too hard either about what it looks like to get rid of\n> NO_NSEC entirely, and I'm not totally sure if that's a good idea.\n\nYou couldn't access it even if core.usenanosec is supported in the\nbuild, because your fake nsec values would all be \"0\" and it's\neffectively a noop. ;)\n\nMy suggestion wasn't really about supporting more cases, but just about\nmaking the code simpler by having one less #ifdef. But like I said\nearlier, we can't get rid of the NO_NSEC knob entirely, so it's probably\nnot worth worrying about the one #ifdef either way.\n\n-Peff\n"},{"id":"551745","messageId":"B02189AD-DEC3-4117-8505-AAFA56494822@gmail.com","threadId":"66138","inReplyTo":"20260902072646.GB70165@coredump.intra.peff.net","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-02T11:45:38Z","receivedAt":"2026-09-02T11:45:51Z","isPatch":true,"body":"\n> Le 2 sept. 2026 à 03:26, Jeff King <peff@peff.net> a écrit :\n> \n> ﻿On Tue, Sep 01, 2026 at 08:36:22AM -0400, D. Ben Knoble wrote:\n> \n>>> This hunk made me wonder if we even need to do any build-time magic here\n>>> at all. If your platform doesn't support nanosecond stat entries, then\n>>> you're probably not going to ask for core.usenanosec in the first place.\n>>> But if you do, I think the code still works; we fake the entries as \"0\",\n>>> so they'd always yield a racy tie, just as if core.usenanosec was\n>>> disabled.\n>> \n>> At first I thought you meant we fake the cfg->use_nanosec as 0; it\n>> took me a moment to realize you mean that we fake the index entries as\n>> 0ns. (That is what you mean, right?)\n> \n> Yeah, sorry to be unclear. I meant that we still have this code:\n> \n>  #ifdef NO_NSEC\n>  #define ST_CTIME_NSEC(st) 0\n>  #define ST_MTIME_NSEC(st) 0\n> \n> So we are free to pretend that stat nsecs exist and compare them.\n> \n>> In that case, yes, I suppose it would work. Might be confusing in a\n>> debugger to see use_nanosec set and checked, though?\n> \n> Maybe. Looking at the list of NO_NSEC flags in config.mak.uname, I\n> suspect it's a pretty small population in the first place.\n> \n>> Hm, yeah. I haven't thought too hard either about the interactions\n>> where you toggle core.usenanosec on and off, but giving it an initial\n>> think they seem fine. Unlike this hypothetical case, when it's off we\n>> don't look at the ns fields, so I don't think we end up with any false\n>> negatives.\n>> \n>> And in this hypothetical, by restricting the option parsing we avoid\n>> reading the ns values on unsupported platforms, I think?\n> \n> I'd have to double check, but I thought that even without USE_NSEC (and\n> thus even with your new core.usenanosec off) we still read and store the\n> nanosecond values in the index, as long as the platform supports it (and\n> if not, then we use those \"0\" fallback values).\n> \n> So they are always there in the index. I guess the same odd sequence\n> applies even today. If you:\n> \n>  1. Build with NO_NSEC and get \"fake\" 0 values in your index.\n> \n>  2. Re-build without NO_NSEC, and also enable USE_NSEC. Now we get\n>     _real_ values when we stat(), and compare them to the fake values\n>     in the index.\n> \n> Now the index values appear up to 1-second older than they actually are.\n> Which could maybe yield a racy miss of an update? Probably not for\n> stat-freshness (where we want an exact match), but maybe for some index\n> vs entry racy-git comparison. I didn't think that hard about it, because\n> at some point this sequence is just kind of insane.\n> \n>> The build-time conditional _does_ mean that if your distro (e.g.)\n>> provides a NO_NSEC build, you can't access the core.usenanosec feature\n>> without compiling yourself, even if your platform supports it. But I\n>> haven't thought too hard either about what it looks like to get rid of\n>> NO_NSEC entirely, and I'm not totally sure if that's a good idea.\n> \n> You couldn't access it even if core.usenanosec is supported in the\n> build, because your fake nsec values would all be \"0\" and it's\n> effectively a noop. ;)\n> \n> My suggestion wasn't really about supporting more cases, but just about\n> making the code simpler by having one less #ifdef. But like I said\n> earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably\n> not worth worrying about the one #ifdef either way.\n> \n> -Peff\n\nRight on. Always good to find myself nodding along with your explanations :)"},{"id":"551809","messageId":"xmqqh5k7gy9k.fsf@gitster.g","threadId":"66138","inReplyTo":"B02189AD-DEC3-4117-8505-AAFA56494822@gmail.com","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-02T21:05:11Z","receivedAt":"2026-09-02T21:05:14Z","isPatch":true,"body":"Ben Knoble <ben.knoble@gmail.com> writes:\n\n>> My suggestion wasn't really about supporting more cases, but just about\n>> making the code simpler by having one less #ifdef. But like I said\n>> earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably\n>> not worth worrying about the one #ifdef either way.\n>> \n>> -Peff\n>\n> Right on. Always good to find myself nodding along with your explanations :)\n\nOK.  So will we see a hopefully small and final reroll that takes\nadvantage of the fact that ST_XTIME_NSEC(st) would usefully hide the\nNO_NSEC build-time differences?\n\nI still am worried that something that sits this deep in the\ncallchain can easily BUG() when working on a repository that is not\nthe_repository due to the use of repo_config_values(), and we might\nbe better off adopting safe default when istate->repo is different\nfrom the_repository, but other than that, I think the series is in\ngreat shape.\n\nThanks.\n\n\n"},{"id":"551815","messageId":"842F2470-F158-4E77-AD98-DEA530FC4460@gmail.com","threadId":"66138","inReplyTo":"xmqqh5k7gy9k.fsf@gitster.g","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-03T01:00:35Z","receivedAt":"2026-09-03T01:00:48Z","isPatch":true,"body":"\n> Le 2 sept. 2026 à 17:05, Junio C Hamano <gitster@pobox.com> a écrit :\n> \n> ﻿Ben Knoble <ben.knoble@gmail.com> writes:\n> \n>>> My suggestion wasn't really about supporting more cases, but just about\n>>> making the code simpler by having one less #ifdef. But like I said\n>>> earlier, we can't get rid of the NO_NSEC knob entirely, so it's probably\n>>> not worth worrying about the one #ifdef either way.\n>>> \n>>> -Peff\n>> \n>> Right on. Always good to find myself nodding along with your explanations :)\n> \n> OK.  So will we see a hopefully small and final reroll that takes\n> advantage of the fact that ST_XTIME_NSEC(st) would usefully hide the\n> NO_NSEC build-time differences?\n\nAh, 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).\n\n> I still am worried that something that sits this deep in the\n> callchain can easily BUG() when working on a repository that is not\n> the_repository due to the use of repo_config_values(), and we might\n> be better off adopting safe default when istate->repo is different\n> from the_repository, but other than that, I think the series is in\n> great shape.\n> \n> Thanks.\n\nYea. 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.\n\nAbsent suggestions, though, I’m afraid my time is limited to explore the guts of yet another subsystem ;)"},{"id":"551881","messageId":"xmqqbjaefhwo.fsf@gitster.g","threadId":"66138","inReplyTo":"842F2470-F158-4E77-AD98-DEA530FC4460@gmail.com","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-03T15:56:07Z","receivedAt":"2026-09-03T15:56:10Z","isPatch":true,"body":"Ben Knoble <ben.knoble@gmail.com> writes:\n\n>> I still am worried that something that sits this deep in the\n>> callchain can easily BUG() when working on a repository that is not\n>> the_repository due to the use of repo_config_values(), and we might\n>> be better off adopting safe default when istate->repo is different\n>> from the_repository, but other than that, I think the series is in\n>> great shape.\n>> \n>> Thanks.\n\n[administrivia: wrap overly long lines]\n\n> Yea. See previous messages re: convincing the test apparatus to\n> set this globally. If I could run it that way at least locally, it\n> would go a little ways towards scaring those BUGs out into the\n> light.\n\nI am not worried too much about the current code.  I am more worried\nabout how much this will hinder future development of new features,\ne.g., diff or status recursively going into submodules without\nspawning subprocesses, which is done for grep already.  Testing and\nseeing 'git grep --recurse-submodule' not hitting a BUG() does not\nassure us all that much, as I do not think it needs to deal with\nracily clean entries any specially.\n\nThanks.\n"},{"id":"551892","messageId":"D0BA1B32-1CAD-4328-A612-75A648413017@gmail.com","threadId":"66138","inReplyTo":"xmqqbjaefhwo.fsf@gitster.g","subject":"Re: [PATCH v6 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-03T18:16:31Z","receivedAt":"2026-09-03T18:16:43Z","isPatch":true,"body":"\n> Le 3 sept. 2026 à 11:56, Junio C Hamano <gitster@pobox.com> a écrit :\n> \n> ﻿Ben Knoble <ben.knoble@gmail.com> writes:\n> \n>>> I still am worried that something that sits this deep in the\n>>> callchain can easily BUG() when working on a repository that is not\n>>> the_repository due to the use of repo_config_values(), and we might\n>>> be better off adopting safe default when istate->repo is different\n>>> from the_repository, but other than that, I think the series is in\n>>> great shape.\n>>> \n>>> Thanks.\n> \n>> Yea. See previous messages re: convincing the test apparatus to\n>> set this globally. If I could run it that way at least locally, it\n>> would go a little ways towards scaring those BUGs out into the\n>> light.\n> \n> I am not worried too much about the current code.  I am more worried\n> about how much this will hinder future development of new features,\n> e.g., diff or status recursively going into submodules without\n> spawning subprocesses, which is done for grep already.\n\nSure. Some kind of safe default could alleviate that.\nBut seeing recent work in these areas convinces me that\nwe should use this as impetus to lift the restriction, and\nI worry that papering over it will remove that impetus.\nStill, if a later series needs such a band-aid, I suppose it\ncan add the safe fallback. And that’s where testing would\nbe nice for automatic feedback on new such interactions.\n\n> Testing and\n> seeing 'git grep --recurse-submodule' not hitting a BUG() does not\n> assure us all that much, as I do not think it needs to deal with\n> racily clean entries any specially.\n\nA prior reply of mine to Patrick specifically mentioned diff \nwith submodules, I believe. But I agree that positive evidence \nis probably better than negative evidence.\n\nAll-in-all, I’m not inclined to change the shape of this series\nat the present point in this discussion, but if you (or others)\nfeel strongly about this « safe default » being a requirement,\nI will find some time eventually."},{"id":"552534","messageId":"cover.1789129924.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1787231825.git.ben.knoble@gmail.com","subject":"[PATCH v7 0/3] Convert USE_NSEC to runtime config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-11T12:32:26Z","receivedAt":"2026-09-11T12:33:22Z","isPatch":true,"body":"Topic name: dk/use-nsec-runtime (applied)\n\nTopic summary: Expose USE_NSEC as a runtime configuration, since\nbuild-time is too early for distributing Git [1]. As a result, common\nindex-related options, like git-diff, are less likely to hit \"racy git\"\nproblems on supported filesystems.\n\n[1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n\nBuilt on master (2c78326f81 (The 11th batch, 2026-08-05)).\n\nChanges in v7:\n\n• documentation typofix\n• I opted not to finagle #ifdefs more [2] nor to add a \"safe default\n  when istate->repo is different from the_repository\" (replies to [2])\n\n[2]: https://lore.kernel.org/git/842F2470-F158-4E77-AD98-DEA530FC4460@gmail.com/\n\nChanges in v6:\n\n• comment wording tweak\n\nChanges in v5:\n\n• improve message flow in patch 2\n\nChanges in v4:\n\n• fix message typo\n• change #ifdef strategy: only ignore the config variable.\n  Otherwise, use the use_nanosec member unconditionally. Also clarify\n  that config might be ignore depending on build options in the docs.\n• mention potential platform unsafety directly in config doc in\n  addition to the link to Racy Git\n\nChanges in v3:\n\n• #ifdef out use_nanosec when NO_NSEC is requested\n\nAs I have heard no comments about the \"Todo\" lines below, which perhaps\ncould more clearly be marked \"RFC\"/\"RFH\", I've added this line to call\nthem out ;) and renamed them \"Comments welcome\"\n\nChanges in v2:\n\n• move Best-viewed-with trailer into message body as descriptive\n  text.\n• read core.useNanosec through struct repo instead of parsing\n  config strings. The test suite passes locally this way, though that\n  skipped 151 tests.\n    • CI run: https://github.com/benknoble/git/actions/runs/31701945211\n\nOriginal cover letter:\n\nHi all, this series follows up on the previous racy Git/USE_NSEC\nconversations.\n\n• The first patch is a mostly-unrelated documentation fix for Meson, but\n  it came out of something I spotted while reviewing the outputs of the\n  final (main) patch.\n• The second patch is a preliminary no-op reorganization of\n  repo_config_values_init.\n• The third patch is the meat, converting USE_NSEC into core.useNanosec.\n\nThere is a small textual and semantic conflict with\n'ty/repo-config-cleanups' in 'seen', since that branch removes the\ncomments in 'struct repo_config_values' which this series adds to. (The\nsemantic conflict is that, if we drop those comments, we should probably\nnot add them to repo_config_values_init like I do in patch 2.)\n\nComments welcome: I haven't touched any tests; I saw a bunch of hits for\n\"git grep racy t\" but wasn't sure how to fit this particular change in,\nespecially since it won't be equally valid on all systems? Advice\nwelcome.\n\nComments welcome: I wonder if \"useNanosec\" paints us into too much of a\ncorner; that is (slightly more abstractly), we are using *extended\nprecision* in the index. Maybe the name and documentation should reflect\nthat, so we aren't too committed to \"nanoseconds\"?\n    • Some platforms could offer extended precision that is not as\n      precise as nanoseconds\n    • Some could offer precision _beyond_ nanoseconds\n\nidk.\n\nv1: <cover.1786103607.git.ben.knoble@gmail.com>\nv2: <cover.1786710807.git.ben.knoble@gmail.com>\nv3: <cover.1787065125.git.ben.knoble@gmail.com>\nv4: <cover.1787231825.git.ben.knoble@gmail.com>\nv5: <cover.1788010335.git.ben.knoble@gmail.com>\nv6: <cover.1788206466.git.ben.knoble@gmail.com>\n\n[1/3] meson: expose knob for xmlto relative links in manuals\n[2/3] environment: align repo_config_values_init with struct declaration\n[3/3] core: convert build-time USE_NSEC into runtime core.useNanosec\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/meson.build             |  7 ++++++-\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         | 27 ++++++++++++++++++++-------\n environment.h                         |  1 +\n meson_options.txt                     |  2 ++\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 12 files changed, 57 insertions(+), 48 deletions(-)\n\nDiff-intervalle contre v6 :\n1:  d612de6c2d = 1:  d612de6c2d meson: expose knob for xmlto relative links in manuals\n2:  12974e07d0 = 2:  12974e07d0 environment: align repo_config_values_init with struct declaration\n3:  0a611f6140 ! 3:  d983e2f0a5 core: convert build-time USE_NSEC into runtime core.useNanosec\n    @@ Documentation/config/core.adoc: core.trustctime::\n      \n     +core.useNanosec::\n     +\tIf true, use nanosecond precision for ctime and mtime\n    -+\tcomparisions between the index and the working tree (if Git\n    ++\tcomparisons between the index and the working tree (if Git\n     +\twas compiled to respect this option).\n     +\tThis is unsafe on some platforms;\n     +\tsee link:technical/racy-git.html[Racy Git]. False by default.\n\nbase-commit: 2c78326f810173a4f3aefd8021f1e07575412481\n-- \n2.55.0.1003.g10538fe699.dirty\n\n"},{"id":"552535","messageId":"d612de6c2de615f368b5985f200c5ea8e3116c08.1789129924.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1789129924.git.ben.knoble@gmail.com","subject":"[PATCH v7 1/3] meson: expose knob for xmlto relative links in manuals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-11T12:32:27Z","receivedAt":"2026-09-11T12:33:22Z","isPatch":true,"body":"Makefile-based builds have had this knob for most of the project's life,\nsince a479a564dc (Documentation/Makefile: allow\nman.base.url.for.relative.link to be set from Make, 2009-12-03).\n\nMeson, however, hard-codes the equivalent of $prefix/$mandir, which is\nnot really where all the HTML docs are stored in most distro builds.\nPlus, this value is missing a trailing slash, so links come out broken,\nlike this in git.1:\n\n        1. Git User’s Manual\n           /usr/share/manuser-manual.html\n\nOf course we can do better:\n\n1. Change the default to match Make: use file://$(htmldir)/ (with\n   trailing slash!) to form a local URL pointing at the HTML docs. This\n   is safe because all current uses of link:<relative> point at HTML\n   docs:\n\n      git grep 'link:[[:alnum:]]' Documentation | grep -ve html -e http\n\n   produces only a single result (Documentation/howto/howto-index.sh)\n   which can be ignored. Since nothing else [*] in the normal build sets\n   MAN_BASE_URL, this seems like the right default.\n\n2. Provide a configurable knob, just like the Makefile, so distributions\n   that build with Meson (like Gentoo) can decide where to make the\n   links if they need to. Those that set htmldir probably won't need to\n   tweak this any further, though.\n\n[*]: Well, Git's todo branch has a script dodoc.sh to build and archive\n     docs for kernel.org; these docs are pulled by Homebrew\n     installations, for example. It sets MAN_BASE_URL to \"git_htmldocs\",\n     so the equivalent note on macOS + Homebrew is\n\n        1. Git User’s Manual\n           git-htmldocs/user-manual.html\n\n     which is not functional either, but that's a problem for\n     downstream. In any case, users can recover the right path with\n     \"git --html-path\".\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    This patch is mostly because I noticed the link I added in a later patch\n    didn't come out right.\n    \n    I did an internet search for \"MAN_BASE_URL\" and got no real hits, so I'm\n    not sure if any distros today actually use it, but that's not a proper\n    audit in that I didn't look at any distro _code_ besides Gentoo (which,\n    as noted, uses Meson).\n\n Documentation/meson.build | 7 ++++++-\n meson_options.txt         | 2 ++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex f4854f802d..cfa9c67609 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -379,13 +379,18 @@ foreach manpage, category : manpages\n       output: fs.stem(manpage) + '.xml',\n     )\n \n+    man_base_url = 'file://' + htmldir + '/'\n+    if get_option('man_base_url') != ''\n+      man_base_url = get_option('man_base_url')\n+    endif\n+\n     doc_targets += custom_target(\n       command: [\n         xmlto,\n         '-m', '@INPUT0@',\n         '-m', '@INPUT1@',\n         '--stringparam',\n-        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),\n+        'man.base.url.for.relative.links=' + man_base_url,\n         'man',\n         manpage_xml_target,\n         '-o',\ndiff --git a/meson_options.txt b/meson_options.txt\nindex dc88f130d7..d590c21648 100644\n--- a/meson_options.txt\n+++ b/meson_options.txt\n@@ -111,6 +111,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform'\n   description: 'Default format used when executing git-help(1).')\n option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto',\n   description: 'Which backend to use to generate documentation.')\n+option('man_base_url', type: 'string', value: '',\n+  description: 'The base URL to use for relative links in manuals')\n \n # Testing.\n option('benchmarks', type: 'feature', value: 'auto',\n-- \n2.55.0.1003.g10538fe699.dirty\n\n"},{"id":"552536","messageId":"12974e07d088c1621248296d08b6583c568ba4cf.1789129924.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1789129924.git.ben.knoble@gmail.com","subject":"[PATCH v7 2/3] environment: align repo_config_values_init with struct declaration","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-11T12:32:28Z","receivedAt":"2026-09-11T12:33:25Z","isPatch":true,"body":"The order of assignments in repo_config_values_init is chaotic and hard\nto follow, especially with the definition of 'struct repo_config_values'\nto ensure all members are initialized. As new members will be added in\nthe future, make it easier to validate changes by aligning the two.\n\nRefactor assignment order with no behavioral changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n environment.c | 19 ++++++++++++-------\n 1 file changed, 12 insertions(+), 7 deletions(-)\n\ndiff --git a/environment.c b/environment.c\nindex 76ee65e62b..6676e6f5ae 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -745,6 +745,7 @@ int git_default_config(const char *var, const char *value,\n \n void repo_config_values_init(struct repo_config_values *cfg)\n {\n+\t/* section \"core\" config values */\n \tcfg->attributes_file = NULL;\n \tcfg->excludes_file = NULL;\n \tcfg->editor_program = NULL;\n@@ -756,20 +757,24 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->autorebase = AUTOREBASE_NEVER;\n \tcfg->object_creation_mode = OBJECT_CREATION_MODE;\n \tcfg->apply_sparse_checkout = 0;\n-\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n-\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n-\tcfg->ignore_case = 0;\n-\tcfg->trust_executable_bit = 1;\n-\tcfg->has_symlinks = platform_has_symlinks();\n-\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n \tcfg->trust_ctime = 1;\n \tcfg->check_stat = 1;\n \tcfg->zlib_compression_level = Z_BEST_SPEED;\n \tcfg->pack_compression_level = Z_DEFAULT_COMPRESSION;\n \tcfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */\n \tcfg->core_sparse_checkout_cone = 0;\n-\tcfg->sparse_expect_files_outside_of_patterns = 0;\n \tcfg->warn_on_object_refname_ambiguity = 1;\n+\tcfg->protect_hfs = PROTECT_HFS_DEFAULT;\n+\tcfg->protect_ntfs = PROTECT_NTFS_DEFAULT;\n+\tcfg->ignore_case = 0;\n+\tcfg->trust_executable_bit = 1;\n+\tcfg->has_symlinks = platform_has_symlinks();\n+\n+\t/* section \"sparse\" config values */\n+\tcfg->sparse_expect_files_outside_of_patterns = 0;\n+\n+\t/* section \"branch\" config values */\n+\tcfg->branch_track = BRANCH_TRACK_REMOTE;\n }\n \n void repo_config_values_clear(struct repo_config_values *cfg)\n-- \n2.55.0.1003.g10538fe699.dirty\n\n"},{"id":"552537","messageId":"d983e2f0a5e746d3ae0b71c54d29628361edfcf8.1789129924.git.ben.knoble@gmail.com","threadId":"66138","inReplyTo":"cover.1789129924.git.ben.knoble@gmail.com","subject":"[PATCH v7 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-11T12:32:29Z","receivedAt":"2026-09-11T12:33:26Z","isPatch":true,"body":"Racy Git problems persist today, manifesting themselves in the\nperformance of commands like \"git diff\" in new worktrees [1]. We have\nlong had a build knob \"USE_NSEC\" to tell Git to use in-core nanosecond\nprecision when available, which mitigates most if not all racy issues,\nbut most builds we know about don't use it. In part, that's because\nsomeone distributing Git can't safely enable it at compile-time if they\ndon't know exactly what platforms their distribution will be used on.\n\n[1]: https://lore.kernel.org/git/CALnO6CADMJSixqYvL1Yo8qKX5rWhKQ+2OoSEuPUh-yoeK9TseQ@mail.gmail.com\n\nThese days, most platforms are likely to be safe for the USE_NSEC code.\nRegardless, we want to give users the ability to benefit from it. This\nrequires exposing the compile-time gated code as a runtime option.\n\nIn addition, update the Racy Git documentation and other mentions of\nUSE_NSEC in the code.\n\nDue to the conversion from #ifdef to runtime check, using the flag\n\"--ignore-space-change\" may be particularly helpful when viewing changes\nfrom this patch.\n\nSigned-off-by: D. Ben Knoble <ben.knoble@gmail.com>\n---\n\nNotes (benknoble/commits):\n    Related benchmarks: <https://lore.kernel.org/git/CALnO6CBm4g27mWBvD9m6yL0e5YZu3M9_zcUeLZk7QwTgnxMLQA@mail.gmail.com/>\n    CI: <https://github.com/benknoble/git/actions/runs/32365602564>\n\n Documentation/config/core.adoc        |  7 +++++++\n Documentation/technical/racy-git.adoc | 11 ++++++-----\n Makefile                              | 12 +-----------\n builtin/update-index.c                |  2 +-\n compat/posix.h                        |  1 -\n configure.ac                          |  6 ------\n environment.c                         |  8 ++++++++\n environment.h                         |  1 +\n read-cache.c                          | 15 ++++++---------\n statinfo.c                            | 14 +++++++-------\n 10 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc\nindex 340329edc3..0b697f53f1 100644\n--- a/Documentation/config/core.adoc\n+++ b/Documentation/config/core.adoc\n@@ -118,6 +118,13 @@ core.trustctime::\n \tcrawlers and some backup systems).\n \tSee linkgit:git-update-index[1]. True by default.\n \n+core.useNanosec::\n+\tIf true, use nanosecond precision for ctime and mtime\n+\tcomparisons between the index and the working tree (if Git\n+\twas compiled to respect this option).\n+\tThis is unsafe on some platforms;\n+\tsee link:technical/racy-git.html[Racy Git]. False by default.\n+\n core.splitIndex::\n \tIf true, the split-index feature of the index will be used.\n \tSee linkgit:git-update-index[1]. False by default.\ndiff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc\nindex 59bea66c0f..499231585b 100644\n--- a/Documentation/technical/racy-git.adoc\n+++ b/Documentation/technical/racy-git.adoc\n@@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime`\n timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.\n With a `USE_STDEV` compile-time option, `st_dev` is also\n compared, but this is not enabled by default because this member\n-is not stable on network filesystems.  With `USE_NSEC`\n-compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n+is not stable on network filesystems.  With 'core.useNanosec'\n+config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`\n members are also compared. On Linux, this is not enabled by default\n because in-core timestamps can have finer granularity than\n on-disk timestamps, resulting in meaningless changes when an\n@@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git\n ([PATCH] Sync in core time granularity with filesystems,\n 2005-01-04). This patch is included in kernel 2.6.11 and newer, but\n only fixes the issue for file systems with exactly 1 ns or 1 s\n-resolution. Other file systems are still broken in current Linux\n-kernels (e.g. CEPH, CIFS, NTFS, UDF), see\n-https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/\n+resolution.  As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE)\n+were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/.  FAT\n+has been fixed since 2015.  The usual suspects (ext2, ext4, XFS) are known to\n+work, too.\n \n Racy Git\n --------\ndiff --git a/Makefile b/Makefile\nindex fac3e8879c..b4ebcb9e83 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -197,18 +197,11 @@ include shared.mak\n # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,\n # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On\n-# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times\n-# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git\n-# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See\n-# Documentation/technical/racy-git.adoc for details.\n-#\n # Define USE_ST_TIMESPEC if your \"struct stat\" uses \"st_ctimespec\" instead of\n # \"st_ctim\"\n #\n # Define NO_NSEC if your \"struct stat\" does not have \"st_ctim.tv_nsec\"\n-# available.  This automatically turns USE_NSEC off.\n+# available.\n #\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n@@ -1935,9 +1928,6 @@ endif\n ifdef NO_ST_BLOCKS_IN_STRUCT_STAT\n \tBASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT\n endif\n-ifdef USE_NSEC\n-\tBASIC_CFLAGS += -DUSE_NSEC\n-endif\n ifdef USE_ST_TIMESPEC\n \tBASIC_CFLAGS += -DUSE_ST_TIMESPEC\n endif\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 241abd4332..a10c07b636 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -130,7 +130,7 @@ static void xrmdir(const char *path)\n static void avoid_racy(void)\n {\n \t/*\n-\t * not use if we could usleep(10) if USE_NSEC is defined. The\n+\t * not use if we could usleep(10) if core.useNanosec is enabled. The\n \t * field nsec could be there, but the OS could choose to\n \t * ignore it?\n \t */\ndiff --git a/compat/posix.h b/compat/posix.h\nindex e2e794cad7..51ee03233b 100644\n--- a/compat/posix.h\n+++ b/compat/posix.h\n@@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size,\n } while (0)\n \n #ifdef NO_NSEC\n-#undef USE_NSEC\n #define ST_CTIME_NSEC(st) 0\n #define ST_MTIME_NSEC(st) 0\n #else\ndiff --git a/configure.ac b/configure.ac\nindex cfb50112bf..fc956776ab 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv))\n \n ## --enable-FEATURE[=ARG] and --disable-FEATURE\n #\n-# Define USE_NSEC below if you want git to care about sub-second file mtimes\n-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n-# randomly break unless your underlying filesystem supports those sub-second\n-# times (my ext3 doesn't).\n-#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-index perspective.\n \ndiff --git a/environment.c b/environment.c\nindex 6676e6f5ae..c83cf44839 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,\n \t\treturn 0;\n \t}\n \n+#ifndef NO_NSEC\n+\tif (!strcmp(var, \"core.usenanosec\")) {\n+\t\tcfg->use_nanosec = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+#endif\n+\n \t/* Add other config variables here and to Documentation/config.adoc. */\n \treturn platform_core_config(var, value, ctx, cb);\n }\n@@ -769,6 +776,7 @@ void repo_config_values_init(struct repo_config_values *cfg)\n \tcfg->ignore_case = 0;\n \tcfg->trust_executable_bit = 1;\n \tcfg->has_symlinks = platform_has_symlinks();\n+\tcfg->use_nanosec = 0;\n \n \t/* section \"sparse\" config values */\n \tcfg->sparse_expect_files_outside_of_patterns = 0;\ndiff --git a/environment.h b/environment.h\nindex e7ec5b0437..a35534afe5 100644\n--- a/environment.h\n+++ b/environment.h\n@@ -139,6 +139,7 @@ struct repo_config_values {\n \tint ignore_case;\n \tint trust_executable_bit;\n \tint has_symlinks;\n+\tint use_nanosec;\n \n \t/* section \"sparse\" config values */\n \tint sparse_expect_files_outside_of_patterns;\ndiff --git a/read-cache.c b/read-cache.c\nindex 6c449f393d..b32cfd0ef1 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -354,15 +354,12 @@ static int is_racy_stat(const struct index_state *istate,\n \t\t\tconst struct stat_data *sd)\n {\n \treturn (istate->timestamp.sec &&\n-#ifdef USE_NSEC\n-\t\t /* nanosecond timestamped files can also be racy! */\n-\t\t(istate->timestamp.sec < sd->sd_mtime.sec ||\n-\t\t (istate->timestamp.sec == sd->sd_mtime.sec &&\n-\t\t  istate->timestamp.nsec <= sd->sd_mtime.nsec))\n-#else\n-\t\tistate->timestamp.sec <= sd->sd_mtime.sec\n-#endif\n-\t\t);\n+\t\t/* nanosecond timestamped files can also be racy! */\n+\t\t(repo_config_values(istate->repo)->use_nanosec\n+\t\t ? (istate->timestamp.sec < sd->sd_mtime.sec ||\n+\t\t    (istate->timestamp.sec == sd->sd_mtime.sec &&\n+\t\t     istate->timestamp.nsec <= sd->sd_mtime.nsec))\n+\t\t : istate->timestamp.sec <= sd->sd_mtime.sec));\n }\n \n int is_racy_timestamp(const struct index_state *istate,\ndiff --git a/statinfo.c b/statinfo.c\nindex 5e00af127d..d9ddcf9382 100644\n--- a/statinfo.c\n+++ b/statinfo.c\n@@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)\n \t    sd->sd_ctime.sec != (unsigned int)st->st_ctime)\n \t\tchanged |= CTIME_CHANGED;\n \n-#ifdef USE_NSEC\n-\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n-\t\tchanged |= MTIME_CHANGED;\n-\tif (cfg->trust_ctime && cfg->check_stat &&\n-\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n-\t\tchanged |= CTIME_CHANGED;\n-#endif\n+\tif (cfg->use_nanosec) {\n+\t\tif (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))\n+\t\t\tchanged |= MTIME_CHANGED;\n+\t\tif (cfg->trust_ctime && cfg->check_stat &&\n+\t\t    sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))\n+\t\t\tchanged |= CTIME_CHANGED;\n+\t}\n \n \tif (cfg->check_stat) {\n \t\tif (sd->sd_uid != (unsigned int) st->st_uid ||\n-- \n2.55.0.1003.g10538fe699.dirty\n\n"},{"id":"552581","messageId":"xmqqwlsrab5f.fsf@gitster.g","threadId":"66138","inReplyTo":"cover.1789129924.git.ben.knoble@gmail.com","subject":"Re: [PATCH v7 0/3] Convert USE_NSEC to runtime config","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-09-11T18:35:56Z","receivedAt":"2026-09-11T18:36:01Z","isPatch":true,"body":"\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n\n> Topic name: dk/use-nsec-runtime (applied)\n>\n> Topic summary: Expose USE_NSEC as a runtime configuration, since\n> build-time is too early for distributing Git [1]. As a result, common\n> index-related options, like git-diff, are less likely to hit \"racy git\"\n> problems on supported filesystems.\n>\n> [1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n>\n> Built on master (2c78326f81 (The 11th batch, 2026-08-05)).\n>\n> Changes in v7:\n>\n> • documentation typofix\n> • I opted not to finagle #ifdefs more [2] nor to add a \"safe default\n>   when istate->repo is different from the_repository\" (replies to [2])\n\nThese three match exactly what I had when I queued v6, which\nconfused me quite a lot.  It turns out that I have already locally\nreworded the log message of [v6 3/3] \"comparisions\" ;-).\n\nQueued.  Thanks.\n\n\n"},{"id":"552591","messageId":"88372951-1938-43D2-88E9-E3E9A2FA2A85@gmail.com","threadId":"66138","inReplyTo":"xmqqwlsrab5f.fsf@gitster.g","subject":"Re: [PATCH v7 0/3] Convert USE_NSEC to runtime config","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2026-09-11T20:16:28Z","receivedAt":"2026-09-11T20:16:41Z","isPatch":true,"body":"\n> Le 11 sept. 2026 à 14:35, Junio C Hamano <gitster@pobox.com> a écrit :\n> \n> ﻿\"D. Ben Knoble\" <ben.knoble@gmail.com> writes:\n> \n>> Topic name: dk/use-nsec-runtime (applied)\n>> \n>> Topic summary: Expose USE_NSEC as a runtime configuration, since\n>> build-time is too early for distributing Git [1]. As a result, common\n>> index-related options, like git-diff, are less likely to hit \"racy git\"\n>> problems on supported filesystems.\n>> \n>> [1]: https://git.github.io/rev_news/2026/07/31/edition-137/\n>> \n>> Built on master (2c78326f81 (The 11th batch, 2026-08-05)).\n>> \n>> Changes in v7:\n>> \n>> • documentation typofix\n>> • I opted not to finagle #ifdefs more [2] nor to add a \"safe default\n>>  when istate->repo is different from the_repository\" (replies to [2])\n> \n> These three match exactly what I had when I queued v6, which\n> confused me quite a lot.  It turns out that I have already locally\n> reworded the log message of [v6 3/3] \"comparisions\" ;-).\n> \n> Queued.  Thanks.\n\nRight, I should have mentioned you already had this as far as\nI knew. This was primarily a nudge for the (in my view?) stale\nWhat’s Cooking status :)"}]}