diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc index e82a09daa0..b0a2dc4fc9 100644 --- a/Documentation/config/core.adoc +++ b/Documentation/config/core.adoc @@ -118,6 +118,12 @@ core.trustctime:: crawlers and some backup systems). See linkgit:git-update-index[1]. True by default. +core.useNanosec:: + If true, use nanosecond precision for ctime and mtime + comparisions between the index and the working tree (if Git + was compiled to store it). + See link:technical/racy-git.html[Racy Git]. False by default. + core.splitIndex:: If true, the split-index feature of the index will be used. See linkgit:git-update-index[1]. False by default. diff --git a/Documentation/meson.build b/Documentation/meson.build index 85f37da47e..99cb1cf34a 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -381,13 +381,18 @@ foreach manpage, category : manpages output: fs.stem(manpage) + '.xml', ) + man_base_url = 'file://' + htmldir + '/' + if get_option('man_base_url') != '' + man_base_url = get_option('man_base_url') + endif + doc_targets += custom_target( command: [ xmlto, '-m', '@INPUT0@', '-m', '@INPUT1@', '--stringparam', - 'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'), + 'man.base.url.for.relative.links=' + man_base_url, 'man', manpage_xml_target, '-o', diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc index 59bea66c0f..499231585b 100644 --- a/Documentation/technical/racy-git.adoc +++ b/Documentation/technical/racy-git.adoc @@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime` timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members. With a `USE_STDEV` compile-time option, `st_dev` is also compared, but this is not enabled by default because this member -is not stable on network filesystems. With `USE_NSEC` -compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec` +is not stable on network filesystems. With 'core.useNanosec' +config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec` members are also compared. On Linux, this is not enabled by default because in-core timestamps can have finer granularity than on-disk timestamps, resulting in meaningless changes when an @@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git ([PATCH] Sync in core time granularity with filesystems, 2005-01-04). This patch is included in kernel 2.6.11 and newer, but only fixes the issue for file systems with exactly 1 ns or 1 s -resolution. Other file systems are still broken in current Linux -kernels (e.g. CEPH, CIFS, NTFS, UDF), see -https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/ +resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE) +were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT +has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to +work, too. Racy Git -------- diff --git a/Makefile b/Makefile index c21e2ca5d8..b7617bdb03 100644 --- a/Makefile +++ b/Makefile @@ -200,18 +200,11 @@ include shared.mak # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback, # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299) # -# Define USE_NSEC below if you want git to care about sub-second file mtimes -# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On -# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times -# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git -# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See -# Documentation/technical/racy-git.adoc for details. -# # Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of # "st_ctim" # # Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" -# available. This automatically turns USE_NSEC off. +# available. # # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. @@ -1943,9 +1936,6 @@ endif ifdef NO_ST_BLOCKS_IN_STRUCT_STAT BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT endif -ifdef USE_NSEC - BASIC_CFLAGS += -DUSE_NSEC -endif ifdef USE_ST_TIMESPEC BASIC_CFLAGS += -DUSE_ST_TIMESPEC endif diff --git a/builtin/update-index.c b/builtin/update-index.c index 241abd4332..8e0c25655f 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -130,7 +130,7 @@ static void xrmdir(const char *path) static void avoid_racy(void) { /* - * not use if we could usleep(10) if USE_NSEC is defined. The + * not use if we could usleep(10) if core.useNanosec is defined. The * field nsec could be there, but the OS could choose to * ignore it? */ diff --git a/compat/posix.h b/compat/posix.h index 71cc731620..108d38e0df 100644 --- a/compat/posix.h +++ b/compat/posix.h @@ -501,7 +501,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size, } while (0) #ifdef NO_NSEC -#undef USE_NSEC #define ST_CTIME_NSEC(st) 0 #define ST_MTIME_NSEC(st) 0 #else diff --git a/configure.ac b/configure.ac index cfb50112bf..fc956776ab 100644 --- a/configure.ac +++ b/configure.ac @@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv)) ## --enable-FEATURE[=ARG] and --disable-FEATURE # -# Define USE_NSEC below if you want git to care about sub-second file mtimes -# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and -# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely -# randomly break unless your underlying filesystem supports those sub-second -# times (my ext3 doesn't). -# # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. diff --git a/environment.c b/environment.c index 31923e04cf..2933b25896 100644 --- a/environment.c +++ b/environment.c @@ -572,6 +572,11 @@ int git_default_core_config(const char *var, const char *value, return 0; } + if (!strcmp(var, "core.usenanosec")) { + cfg->use_nanosec = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.adoc. */ return platform_core_config(var, value, ctx, cb); } @@ -746,6 +751,7 @@ int git_default_config(const char *var, const char *value, void repo_config_values_init(struct repo_config_values *cfg) { + /* section "core" config values */ cfg->attributes_file = NULL; cfg->excludes_file = NULL; cfg->editor_program = NULL; @@ -757,20 +763,25 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->autorebase = AUTOREBASE_NEVER; cfg->object_creation_mode = OBJECT_CREATION_MODE; cfg->apply_sparse_checkout = 0; - cfg->protect_hfs = PROTECT_HFS_DEFAULT; - cfg->protect_ntfs = PROTECT_NTFS_DEFAULT; - cfg->ignore_case = 0; - cfg->trust_executable_bit = 1; - cfg->has_symlinks = platform_has_symlinks(); - cfg->branch_track = BRANCH_TRACK_REMOTE; cfg->trust_ctime = 1; cfg->check_stat = 1; cfg->zlib_compression_level = Z_BEST_SPEED; cfg->pack_compression_level = Z_DEFAULT_COMPRESSION; cfg->precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ cfg->core_sparse_checkout_cone = 0; - cfg->sparse_expect_files_outside_of_patterns = 0; cfg->warn_on_object_refname_ambiguity = 1; + cfg->protect_hfs = PROTECT_HFS_DEFAULT; + cfg->protect_ntfs = PROTECT_NTFS_DEFAULT; + cfg->ignore_case = 0; + cfg->trust_executable_bit = 1; + cfg->has_symlinks = platform_has_symlinks(); + cfg->use_nanosec = 0; + + /* section "sparse" config values */ + cfg->sparse_expect_files_outside_of_patterns = 0; + + /* section "branch" config values */ + cfg->branch_track = BRANCH_TRACK_REMOTE; } void repo_config_values_clear(struct repo_config_values *cfg) diff --git a/environment.h b/environment.h index 67fd387d35..59cb06f0a0 100644 --- a/environment.h +++ b/environment.h @@ -138,6 +138,7 @@ struct repo_config_values { int ignore_case; int trust_executable_bit; int has_symlinks; + int use_nanosec; int sparse_expect_files_outside_of_patterns; enum branch_track branch_track; }; diff --git a/meson_options.txt b/meson_options.txt index becf4689bf..5fecb97daf 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -115,6 +115,8 @@ option('default_help_format', type: 'combo', choices: ['man', 'html', 'platform' description: 'Default format used when executing git-help(1).') option('docs_backend', type: 'combo', choices: ['asciidoc', 'asciidoctor', 'auto'], value: 'auto', description: 'Which backend to use to generate documentation.') +option('man_base_url', type: 'string', value: '', + description: 'The base URL to use for relative links in manuals') # Testing. option('benchmarks', type: 'feature', value: 'auto', diff --git a/read-cache.c b/read-cache.c index c076984858..e5e7e06d0f 100644 --- a/read-cache.c +++ b/read-cache.c @@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st) static int is_racy_stat(const struct index_state *istate, const struct stat_data *sd) { + int use_nsec = 0; + repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec); + return (istate->timestamp.sec && -#ifdef USE_NSEC - /* nanosecond timestamped files can also be racy! */ - (istate->timestamp.sec < sd->sd_mtime.sec || - (istate->timestamp.sec == sd->sd_mtime.sec && - istate->timestamp.nsec <= sd->sd_mtime.nsec)) -#else - istate->timestamp.sec <= sd->sd_mtime.sec -#endif + /* nanosecond timestamped files can also be racy! */ + use_nsec + ? (istate->timestamp.sec < sd->sd_mtime.sec || + (istate->timestamp.sec == sd->sd_mtime.sec && + istate->timestamp.nsec <= sd->sd_mtime.nsec)) + : istate->timestamp.sec <= sd->sd_mtime.sec ); } diff --git a/statinfo.c b/statinfo.c index 5e00af127d..d9ddcf9382 100644 --- a/statinfo.c +++ b/statinfo.c @@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st) sd->sd_ctime.sec != (unsigned int)st->st_ctime) changed |= CTIME_CHANGED; -#ifdef USE_NSEC - if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) - changed |= MTIME_CHANGED; - if (cfg->trust_ctime && cfg->check_stat && - sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) - changed |= CTIME_CHANGED; -#endif + if (cfg->use_nanosec) { + if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) + changed |= MTIME_CHANGED; + if (cfg->trust_ctime && cfg->check_stat && + sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) + changed |= CTIME_CHANGED; + } if (cfg->check_stat) { if (sd->sd_uid != (unsigned int) st->st_uid ||