Skip to content

Commit da76859

Browse files
committed
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' * 'merge.directoryRenames=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 <dstolee@microsoft.com>
1 parent 63b522a commit da76859

13 files changed

+107
-65
lines changed

Documentation/config/feature.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@ feature.*::
44
developer community as recommended defaults and are subject to change.
55
In particular, new config options may be added with different defaults.
66

7+
feature.experimental::
8+
Enable config options that are new to Git, and are being considered for
9+
future defaults. Config settings included here may be added or removed
10+
with each release, including minor version updates. These settings may
11+
have unintended interactions since they are so new. Please enable this
12+
setting if you are interested in providing feedback on experimental
13+
features. The new default values are:
14+
+
15+
* `pack.useSparse=true` uses a new algorithm when constructing a pack-file
16+
which can improve `git push` performance in repos with many files.
17+
+
18+
* `merge.directoryRenames=true` uses a new algorithm for detecting renames by
19+
using entire directories at a time instead of single files at a time.
20+
+
21+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
22+
skipping more commits at a time, reducing the number of round trips.
23+
724
feature.manyCommits::
825
Enable config options that optimize for repos with many commits. This
926
setting is recommended for repos with at least 100,000 commits. The

Documentation/config/fetch.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ fetch.negotiationAlgorithm::
5959
effort to converge faster, but may result in a larger-than-necessary
6060
packfile; The default is "default" which instructs Git to use the default algorithm
6161
that never skips commits (unless the server has acknowledged it or one
62-
of its descendants).
62+
of its descendants). If `feature.experimental` is enabled, then this
63+
setting defaults to "skipping".
6364
Unknown values will cause 'git fetch' to error out.
6465
+
6566
See also the `--negotiation-tip` option for linkgit:git-fetch[1].

Documentation/config/merge.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ merge.directoryRenames::
5454
moved into the new directory. If set to "conflict", a conflict
5555
will be reported for such paths. If merge.renames is false,
5656
merge.directoryRenames is ignored and treated as false. Defaults
57-
to "conflict".
57+
to "conflict" unless `feature.experimental` is enabled and the
58+
default is "true".
5859

5960
merge.renormalize::
6061
Tell Git that canonical representation of files in the

Documentation/config/pack.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ pack.useSparse::
112112
objects. This can have significant performance benefits when
113113
computing a pack to send a small change. However, it is possible
114114
that extra objects are added to the pack-file if the included
115-
commits contain certain types of direct renames.
115+
commits contain certain types of direct renames. Default is `false`
116+
unless `feature.experimental` is enabled.
116117

117118
pack.writeBitmaps (deprecated)::
118119
This is a deprecated synonym for `repack.writeBitmaps`.

builtin/am.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "string-list.h"
3535
#include "packfile.h"
3636
#include "repository.h"
37+
#include "repo-settings.h"
3738

3839
/**
3940
* Returns the length of the first line of msg.
@@ -1538,7 +1539,8 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
15381539
o.branch1 = "HEAD";
15391540
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
15401541
o.branch2 = their_tree_name;
1541-
o.detect_directory_renames = 0;
1542+
prepare_repo_settings(the_repository);
1543+
the_repository->settings->merge_directory_renames = 0;
15421544

15431545
if (state->quiet)
15441546
o.verbosity = 0;

fetch-negotiator.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@
22
#include "fetch-negotiator.h"
33
#include "negotiator/default.h"
44
#include "negotiator/skipping.h"
5+
#include "repository.h"
6+
#include "repo-settings.h"
57

6-
void fetch_negotiator_init(struct fetch_negotiator *negotiator,
7-
const char *algorithm)
8+
void fetch_negotiator_init(struct repository *r,
9+
struct fetch_negotiator *negotiator)
810
{
9-
if (algorithm) {
10-
if (!strcmp(algorithm, "skipping")) {
11-
skipping_negotiator_init(negotiator);
12-
return;
13-
} else if (!strcmp(algorithm, "default")) {
14-
/* Fall through to default initialization */
15-
} else {
16-
die("unknown fetch negotiation algorithm '%s'", algorithm);
17-
}
11+
prepare_repo_settings(r);
12+
switch(r->settings->fetch_negotiation_algorithm) {
13+
case FETCH_NEGOTIATION_SKIPPING:
14+
skipping_negotiator_init(negotiator);
15+
return;
16+
17+
case FETCH_NEGOTIATION_DEFAULT:
18+
default:
19+
default_negotiator_init(negotiator);
20+
return;
1821
}
19-
default_negotiator_init(negotiator);
2022
}

