Add the ability to control rename detection for merge via a config setting.
This setting behaves the same and defaults to the value of diff.renames but only
applies to merge.
Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Ben Peart <benpeart@microsoft.com>
Reviewed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
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
repository has changed over time (e.g. earlier commits record
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:
`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>;;
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;
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
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;
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);
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);
}
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)
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;
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;
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,
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