Merge branch 'bp/merge-rename-config'

With merge.renames configuration set to false, the recursive merge
strategy can be told not to spend cycles trying to find renamed
paths and merge them accordingly.

* bp/merge-rename-config:
  merge: pass aggressive when rename detection is turned off
  merge: add merge.renames config setting
  merge: update documentation for {merge,diff}.renameLimit
This commit is contained in:
Junio C Hamano 2018-05-30 14:04:04 +09:00
commit 6e2ba77bda
8 changed files with 69 additions and 14 deletions

View File

@ -112,7 +112,8 @@ diff.orderFile::
diff.renameLimit::
The number of files to consider when performing the copy/rename
detection; equivalent to the 'git diff' option `-l`.
detection; equivalent to the 'git diff' option `-l`. This setting
has no effect if rename detection is turned off.
diff.renames::
Whether and how Git detects renames. If set to "false",

View File

@ -35,7 +35,13 @@ include::fmt-merge-msg-config.txt[]
merge.renameLimit::
The number of files to consider when performing rename detection
during a merge; if not specified, defaults to the value of
diff.renameLimit.
diff.renameLimit. This setting has no effect if rename detection
is turned off.
merge.renames::
Whether and how Git detects renames. If set to "false",
rename detection is disabled. If set to "true", basic rename
detection is enabled. Defaults to the value of diff.renames.
merge.renormalize::
Tell Git that canonical representation of files in the

View File

@ -23,8 +23,9 @@ recursive::
causing mismerges by tests done on actual merge commits
taken from Linux 2.6 kernel development history.
Additionally this can detect and handle merges involving
renames. This is the default merge strategy when
pulling or merging one branch.
renames, but currently cannot make use of detected
copies. This is the default merge strategy when pulling
or merging one branch.
+
The 'recursive' strategy can take the following options:
@ -84,12 +85,14 @@ no-renormalize;;
`merge.renormalize` configuration variable.
no-renames;;
Turn off rename detection.
Turn off rename detection. This overrides the `merge.renames`
configuration variable.
See also linkgit:git-diff[1] `--no-renames`.
find-renames[=<n>];;
Turn on rename detection, optionally setting the similarity
threshold. This is the default.
threshold. This is the default. This overrides the
'merge.renames' configuration variable.
See also linkgit:git-diff[1] `--find-renames`.
rename-threshold=<n>;;

2
diff.c
View File