fetch-negotiator.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define FETCH_NEGOTIATOR_H
33

44
struct commit;
5+
struct repository;
56

67
/*
78
* An object that supplies the information needed to negotiate the contents of
@@ -52,7 +53,7 @@ struct fetch_negotiator {
5253
void *data;
5354
};
5455

55-
void fetch_negotiator_init(struct fetch_negotiator *negotiator,
56-
const char *algorithm);
56+
void fetch_negotiator_init(struct repository *r,
57+
struct fetch_negotiator *negotiator);
5758

5859
#endif

fetch-pack.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ static int agent_supported;
3636
static int server_supports_filtering;
3737
static struct lock_file shallow_lock;
3838
static const char *alternate_shallow_file;
39-
static char *negotiation_algorithm;
4039
static struct strbuf fsck_msg_types = STRBUF_INIT;
4140

4241
/* Remember to update object flag allocation in object.h */
@@ -892,12 +891,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
892891
struct shallow_info *si,
893892
char **pack_lockfile)
894893
{
894+
struct repository *r = the_repository;
895895
struct ref *ref = copy_ref_list(orig_ref);
896896
struct object_id oid;
897897
const char *agent_feature;
898898
int agent_len;
899899
struct fetch_negotiator negotiator;
900-
fetch_negotiator_init(&negotiator, negotiation_algorithm);
900+
fetch_negotiator_init(r, &negotiator);
901901

902902
sort_ref_list(&ref, ref_compare_name);
903903
QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -911,7 +911,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
911911

912912
if (server_supports("shallow"))
913913
print_verbose(args, _("Server supports %s"), "shallow");
914-
else if (args->depth > 0 || is_repository_shallow(the_repository))
914+
else if (args->depth > 0 || is_repository_shallow(r))
915915
die(_("Server does not support shallow clients"));
916916
if (args->depth > 0 || args->deepen_since || args->deepen_not)
917917
args->deepen = 1;
@@ -1379,14 +1379,15 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
13791379
struct shallow_info *si,
13801380
char **pack_lockfile)
13811381
{
1382+
struct repository *r = the_repository;
13821383
struct ref *ref = copy_ref_list(orig_ref);
13831384
enum fetch_state state = FETCH_CHECK_LOCAL;
13841385
struct oidset common = OIDSET_INIT;
13851386
struct packet_reader reader;
13861387
int in_vain = 0;
13871388
int haves_to_send = INITIAL_FLUSH;
13881389
struct fetch_negotiator negotiator;
1389-
fetch_negotiator_init(&negotiator, negotiation_algorithm);
1390+
fetch_negotiator_init(r, &negotiator);
13901391
packet_reader_init(&reader, fd[0], NULL, 0,
13911392
PACKET_READ_CHOMP_NEWLINE |
13921393
PACKET_READ_DIE_ON_ERR_PACKET);
@@ -1505,8 +1506,6 @@ static void fetch_pack_config(void)
15051506
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
15061507
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
15071508
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
1508-
git_config_get_string("fetch.negotiationalgorithm",
1509-
&negotiation_algorithm);
15101509

15111510
git_config(fetch_pack_config_cb, NULL);
15121511
}

merge-recursive.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "submodule.h"
2929
#include "revision.h"
3030
#include "commit-reach.h"
31+
#include "repo-settings.h"
3132

