From 7211b9e7534e021d7c46117ec0c64482e7930560 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Tue, 13 Aug 2019 11:37:43 -0700 Subject: repo-settings: consolidate some config settings There are a few important config settings that are not loaded during git_default_config. These are instead loaded on-demand. Centralize these config options to a single scan, and store all of the values in a repo_settings struct. The values for each setting are initialized as negative to indicate "unset". This centralization will be particularly important in a later change to introduce "meta" config settings that change the defaults for these config settings. Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano diff --git a/Makefile b/Makefile index 11ccea4..032fe9b 100644 --- a/Makefile +++ b/Makefile @@ -964,6 +964,7 @@ LIB_OBJS += refspec.o LIB_OBJS += ref-filter.o LIB_OBJS += remote.o LIB_OBJS += replace-object.o +LIB_OBJS += repo-settings.o LIB_OBJS += repository.o LIB_OBJS += rerere.o LIB_OBJS += resolve-undo.o diff --git a/builtin/gc.c b/builtin/gc.c index c18efad..4b8fbb9 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -41,7 +41,6 @@ static int aggressive_depth = 50; static int aggressive_window = 250; static int gc_auto_threshold = 6700; static int gc_auto_pack_limit = 50; -static int gc_write_commit_graph; static int detach_auto = 1; static timestamp_t gc_log_expire_time; static const char *gc_log_expire = "1.day.ago"; @@ -148,7 +147,6 @@ static void gc_config(void) git_config_get_int("gc.aggressivedepth", &aggressive_depth); git_config_get_int("gc.auto", &gc_auto_threshold); git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit); - git_config_get_bool("gc.writecommitgraph", &gc_write_commit_graph); git_config_get_bool("gc.autodetach", &detach_auto); git_config_get_expiry("gc.pruneexpire", &prune_expire); git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire); @@ -685,11 +683,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix) clean_pack_garbage(); } - if (gc_write_commit_graph && - write_commit_graph_reachable(get_object_directory(), - !quiet && !daemonized ? COMMIT_GRAPH_PROGRESS : 0, - NULL)) - return 1; + prepare_repo_settings(the_repository); + if (the_repository->settings.gc_write_commit_graph == 1) + write_commit_graph_reachable(get_object_directory(), + !quiet && !daemonized ? COMMIT_GRAPH_PROGRESS : 0, + NULL); if (auto_gc && too_many_loose_objects()) warning(_("There are too many unreachable loose objects; " diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 267c562..f9f7181 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2709,10 +2709,6 @@ static int git_pack_config(const char *k, const char *v, void *cb) use_bitmap_index_default = git_config_bool(k, v); return 0; } - if (!strcmp(k, "pack.usesparse")) { - sparse = git_config_bool(k, v); - return 0; - } if (!strcmp(k, "pack.threads")) { delta_search_threads = git_config_int(k, v); if (delta_search_threads < 0) @@ -3332,6 +3328,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) read_replace_refs = 0; sparse = git_env_bool("GIT_TEST_PACK_SPARSE", 0); + prepare_repo_settings(the_repository); + if (!sparse && the_repository->settings.pack_use_sparse != -1) + sparse = the_repository->settings.pack_use_sparse; + reset_pack_idx_option(&pack_idx_opts); git_config(git_pack_config, NULL); diff --git a/commit-graph.c b/commit-graph.c index b3c4de7..7854e49 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -466,7 +466,6 @@ static void prepare_commit_graph_one(struct repository *r, const char *obj_dir) static int prepare_commit_graph(struct repository *r) { struct object_directory *odb; - int config_value; if (git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD, 0)) die("dying as requested by the '%s' variable on commit-graph load!", @@ -476,9 +475,10 @@ static int prepare_commit_graph(struct repository *r) return !!r->objects->commit_graph; r->objects->commit_graph_attempted = 1; + prepare_repo_settings(r); + if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) && - (repo_config_get_bool(r, "core.commitgraph", &config_value) || - !config_value)) + r->settings.core_commit_graph != 1) /* * This repository is not configured to use commit graphs, so * do not load one. (But report commit_graph_attempted anyway diff --git a/read-cache.c b/read-cache.c index c701f7f..59dbebc 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1599,16 +1599,17 @@ struct cache_entry *refresh_cache_entry(struct index_state *istate, #define INDEX_FORMAT_DEFAULT 3 -static unsigned int get_index_format_default(void) +static unsigned int get_index_format_default(struct repository *r) { char *envversion = getenv("GIT_INDEX_VERSION"); char *endp; - int value; unsigned int version = INDEX_FORMAT_DEFAULT; if (!envversion) { - if (!git_config_get_int("index.version", &value)) - version = value; + prepare_repo_settings(r); + + if (r->settings.index_version >= 0) + version = r->settings.index_version; if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) { warning(_("index.version set, but the value is invalid.\n" "Using version %i"), INDEX_FORMAT_DEFAULT); @@ -2765,7 +2766,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, } if (!istate->version) { - istate->version = get_index_format_default(); + istate->version = get_index_format_default(the_repository); if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0)) init_split_index(istate); } diff --git a/repo-settings.c b/repo-settings.c new file mode 100644 index 0000000..309577f --- /dev/null +++ b/repo-settings.c @@ -0,0 +1,25 @@ +#include "cache.h" +#include "config.h" +#include "repository.h" + +void prepare_repo_settings(struct repository *r) +{ + int value; + + if (r->settings.initialized) + return; + + /* Defaults */ + memset(&r->settings, -1, sizeof(r->settings)); + + if (!repo_config_get_bool(r, "core.commitgraph", &value)) + r->settings.core_commit_graph = value; + if (!repo_config_get_bool(r, "gc.writecommitgraph", &value)) + r->settings.gc_write_commit_graph = value; + + if (!repo_config_get_bool(r, "index.version", &value)) + r->settings.index_version = value; + + if (!repo_config_get_bool(r, "pack.usesparse", &value)) + r->settings.pack_use_sparse = value; +} diff --git a/repository.h b/repository.h index 4fb6a58..cc285ad 100644 --- a/repository.h +++ b/repository.h @@ -11,6 +11,17 @@ struct pathspec; struct raw_object_store; struct submodule_cache; +struct repo_settings { + int initialized; + + int core_commit_graph; + int gc_write_commit_graph; + + int index_version; + + int pack_use_sparse; +}; + struct repository { /* Environment */ /* @@ -72,6 +83,8 @@ struct repository { */ char *submodule_prefix; + struct repo_settings settings; + /* Subsystems */ /* * Repository's config which contains key-value pairs from the usual @@ -157,5 +170,6 @@ int repo_read_index_unmerged(struct repository *); */ void repo_update_index_if_able(struct repository *, struct lock_file *); +void prepare_repo_settings(struct repository *r); #endif /* REPOSITORY_H */ -- cgit v0.10.2-6-g49f6 From b068d9a250246896cc56b9450049b2ed6451ccbb Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Tue, 13 Aug 2019 11:37:45 -0700 Subject: t6501: use 'git gc' in quiet mode t6501-freshen-objects.sh sends the standard error from 'git gc' to a file and verifies that it is empty. This is intended as a way to ensure no warnings are written during the operation. However, as the commit-graph is added as a step to 'git gc', its progress will appear in the output. Pass the '-q' argument to avoid a failing test case when progress is written. Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh index 033871e..f30b484 100755 --- a/t/t6501-freshen-objects.sh +++ b/t/t6501-freshen-objects.sh @@ -137,7 +137,7 @@ test_expect_success 'do not complain about existing broken links (commit)' ' some message EOF commit=$(git hash-object -t commit -w broken-commit) && - git gc 2>stderr && + git gc -q 2>stderr && verbose git cat-file -e $commit && test_must_be_empty stderr ' @@ -147,7 +147,7 @@ test_expect_success 'do not complain about existing broken links (tree)' ' 100644 blob 0000000000000000000000000000000000000003 foo EOF tree=$(git mktree --missing stderr && + git gc -q 2>stderr && git cat-file -e $tree && test_must_be_empty stderr ' @@ -162,7 +162,7 @@ test_expect_success 'do not complain about existing broken links (tag)' ' this is a broken tag EOF tag=$(git hash-object -t tag -w broken-tag) && - git gc 2>stderr && + git gc -q 2>stderr && git cat-file -e $tag && test_must_be_empty stderr ' -- cgit v0.10.2-6-g49f6 From 31b1de6a09bad59cc0d88419925486afc7add277 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Tue, 13 Aug 2019 11:37:45 -0700 Subject: commit-graph: turn on commit-graph by default The commit-graph feature has seen a lot of activity in the past year or so since it was introduced. The feature is a critical performance enhancement for medium- to large-sized repos, and does not significantly hurt small repos. Change the defaults for core.commitGraph and gc.writeCommitGraph to true so users benefit from this feature by default. There are several places in the test suite where the environment variable GIT_TEST_COMMIT_GRAPH is disabled to avoid reading a commit-graph, if it exists. The config option overrides the environment, so swap these. Some GIT_TEST_COMMIT_GRAPH assignments remain, and those are to avoid writing a commit-graph when a new commit is created. Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index 75538d2..e66d79f 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -577,7 +577,7 @@ the `GIT_NOTES_REF` environment variable. See linkgit:git-notes[1]. core.commitGraph:: If true, then git will read the commit-graph file (if it exists) - to parse the graph structure of commits. Defaults to false. See + to parse the graph structure of commits. Defaults to true. See linkgit:git-commit-graph[1] for more information. core.useReplaceRefs:: diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt index 02b92b1..00ea0a6 100644 --- a/Documentation/config/gc.txt +++ b/Documentation/config/gc.txt @@ -63,7 +63,7 @@ gc.writeCommitGraph:: If true, then gc will rewrite the commit-graph file when linkgit:git-gc[1] is run. When using `git gc --auto` the commit-graph will be updated if housekeeping is - required. Default is false. See linkgit:git-commit-graph[1] + required. Default is true. See linkgit:git-commit-graph[1] for details. gc.logExpiry:: diff --git a/repo-settings.c b/repo-settings.c index 309577f..d00b675 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -2,6 +2,8 @@ #include "config.h" #include "repository.h" +#define UPDATE_DEFAULT_BOOL(s,v) do { if (s == -1) { s = v; } } while(0) + void prepare_repo_settings(struct repository *r) { int value; @@ -16,6 +18,8 @@ void prepare_repo_settings(struct repository *r) r->settings.core_commit_graph = value; if (!repo_config_get_bool(r, "gc.writecommitgraph", &value)) r->settings.gc_write_commit_graph = value; + UPDATE_DEFAULT_BOOL(r->settings.core_commit_graph, 1); + UPDATE_DEFAULT_BOOL(r->settings.gc_write_commit_graph, 1); if (!repo_config_get_bool(r, "index.version", &value)) r->settings.index_version = value; diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh index 5bd892f..181ffa4 100755 --- a/t/t0410-partial-clone.sh +++ b/t/t0410-partial-clone.sh @@ -234,7 +234,7 @@ test_expect_success 'rev-list stops traversal at missing and promised commit' ' git -C repo config core.repositoryformatversion 1 && git -C repo config extensions.partialclone "arbitrary string" && - GIT_TEST_COMMIT_GRAPH=0 git -C repo rev-list --exclude-promisor-objects --objects bar >out && + GIT_TEST_COMMIT_GRAPH=0 git -C repo -c core.commitGraph=false rev-list --exclude-promisor-objects --objects bar >out && grep $(git -C repo rev-parse bar) out && ! grep $FOO out ' diff --git a/t/t5307-pack-missing-commit.sh b/t/t5307-pack-missing-commit.sh index dacb440..f4338ab 100755 --- a/t/t5307-pack-missing-commit.sh +++ b/t/t5307-pack-missing-commit.sh @@ -24,11 +24,11 @@ test_expect_success 'check corruption' ' ' test_expect_success 'rev-list notices corruption (1)' ' - test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git rev-list HEAD + test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list HEAD ' test_expect_success 'rev-list notices corruption (2)' ' - test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git rev-list --objects HEAD + test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --objects HEAD ' test_expect_success 'pack-objects notices corruption' ' diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh index 03f45a1..19aa40d 100755 --- a/t/t5324-split-commit-graph.sh +++ b/t/t5324-split-commit-graph.sh @@ -8,6 +8,7 @@ GIT_TEST_COMMIT_GRAPH=0 test_expect_success 'setup repo' ' git init && git config core.commitGraph true && + git config gc.writeCommitGraph false && infodir=".git/objects/info" && graphdir="$infodir/commit-graphs" && test_oid_init @@ -332,6 +333,7 @@ test_expect_success 'split across alternate where alternate is not split' ' git clone --no-hardlinks . alt-split && ( cd alt-split && + rm -f .git/objects/info/commit-graph && echo "$(pwd)"/../.git/objects >.git/objects/info/alternates && test_commit 18 && git commit-graph write --reachable --split && diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh index 545b461..bad02cf 100755 --- a/t/t6011-rev-list-with-bad-commit.sh +++ b/t/t6011-rev-list-with-bad-commit.sh @@ -42,7 +42,7 @@ test_expect_success 'corrupt second commit object' \ ' test_expect_success 'rev-list should fail' ' - test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git rev-list --all > /dev/null + test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null ' test_expect_success 'git repack _MUST_ fail' \ -- cgit v0.10.2-6-g49f6 From ad0fb65999382052cf21408df490d0b39800d487 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Tue, 13 Aug 2019 11:37:46 -0700 Subject: repo-settings: parse core.untrackedCache The core.untrackedCache config setting is slightly complicated, so clarify its use and centralize its parsing into the repo settings. The default value is "keep" (returned as -1), which persists the untracked cache if it exists. If the value is set as "false" (returned as 0), then remove the untracked cache if it exists. If the value is set as "true" (returned as 1), then write the untracked cache and persist it. Instead of relying on magic values of -1, 0, and 1, split these options into an enum. This allows the use of "-1" as a default value. After parsing the config options, if the value is unset we can initialize it to UNTRACKED_CACHE_KEEP. Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano diff --git a/builtin/update-index.c b/builtin/update-index.c index dff2f4b..49302d9 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -966,6 +966,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) struct parse_opt_ctx_t ctx; strbuf_getline_fn getline_fn; int parseopt_state = PARSE_OPT_UNKNOWN; + struct repository *r = the_repository; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, N_("continue refresh even when index needs update"), @@ -1180,11 +1181,12 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) remove_split_index(&the_index); } + prepare_repo_settings(r); switch (untracked_cache) { case UC_UNSPECIFIED: break; case UC_DISABLE: - if (git_config_get_untracked_cache() == 1) + if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE) warning(_("core.untrackedCache is set to true; " "remove or change it, if you really want to " "disable the untracked cache")); @@ -1196,7 +1198,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) return !test_if_untracked_cache_is_supported(); case UC_ENABLE: case UC_FORCE: - if (git_config_get_untracked_cache() == 0) + if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE) warning(_("core.untrackedCache is set to false; " "remove or change it, if you really want to " "enable the untracked cache")); diff --git a/config.c b/config.c index faa57e4..3241dbc 100644 --- a/config.c +++ b/config.c @@ -2277,30 +2277,6 @@ int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestam return -1; /* thing exists but cannot be parsed */ } -int git_config_get_untracked_cache(void) -{ - int val = -1; - const char *v; - - /* Hack for test programs like test-dump-untracked-cache */ - if (ignore_untracked_cache_config) - return -1; - - if (!git_config_get_maybe_bool("core.untrackedcache", &val)) - return val; - - if (!git_config_get_value("core.untrackedcache", &v)) { - if (!strcasecmp(v, "keep")) - return -1; - - error(_("unknown core.untrackedCache value '%s'; " - "using 'keep' default value"), v); - return -1; - } - - return -1; /* default value */ -} - int git_config_get_split_index(void) { int val; diff --git a/read-cache.c b/read-cache.c index 59dbebc..7a07286 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1845,18 +1845,17 @@ static void check_ce_order(struct index_state *istate) static void tweak_untracked_cache(struct index_state *istate) { - switch (git_config_get_untracked_cache()) { - case -1: /* keep: do nothing */ - break; - case 0: /* false */ + struct repository *r = the_repository; + + prepare_repo_settings(r); + + if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE) { remove_untracked_cache(istate); - break; - case 1: /* true */ - add_untracked_cache(istate); - break; - default: /* unknown value: do nothing */ - break; + return; } + + if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE) + add_untracked_cache(istate); } static void tweak_split_index(struct index_state *istate) diff --git a/repo-settings.c b/repo-settings.c index d00b675..abbc656 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -7,6 +7,7 @@ void prepare_repo_settings(struct repository *r) { int value; + char *strval; if (r->settings.initialized) return; @@ -23,7 +24,25 @@ void prepare_repo_settings(struct repository *r) if (!repo_config_get_bool(r, "index.version", &value)) r->settings.index_version = value; + if (!repo_config_get_maybe_bool(r, "core.untrackedcache", &value)) { + if (value == 0) + r->settings.core_untracked_cache = UNTRACKED_CACHE_REMOVE; + else + r->settings.core_untracked_cache = UNTRACKED_CACHE_WRITE; + } else if (!repo_config_get_string(r, "core.untrackedcache", &strval)) { + if (!strcasecmp(strval, "keep")) + r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP; + + free(strval); + } + if (!repo_config_get_bool(r, "pack.usesparse", &value)) r->settings.pack_use_sparse = value; + + /* Hack for test programs like test-dump-untracked-cache */ + if (ignore_untracked_cache_config) + r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP; + else + UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_KEEP); } diff --git a/repository.h b/repository.h index cc285ad..cf7ff07 100644 --- a/repository.h +++ b/repository.h @@ -11,6 +11,13 @@ struct pathspec; struct raw_object_store; struct submodule_cache; +enum untracked_cache_setting { + UNTRACKED_CACHE_UNSET = -1, + UNTRACKED_CACHE_REMOVE = 0, + UNTRACKED_CACHE_KEEP = 1, + UNTRACKED_CACHE_WRITE = 2 +}; + struct repo_settings { int initialized; @@ -18,6 +25,7 @@ struct repo_settings { int gc_write_commit_graph; int index_version; + enum untracked_cache_setting core_untracked_cache; int pack_use_sparse; }; -- cgit v0.10.2-6-g49f6 From c6cc4c5afd2efd5f8081a3839b48d003de4e094f Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Tue, 13 Aug 2019 11:37:47 -0700 Subject: repo-settings: create feature.manyFiles setting The feature.manyFiles setting is suitable for repos with many files in the working directory. By setting index.version=4 and core.untrackedCache=true, commands such as 'git status' should improve. While adding this setting, modify the index version precedence tests to check how this setting overrides the default for index.version is unset. Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano diff --git a/Documentation/config.txt b/Documentation/config.txt index e3f5bc3..77f3b14 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -345,6 +345,8 @@ include::config/difftool.txt[] include::config/fastimport.txt[] +include::config/feature.txt[] + include::config/fetch.txt[] include::config/format.txt[] diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index e66d79f..852d2ba 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -86,7 +86,9 @@ core.untrackedCache:: it will automatically be removed, if set to `false`. Before setting it to `true`, you should check that mtime is working properly on your system. - See linkgit:git-update-index[1]. `keep` by default. + See linkgit:git-update-index[1]. `keep` by default, unless + `feature.manyFiles` is enabled which sets this setting to + `true` by default. core.checkStat:: When missing or is set to `default`, many fields in the stat diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt new file mode 100644 index 0000000..8ea198a --- /dev/null +++ b/Documentation/config/feature.txt @@ -0,0 +1,15 @@ +feature.*:: + The config settings that start with `feature.` modify the defaults of + a group of other config settings. These groups are created by the Git + developer community as recommended defaults and are subject to change. + In particular, new config options may be added with different defaults. + +feature.manyFiles:: + Enable config options that optimize for repos with many files in the + working directory. With many files, commands such as `git status` and + `git checkout` may be slow and these new defaults improve performance: ++ +* `index.version=4` enables path-prefix compression in the index. ++ +* `core.untrackedCache=true` enables the untracked cache. This setting assumes +that mtime is working on your machine. diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt index f181503..7cb50b3 100644 --- a/Documentation/config/index.txt +++ b/Documentation/config/index.txt @@ -24,3 +24,4 @@ index.threads:: index.version:: Specify the version with which new index files should be initialized. This does not affect existing repositories. + If `feature.manyFiles` is enabled, then the default is 4. diff --git a/repo-settings.c b/repo-settings.c index abbc656..d5bf906 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -36,9 +36,12 @@ void prepare_repo_settings(struct repository *r) free(strval); } - if (!repo_config_get_bool(r, "pack.usesparse", &value)) r->settings.pack_use_sparse = value; + if (!repo_config_get_bool(r, "feature.manyfiles", &value) && value) { + UPDATE_DEFAULT_BOOL(r->settings.index_version, 4); + UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_WRITE); + } /* Hack for test programs like test-dump-untracked-cache */ if (ignore_untracked_cache_config) diff --git a/t/t1600-index.sh b/t/t1600-index.sh index 42962ed..c77721b 100755 --- a/t/t1600-index.sh +++ b/t/t1600-index.sh @@ -59,17 +59,38 @@ test_expect_success 'out of bounds index.version issues warning' ' ) ' -test_expect_success 'GIT_INDEX_VERSION takes precedence over config' ' +test_index_version () { + INDEX_VERSION_CONFIG=$1 && + FEATURE_MANY_FILES=$2 && + ENV_VAR_VERSION=$3 + EXPECTED_OUTPUT_VERSION=$4 && ( rm -f .git/index && - GIT_INDEX_VERSION=4 && - export GIT_INDEX_VERSION && - git config --add index.version 2 && + rm -f .git/config && + if test "$INDEX_VERSION_CONFIG" -ne 0 + then + git config --add index.version $INDEX_VERSION_CONFIG + fi && + git config --add feature.manyFiles $FEATURE_MANY_FILES + if test "$ENV_VAR_VERSION" -ne 0 + then + GIT_INDEX_VERSION=$ENV_VAR_VERSION && + export GIT_INDEX_VERSION + else + unset GIT_INDEX_VERSION + fi && git add a 2>&1 && - echo 4 >expect && + echo $EXPECTED_OUTPUT_VERSION >expect && test-tool index-version <.git/index >actual && test_cmp expect actual ) +} + +test_expect_success 'index version config precedence' ' + test_index_version 2 false 4 4 && + test_index_version 2 true 0 2 && + test_index_version 0 true 0 4 && + test_index_version 0 true 2 2 ' test_done -- cgit v0.10.2-6-g49f6 From aaf633c2ad10b47af7623c130ddfe7231658c7e4 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Tue, 13 Aug 2019 11:37:48 -0700 Subject: repo-settings: create feature.experimental setting The 'feature.experimental' setting includes config options that are not committed to become defaults, but could use additional testing. Update the following config settings to take new defaults, and to use the repo_settings struct if not already using them: * 'pack.useSparse=true' * 'fetch.negotiationAlgorithm=skipping' In the case of fetch.negotiationAlgorithm, the existing logic would load the config option only when about to use the setting, so had a die() statement on an unknown string value. This is removed as now the config is parsed under prepare_repo_settings(). In general, this die() is probably misplaced and not valuable. A test was removed that checked this die() statement executed. Signed-off-by: Derrick Stolee Signed-off-by: Junio C Hamano diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt index 8ea198a..545522f 100644 --- a/Documentation/config/feature.txt +++ b/Documentation/config/feature.txt @@ -4,6 +4,20 @@ feature.*:: developer community as recommended defaults and are subject to change. In particular, new config options may be added with different defaults. +feature.experimental:: + Enable config options that are new to Git, and are being considered for + future defaults. Config settings included here may be added or removed + with each release, including minor version updates. These settings may + have unintended interactions since they are so new. Please enable this + setting if you are interested in providing feedback on experimental + features. The new default values are: ++ +* `pack.useSparse=true` uses a new algorithm when constructing a pack-file +which can improve `git push` performance in repos with many files. ++ +* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by +skipping more commits at a time, reducing the number of round trips. + feature.manyFiles:: Enable config options that optimize for repos with many files in the working directory. With many files, commands such as `git status` and diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt index ba890b5..d402110 100644 --- a/Documentation/config/fetch.txt +++ b/Documentation/config/fetch.txt @@ -59,7 +59,8 @@ fetch.negotiationAlgorithm:: effort to converge faster, but may result in a larger-than-necessary packfile; The default is "default" which instructs Git to use the default algorithm that never skips commits (unless the server has acknowledged it or one - of its descendants). + of its descendants). If `feature.experimental` is enabled, then this + setting defaults to "skipping". Unknown values will cause 'git fetch' to error out. + See also the `--negotiation-tip` option for linkgit:git-fetch[1]. diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt index 9cdcfa7..1d66f0c 100644 --- a/Documentation/config/pack.txt +++ b/Documentation/config/pack.txt @@ -112,7 +112,8 @@ pack.useSparse:: objects. This can have significant performance benefits when computing a pack to send a small change. However, it is possible that extra objects are added to the pack-file if the included - commits contain certain types of direct renames. + commits contain certain types of direct renames. Default is `false` + unless `feature.experimental` is enabled. pack.writeBitmaps (deprecated):: This is a deprecated synonym for `repack.writeBitmaps`. diff --git a/fetch-negotiator.c b/fetch-negotiator.c index d6d685c..0a1357d 100644 --- a/fetch-negotiator.c +++ b/fetch-negotiator.c @@ -2,19 +2,20 @@ #include "fetch-negotiator.h" #include "negotiator/default.h" #include "negotiator/skipping.h" +#include "repository.h" -void fetch_negotiator_init(struct fetch_negotiator *negotiator, - const char *algorithm) +void fetch_negotiator_init(struct repository *r, + struct fetch_negotiator *negotiator) { - if (algorithm) { - if (!strcmp(algorithm, "skipping")) { - skipping_negotiator_init(negotiator); - return; - } else if (!strcmp(algorithm, "default")) { - /* Fall through to default initialization */ - } else { - die("unknown fetch negotiation algorithm '%s'", algorithm); - } + prepare_repo_settings(r); + switch(r->settings.fetch_negotiation_algorithm) { + case FETCH_NEGOTIATION_SKIPPING: + skipping_negotiator_init(negotiator); + return; + + case FETCH_NEGOTIATION_DEFAULT: + default: + default_negotiator_init(negotiator); + return; } - default_negotiator_init(negotiator); } diff --git a/fetch-negotiator.h b/fetch-negotiator.h index 9e3967c..ea78868 100644 --- a/fetch-negotiator.h +++ b/fetch-negotiator.h @@ -2,6 +2,7 @@ #define FETCH_NEGOTIATOR_H struct commit; +struct repository; /* * An object that supplies the information needed to negotiate the contents of @@ -52,7 +53,7 @@ struct fetch_negotiator { void *data; }; -void fetch_negotiator_init(struct fetch_negotiator *negotiator, - const char *algorithm); +void fetch_negotiator_init(struct repository *r, + struct fetch_negotiator *negotiator); #endif diff --git a/fetch-pack.c b/fetch-pack.c index 65be043..d81f47c 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -36,7 +36,6 @@ static int agent_supported; static int server_supports_filtering; static struct lock_file shallow_lock; static const char *alternate_shallow_file; -static char *negotiation_algorithm; static struct strbuf fsck_msg_types = STRBUF_INIT; /* Remember to update object flag allocation in object.h */ @@ -892,12 +891,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, struct shallow_info *si, char **pack_lockfile) { + struct repository *r = the_repository; struct ref *ref = copy_ref_list(orig_ref); struct object_id oid; const char *agent_feature; int agent_len; struct fetch_negotiator negotiator; - fetch_negotiator_init(&negotiator, negotiation_algorithm); + fetch_negotiator_init(r, &negotiator); sort_ref_list(&ref, ref_compare_name); QSORT(sought, nr_sought, cmp_ref_by_name); @@ -911,7 +911,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, if (server_supports("shallow")) print_verbose(args, _("Server supports %s"), "shallow"); - else if (args->depth > 0 || is_repository_shallow(the_repository)) + else if (args->depth > 0 || is_repository_shallow(r)) die(_("Server does not support shallow clients")); if (args->depth > 0 || args->deepen_since || args->deepen_not) args->deepen = 1; @@ -1379,6 +1379,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, struct shallow_info *si, char **pack_lockfile) { + struct repository *r = the_repository; struct ref *ref = copy_ref_list(orig_ref); enum fetch_state state = FETCH_CHECK_LOCAL; struct oidset common = OIDSET_INIT; @@ -1386,7 +1387,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, int in_vain = 0; int haves_to_send = INITIAL_FLUSH; struct fetch_negotiator negotiator; - fetch_negotiator_init(&negotiator, negotiation_algorithm); + fetch_negotiator_init(r, &negotiator); packet_reader_init(&reader, fd[0], NULL, 0, PACKET_READ_CHOMP_NEWLINE | PACKET_READ_DIE_ON_ERR_PACKET); @@ -1505,8 +1506,6 @@ static void fetch_pack_config(void) git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta); git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects); git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects); - git_config_get_string("fetch.negotiationalgorithm", - &negotiation_algorithm); git_config(fetch_pack_config_cb, NULL); } diff --git a/repo-settings.c b/repo-settings.c index d5bf906..3779b85 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -36,16 +36,29 @@ void prepare_repo_settings(struct repository *r) free(strval); } + if (!repo_config_get_string(r, "fetch.negotiationalgorithm", &strval)) { + if (!strcasecmp(strval, "skipping")) + r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING; + else + r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_DEFAULT; + } + if (!repo_config_get_bool(r, "pack.usesparse", &value)) r->settings.pack_use_sparse = value; if (!repo_config_get_bool(r, "feature.manyfiles", &value) && value) { UPDATE_DEFAULT_BOOL(r->settings.index_version, 4); UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_WRITE); } + if (!repo_config_get_bool(r, "feature.experimental", &value) && value) { + UPDATE_DEFAULT_BOOL(r->settings.pack_use_sparse, 1); + UPDATE_DEFAULT_BOOL(r->settings.fetch_negotiation_algorithm, FETCH_NEGOTIATION_SKIPPING); + } /* Hack for test programs like test-dump-untracked-cache */ if (ignore_untracked_cache_config) r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP; else UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_KEEP); + + UPDATE_DEFAULT_BOOL(r->settings.fetch_negotiation_algorithm, FETCH_NEGOTIATION_DEFAULT); } diff --git a/repository.h b/repository.h index cf7ff07..4da275e 100644 --- a/repository.h +++ b/repository.h @@ -18,6 +18,13 @@ enum untracked_cache_setting { UNTRACKED_CACHE_WRITE = 2 }; +enum fetch_negotiation_setting { + FETCH_NEGOTIATION_UNSET = -1, + FETCH_NEGOTIATION_NONE = 0, + FETCH_NEGOTIATION_DEFAULT = 1, + FETCH_NEGOTIATION_SKIPPING = 2, +}; + struct repo_settings { int initialized; @@ -28,6 +35,7 @@ struct repo_settings { enum untracked_cache_setting core_untracked_cache; int pack_use_sparse; + enum fetch_negotiation_setting fetch_negotiation_algorithm; }; struct repository { diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh index 8a14be5..f70cbcc 100755 --- a/t/t5552-skipping-fetch-negotiator.sh +++ b/t/t5552-skipping-fetch-negotiator.sh @@ -60,29 +60,6 @@ test_expect_success 'commits with no parents are sent regardless of skip distanc have_not_sent c6 c4 c3 ' -test_expect_success 'unknown fetch.negotiationAlgorithm values error out' ' - rm -rf server client trace && - git init server && - test_commit -C server to_fetch && - - git init client && - test_commit -C client on_client && - git -C client checkout on_client && - - test_config -C client fetch.negotiationAlgorithm invalid && - test_must_fail git -C client fetch "$(pwd)/server" 2>err && - test_i18ngrep "unknown fetch negotiation algorithm" err && - - # Explicit "default" value - test_config -C client fetch.negotiationAlgorithm default && - git -C client -c fetch.negotiationAlgorithm=default fetch "$(pwd)/server" && - - # Implementation detail: If there is nothing to fetch, we will not error out - test_config -C client fetch.negotiationAlgorithm invalid && - git -C client fetch "$(pwd)/server" 2>err && - test_i18ngrep ! "unknown fetch negotiation algorithm" err -' - test_expect_success 'when two skips collide, favor the larger one' ' rm -rf server client trace && git init server && -- cgit v0.10.2-6-g49f6