@ -177,7 +177,7 @@ static int parse_submodule_params(struct diff_options *options, const char *valu
return 0;
}
static int git_config_rename(const char *var, const char *value)
int git_config_rename(const char *var, const char *value)
{
if (!value)
return DIFF_DETECT_RENAME;

1
diff.h
View File

@ -324,6 +324,7 @@ extern int git_diff_ui_config(const char *var, const char *value, void *cb);
extern void diff_setup(struct diff_options *);
extern int diff_opt_parse(struct diff_options *, const char **, int, const char *);
extern void diff_setup_done(struct diff_options *);
extern int git_config_rename(const char *var, const char *value);
#define DIFF_DETECT_RENAME 1
#define DIFF_DETECT_COPY 2

View File

@ -356,6 +356,7 @@ static int git_merge_trees(struct merge_options *o,
o->unpack_opts.fn = threeway_merge;
o->unpack_opts.src_index = &the_index;
o->unpack_opts.dst_index = &tmp_index;
o->unpack_opts.aggressive = !merge_detect_rename(o);
setup_unpack_trees_porcelain(&o->unpack_opts, "merge");
init_tree_desc_from_tree(t+0, common);
@ -1603,7 +1604,15 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
diff_setup(&opts);
opts.flags.recursive = 1;
opts.flags.rename_empty = 0;
opts.detect_rename = DIFF_DETECT_RENAME;
opts.detect_rename = merge_detect_rename(o);
/*
* We do not have logic to handle the detection of copies. In
* fact, it may not even make sense to add such logic: would we
* really want a change to a base file to be propagated through
* multiple other files by a merge?
*/
if (opts.detect_rename > DIFF_DETECT_RENAME)
opts.detect_rename = DIFF_DETECT_RENAME;
opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
o->diff_rename_limit >= 0 ? o->diff_rename_limit :
1000;
@ -2643,7 +2652,7 @@ static int handle_renames(struct merge_options *o,
ri->head_renames = NULL;
ri->merge_renames = NULL;
if (!o->detect_rename)
if (!merge_detect_rename(o))
return 1;
head_pairs = get_diffpairs(o, common, head);
@ -3325,9 +3334,18 @@ int merge_recursive_generic(struct merge_options *o,
static void merge_recursive_config(struct merge_options *o)
{
char *value = NULL;
git_config_get_int("merge.verbosity", &o->verbosity);
git_config_get_int("diff.renamelimit", &o->diff_rename_limit);
git_config_get_int("merge.renamelimit", &o->merge_rename_limit);
if (!git_config_get_string("diff.renames", &value)) {
o->diff_detect_rename = git_config_rename("diff.renames", value);
free(value);
}
if (!git_config_get_string("merge.renames", &value)) {
o->merge_detect_rename = git_config_rename("merge.renames", value);
free(value);
}
git_config(git_xmerge_config, NULL);
}
@ -3340,7 +3358,8 @@ void init_merge_options(struct merge_options *o)
o->diff_rename_limit = -1;
o->merge_rename_limit = -1;
o->renormalize = 0;
o->detect_rename = 1;
o->diff_detect_rename = -1;
o->merge_detect_rename = -1;
merge_recursive_config(o);
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
if (merge_verbosity)
@ -3391,16 +3410,16 @@ int parse_merge_opt(struct merge_options *o, const char *s)
else if (!strcmp(s, "no-renormalize"))
o->renormalize = 0;
else if (!strcmp(s, "no-renames"))
o->detect_rename = 0;
o->merge_detect_rename = 0;
else if (!strcmp(s, "find-renames")) {
o->detect_rename = 1;
o->merge_detect_rename = 1;
o->rename_score = 0;
}
else if (skip_prefix(s, "find-renames=", &arg) ||
skip_prefix(s, "rename-threshold=", &arg)) {
if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)
return -1;
o->detect_rename = 1;
o->merge_detect_rename = 1;
}
else
return -1;

View File

@ -18,7 +18,8 @@ struct merge_options {
unsigned renormalize : 1;
long xdl_opts;
int verbosity;
int detect_rename;
int diff_detect_rename;
int merge_detect_rename;
int diff_rename_limit;
int merge_rename_limit;
int rename_score;
@ -57,6 +58,12 @@ struct collision_entry {
unsigned reported_already:1;
};
static inline int merge_detect_rename(struct merge_options *o)
{
return o->merge_detect_rename >= 0 ? o->merge_detect_rename :
o->diff_detect_rename >= 0 ? o->diff_detect_rename : 1;
}
/* merge_trees() but with recursive ancestor consolidation */
int merge_recursive(struct merge_options *o,
struct commit *h1,

View File

@ -309,4 +309,22 @@ test_expect_success 'last wins in --find-renames=<m> --rename-threshold=<n>' '
check_threshold_0
'
test_expect_success 'merge.renames disables rename detection' '
git read-tree --reset -u HEAD &&
git -c merge.renames=false merge-recursive $tail &&
check_no_renames
'
test_expect_success 'merge.renames defaults to diff.renames' '
git read-tree --reset -u HEAD &&
git -c diff.renames=false merge-recursive $tail &&
check_no_renames
'
test_expect_success 'merge.renames overrides diff.renames' '
git read-tree --reset -u HEAD &&
test_must_fail git -c diff.renames=false -c merge.renames=true merge-recursive $tail &&
$check_50
'
test_done