3233
struct path_hashmap_entry {
3334
struct hashmap_entry e;
@@ -1375,10 +1376,14 @@ static int handle_rename_via_dir(struct merge_options *opt,
13751376
* there is no content merge to do; just move the file into the
13761377
* desired final location.
13771378
*/
1379+
struct repository *r = the_repository;
13781380
const struct rename *ren = ci->ren1;
13791381
const struct diff_filespec *dest = ren->pair->two;
13801382
char *file_path = dest->path;
1381-
int mark_conflicted = (opt->detect_directory_renames == 1);
1383+
int mark_conflicted;
1384+
1385+
prepare_repo_settings(r);
1386+
mark_conflicted = (r->settings->merge_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT);
13821387
assert(ren->dir_rename_original_dest);
13831388

13841389
if (!opt->call_depth && would_lose_untracked(opt, dest->path)) {
@@ -2850,6 +2855,7 @@ static int detect_and_process_renames(struct merge_options *opt,
28502855
struct string_list *entries,
28512856
struct rename_info *ri)
28522857
{
2858+
struct repository *r = the_repository;
28532859
struct diff_queue_struct *head_pairs, *merge_pairs;
28542860
struct hashmap *dir_re_head, *dir_re_merge;
28552861
int clean = 1;
@@ -2863,7 +2869,8 @@ static int detect_and_process_renames(struct merge_options *opt,
28632869
head_pairs = get_diffpairs(opt, common, head);
28642870
merge_pairs = get_diffpairs(opt, common, merge);
28652871

2866-
if (opt->detect_directory_renames) {
2872+
prepare_repo_settings(r);
2873+
if (r->settings->merge_directory_renames) {
28672874
dir_re_head = get_directory_renames(head_pairs);
28682875
dir_re_merge = get_directory_renames(merge_pairs);
28692876

@@ -3112,6 +3119,7 @@ static int handle_rename_normal(struct merge_options *opt,
31123119
const struct diff_filespec *b,
31133120
struct rename_conflict_info *ci)
31143121
{
3122+
struct repository *r = the_repository;
31153123
struct rename *ren = ci->ren1;
31163124
struct merge_file_info mfi;
31173125
int clean;
@@ -3121,7 +3129,9 @@ static int handle_rename_normal(struct merge_options *opt,
31213129
clean = handle_content_merge(&mfi, opt, path, was_dirty(opt, path),
31223130
o, a, b, ci);
31233131

3124-
if (clean && opt->detect_directory_renames == 1 &&
3132+
prepare_repo_settings(r);
3133+
if (clean &&
3134+
r->settings->merge_directory_renames == MERGE_DIRECTORY_RENAMES_CONFLICT &&
31253135
ren->dir_rename_original_dest) {
31263136
if (update_stages(opt, path,
31273137
NULL,
@@ -3155,6 +3165,7 @@ static void dir_rename_warning(const char *msg,
31553165
static int warn_about_dir_renamed_entries(struct merge_options *opt,
31563166
struct rename *ren)
31573167
{
3168+
struct repository *r = the_repository;
31583169
const char *msg;
31593170
int clean = 1, is_add;
31603171

@@ -3166,12 +3177,13 @@ static int warn_about_dir_renamed_entries(struct merge_options *opt,
31663177
return clean;
31673178

31683179
/* Sanity checks */
3169-
assert(opt->detect_directory_renames > 0);
3180+
prepare_repo_settings(r);
3181+
assert(r->settings->merge_directory_renames > 0);
31703182
assert(ren->dir_rename_original_type == 'A' ||
31713183
ren->dir_rename_original_type == 'R');
31723184

31733185
/* Check whether to treat directory renames as a conflict */
3174-
clean = (opt->detect_directory_renames == 2);
3186+
clean = (r->settings->merge_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE);
31753187

31763188
is_add = (ren->dir_rename_original_type == 'A');
31773189
if (ren->dir_rename_original_type == 'A' && clean) {
@@ -3662,15 +3674,6 @@ static void merge_recursive_config(struct merge_options *opt)
36623674
opt->merge_detect_rename = git_config_rename("merge.renames", value);
36633675
free(value);
36643676
}
3665-
if (!git_config_get_string("merge.directoryrenames", &value)) {
3666-
int boolval = git_parse_maybe_bool(value);
3667-
if (0 <= boolval) {
3668-
opt->detect_directory_renames = boolval ? 2 : 0;
3669-
} else if (!strcasecmp(value, "conflict")) {
3670-
opt->detect_directory_renames = 1;
3671-
} /* avoid erroring on values from future versions of git */
3672-
free(value);
3673-
}
36743677
git_config(git_xmerge_config, NULL);
36753678
}
36763679

@@ -3687,7 +3690,6 @@ void init_merge_options(struct merge_options *opt,
36873690
opt->renormalize = 0;
36883691
opt->diff_detect_rename = -1;
36893692
opt->merge_detect_rename = -1;
3690-
opt->detect_directory_renames = 1;
36913693
merge_recursive_config(opt);
36923694
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
36933695
if (merge_verbosity)

merge-recursive.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ struct merge_options {
2222
unsigned renormalize : 1;
2323
long xdl_opts;
2424
int verbosity;
25-
int detect_directory_renames;
2625
int diff_detect_rename;
2726
int merge_detect_rename;
2827
int diff_rename_limit;

repo-settings.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ static int git_repo_config(const char *key, const char *value, void *cb)
99
{
1010
struct repo_settings *rs = (struct repo_settings *)cb;
1111

12+
if (!strcmp(key, "feature.experimental")) {
13+
UPDATE_DEFAULT(rs->pack_use_sparse, 1);
14+
UPDATE_DEFAULT(rs->merge_directory_renames, MERGE_DIRECTORY_RENAMES_TRUE);
15+
UPDATE_DEFAULT(rs->fetch_negotiation_algorithm, FETCH_NEGOTIATION_SKIPPING);
16+
return 0;
17+
}
1218
if (!strcmp(key, "feature.manycommits")) {
1319
UPDATE_DEFAULT(rs->core_commit_graph, 1);
1420
UPDATE_DEFAULT(rs->gc_write_commit_graph, 1);
@@ -50,6 +56,23 @@ static int git_repo_config(const char *key, const char *value, void *cb)
5056
"using 'keep' default value"), value);
5157
return 0;
5258
}
59+
if (!strcmp(key, "merge.directoryrenames")) {
60+
int bool_value = git_parse_maybe_bool(value);
61+
if (0 <= bool_value) {
62+
rs->merge_directory_renames = bool_value ? MERGE_DIRECTORY_RENAMES_TRUE : 0;
63+
} else if (!strcasecmp(value, "conflict")) {
64+
rs->merge_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;
65+
}
66+
return 0;
67+
}
68+
if (!strcmp(key, "fetch.negotiationalgorithm")) {
69+
if (!strcasecmp(value, "skipping")) {
70+
rs->fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
71+
} else {
72+
rs->fetch_negotiation_algorithm = FETCH_NEGOTIATION_DEFAULT;
73+
}
74+
return 0;
75+
}
5376

5477
return 1;
5578
}
@@ -64,15 +87,22 @@ void prepare_repo_settings(struct repository *r)
6487
/* Defaults */
6588
r->settings->core_commit_graph = -1;
6689
r->settings->gc_write_commit_graph = -1;
67-
r->settings->pack_use_sparse = -1;
90+
6891
r->settings->index_version = -1;
6992
r->settings->core_untracked_cache = -1;
7093

94+
r->settings->pack_use_sparse = -1;
95+
r->settings->merge_directory_renames = -1;
96+
r->settings->fetch_negotiation_algorithm = -1;
97+
7198
repo_config(r, git_repo_config, r->settings);
7299

73100
/* Hack for test programs like test-dump-untracked-cache */
74101
if (ignore_untracked_cache_config)
75102
r->settings->core_untracked_cache = CORE_UNTRACKED_CACHE_KEEP;
76103
else
77104
UPDATE_DEFAULT(r->settings->core_untracked_cache, CORE_UNTRACKED_CACHE_KEEP);
105+
106+
UPDATE_DEFAULT(r->settings->merge_directory_renames, MERGE_DIRECTORY_RENAMES_CONFLICT);
107+
UPDATE_DEFAULT(r->settings->fetch_negotiation_algorithm, FETCH_NEGOTIATION_DEFAULT);
78108
}

repo-settings.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@
44
#define CORE_UNTRACKED_CACHE_WRITE (1 << 0)
55
#define CORE_UNTRACKED_CACHE_KEEP (1 << 1)
66

7+
#define MERGE_DIRECTORY_RENAMES_CONFLICT 1
8+
#define MERGE_DIRECTORY_RENAMES_TRUE 2
9+
10+
#define FETCH_NEGOTIATION_DEFAULT 1
11+
#define FETCH_NEGOTIATION_SKIPPING 2
12+
713
struct repo_settings {
814
int core_commit_graph;
915
int gc_write_commit_graph;
10-
int pack_use_sparse;
16+
1117
int index_version;
1218
int core_untracked_cache;
19+
20+
int pack_use_sparse;
21+
int merge_directory_renames;
22+
int fetch_negotiation_algorithm;
1323
};
1424

1525
struct repository;

0 commit comments

Comments
 (0)