Skip to content

Commit

Permalink
repo-settings: create feature.experimental setting
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
derrickstolee committed Jul 30, 2019
1 parent 0d4774d commit 2e153fa
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 55 deletions.
17 changes: 17 additions & 0 deletions Documentation/config/feature.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ 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.
+
* `merge.directoryRenames=true` uses a new algorithm for detecting renames by
using entire directories at a time instead of single files at a time.
+
* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
skipping more commits at a time, reducing the number of round trips.

feature.manyCommits::
Enable config options that optimize for repos with many commits. This
setting is recommended for repos with at least 100,000 commits. The
Expand Down
3 changes: 2 additions & 1 deletion Documentation/config/fetch.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down
3 changes: 2 additions & 1 deletion Documentation/config/merge.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ merge.directoryRenames::
moved into the new directory. If set to "conflict", a conflict
will be reported for such paths. If merge.renames is false,
merge.directoryRenames is ignored and treated as false. Defaults
to "conflict".
to "conflict" unless `feature.experimental` is enabled and the
default is "true".

merge.renormalize::
Tell Git that canonical representation of files in the
Expand Down
3 changes: 2 additions & 1 deletion Documentation/config/pack.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
25 changes: 13 additions & 12 deletions fetch-negotiator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
5 changes: 3 additions & 2 deletions fetch-negotiator.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define FETCH_NEGOTIATOR_H

struct commit;
struct repository;

/*
* An object that supplies the information needed to negotiate the contents of
Expand Down Expand Up @@ -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
11 changes: 5 additions & 6 deletions fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -1379,14 +1379,15 @@ 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;
struct packet_reader reader;
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);
Expand Down Expand Up @@ -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);
}
Expand Down
14 changes: 5 additions & 9 deletions merge-recursive.c
Original file line number Diff line number Diff line change
Expand Up @@ -3662,15 +3662,6 @@ static void merge_recursive_config(struct merge_options *opt)
opt->merge_detect_rename = git_config_rename("merge.renames", value);
free(value);
}
if (!git_config_get_string("merge.directoryrenames", &value)) {
int boolval = git_parse_maybe_bool(value);
if (0 <= boolval) {
opt->detect_directory_renames = boolval ? 2 : 0;
} else if (!strcasecmp(value, "conflict")) {
opt->detect_directory_renames = 1;
} /* avoid erroring on values from future versions of git */
free(value);
}
git_config(git_xmerge_config, NULL);
}

Expand All @@ -3688,6 +3679,11 @@ void init_merge_options(struct merge_options *opt,
opt->diff_detect_rename = -1;
opt->merge_detect_rename = -1;
opt->detect_directory_renames = 1;

prepare_repo_settings(repo);
if (repo->settings.merge_directory_renames >= 0)
opt->detect_directory_renames = repo->settings.merge_directory_renames;

merge_recursive_config(opt);
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
if (merge_verbosity)
Expand Down
19 changes: 19 additions & 0 deletions repo-settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ void prepare_repo_settings(struct repository *r)
free(strval);
}

if (!repo_config_get_maybe_bool(r, "merge.directoryrenames", &value))
r->settings.merge_directory_renames = value ? MERGE_DIRECTORY_RENAMES_TRUE : 0;
else if (!repo_config_get_string(r, "merge.directoryrenames", &strval)) {
if (!strcasecmp(strval, "conflict"))
r->settings.merge_directory_renames = MERGE_DIRECTORY_RENAMES_CONFLICT;
}
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;
Expand All @@ -46,11 +58,18 @@ void prepare_repo_settings(struct repository *r)
UPDATE_DEFAULT(r->settings.index_version, 4);
UPDATE_DEFAULT(r->settings.core_untracked_cache, UNTRACKED_CACHE_WRITE);
}
if (!repo_config_get_bool(r, "feature.experimental", &value) && value) {
UPDATE_DEFAULT(r->settings.pack_use_sparse, 1);
UPDATE_DEFAULT(r->settings.merge_directory_renames, MERGE_DIRECTORY_RENAMES_TRUE);
UPDATE_DEFAULT(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(r->settings.core_untracked_cache, UNTRACKED_CACHE_KEEP);

UPDATE_DEFAULT(r->settings.merge_directory_renames, MERGE_DIRECTORY_RENAMES_CONFLICT);
UPDATE_DEFAULT(r->settings.fetch_negotiation_algorithm, FETCH_NEGOTIATION_DEFAULT);
}
16 changes: 16 additions & 0 deletions repository.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ enum untracked_cache_setting {
UNTRACKED_CACHE_WRITE = 2
};

enum merge_directory_renames_setting {
MERGE_DIRECTORY_RENAMES_UNSET = -1,
MERGE_DIRECTORY_RENAMES_NONE = 0,
MERGE_DIRECTORY_RENAMES_CONFLICT = 1,
MERGE_DIRECTORY_RENAMES_TRUE = 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;

Expand All @@ -29,6 +43,8 @@ struct repo_settings {
enum untracked_cache_setting core_untracked_cache;

int pack_use_sparse;
enum merge_directory_renames_setting merge_directory_renames;
enum fetch_negotiation_setting fetch_negotiation_algorithm;
};

struct repository {
Expand Down
23 changes: 0 additions & 23 deletions t/t5552-skipping-fetch-negotiator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down

0 comments on commit 2e153fa

Please sign in to comment.