merge: add merge.renames config setting
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>
Ben Peart committed
May 2, 2018 at 16:01 UTC
85b460305ce7ed399c83499851f46c4f870ce280
7 files changed
+64
-12
Documentation/merge-config.txt
+5
@@ -38,6 +38,11 @@ merge.renameLimit::
38
diff.renameLimit. This setting has no effect if rename detection
39
is turned off.
40
41
+merge.renames::
42
+ Whether and how Git detects renames. If set to "false",
43
+ rename detection is disabled. If set to "true", basic rename
44
+ detection is enabled. Defaults to the value of diff.renames.
45
+
46
merge.renormalize::
47
Tell Git that canonical representation of files in the
48
repository has changed over time (e.g. earlier commits record
Documentation/merge-strategies.txt
+7
-4
@@ -23,8 +23,9 @@ recursive::
23
causing mismerges by tests done on actual merge commits
24
taken from Linux 2.6 kernel development history.
25
Additionally this can detect and handle merges involving
26
- renames. This is the default merge strategy when
27
- pulling or merging one branch.
26
+ renames, but currently cannot make use of detected
27
+ copies. This is the default merge strategy when pulling
28
+ or merging one branch.
29
+
30
The 'recursive' strategy can take the following options:
31
@@ -84,12 +85,14 @@ no-renormalize;;
85
`merge.renormalize` configuration variable.
86
87
no-renames;;
87
- Turn off rename detection.
88
+ Turn off rename detection. This overrides the `merge.renames`
89
+ configuration variable.
90
See also linkgit:git-diff[1] `--no-renames`.
91
92
find-renames[=<n>];;
93
Turn on rename detection, optionally setting the similarity
92
- threshold. This is the default.
94
+ threshold. This is the default. This overrides the
95
+ 'merge.renames' configuration variable.
96
See also linkgit:git-diff[1] `--find-renames`.
97
98
rename-threshold=<n>;;
diff.c
+1
-1
@@ -177,7 +177,7 @@ static int parse_submodule_params(struct diff_options *options, const char *valu
177
return 0;
178
}
179
180
-static int git_config_rename(const char *var, const char *value)
180
+int git_config_rename(const char *var, const char *value)
181
{
182
if (!value)
183
return DIFF_DETECT_RENAME;
diff.h
+1
@@ -324,6 +324,7 @@ extern int git_diff_ui_config(const char *var, const char *value, void *cb);
324
extern void diff_setup(struct diff_options *);
325
extern int diff_opt_parse(struct diff_options *, const char **, int, const char *);
326
extern void diff_setup_done(struct diff_options *);
327
+extern int git_config_rename(const char *var, const char *value);
328
329
#define DIFF_DETECT_RENAME 1
330
#define DIFF_DETECT_COPY 2
merge-recursive.c
+24
-6
@@ -1603,7 +1603,15 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
1603
diff_setup(&opts);
1604
opts.flags.recursive = 1;
1605
opts.flags.rename_empty = 0;
1606
- opts.detect_rename = DIFF_DETECT_RENAME;
1606
+ opts.detect_rename = merge_detect_rename(o);
1607
+ /*
1608
+ * We do not have logic to handle the detection of copies. In
1609
+ * fact, it may not even make sense to add such logic: would we
1610
+ * really want a change to a base file to be propagated through
1611
+ * multiple other files by a merge?
1612
+ */
1613
+ if (opts.detect_rename > DIFF_DETECT_RENAME)
1614
+ opts.detect_rename = DIFF_DETECT_RENAME;
1615
opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
1616
o->diff_rename_limit >= 0 ? o->diff_rename_limit :
1617
1000;
@@ -2643,7 +2651,7 @@ static int handle_renames(struct merge_options *o,
2651
ri->head_renames = NULL;
2652
ri->merge_renames = NULL;
2653
2646
- if (!o->detect_rename)
2654
+ if (!merge_detect_rename(o))
2655
return 1;
2656
2657
head_pairs = get_diffpairs(o, common, head);
@@ -3324,9 +3332,18 @@ int merge_recursive_generic(struct merge_options *o,
3332
3333
static void merge_recursive_config(struct merge_options *o)
3334
{
3335
+ char *value = NULL;
3336
git_config_get_int("merge.verbosity", &o->verbosity);
3337
git_config_get_int("diff.renamelimit", &o->diff_rename_limit);
3338
git_config_get_int("merge.renamelimit", &o->merge_rename_limit);
3339
+ if (!git_config_get_string("diff.renames", &value)) {
3340
+ o->diff_detect_rename = git_config_rename("diff.renames", value);
3341
+ free(value);
3342
+ }
3343
+ if (!git_config_get_string("merge.renames", &value)) {
3344
+ o->merge_detect_rename = git_config_rename("merge.renames", value);
3345
+ free(value);
3346
+ }
3347
git_config(git_xmerge_config, NULL);
3348
}
3349
@@ -3339,7 +3356,8 @@ void init_merge_options(struct merge_options *o)
3356
o->diff_rename_limit = -1;
3357
o->merge_rename_limit = -1;
3358
o->renormalize = 0;
3342
- o->detect_rename = 1;
3359
+ o->diff_detect_rename = -1;
3360
+ o->merge_detect_rename = -1;
3361
merge_recursive_config(o);
3362
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
3363
if (merge_verbosity)
@@ -3390,16 +3408,16 @@ int parse_merge_opt(struct merge_options *o, const char *s)
3408
else if (!strcmp(s, "no-renormalize"))
3409
o->renormalize = 0;
3410
else if (!strcmp(s, "no-renames"))
3393
- o->detect_rename = 0;
3411
+ o->merge_detect_rename = 0;
3412
else if (!strcmp(s, "find-renames")) {
3395
- o->detect_rename = 1;
3413
+ o->merge_detect_rename = 1;
3414
o->rename_score = 0;
3415
}
3416
else if (skip_prefix(s, "find-renames=", &arg) ||
3417
skip_prefix(s, "rename-threshold=", &arg)) {
3418
if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0)
3419
return -1;
3402
- o->detect_rename = 1;
3420
+ o->merge_detect_rename = 1;
3421
}
3422
else
3423
return -1;
merge-recursive.h
+8
-1
@@ -18,7 +18,8 @@ struct merge_options {
18
unsigned renormalize : 1;
19
long xdl_opts;
20
int verbosity;
21
- int detect_rename;
21
+ int diff_detect_rename;
22
+ int merge_detect_rename;
23
int diff_rename_limit;
24
int merge_rename_limit;
25
int rename_score;
@@ -57,6 +58,12 @@ struct collision_entry {
58
unsigned reported_already:1;
59
};
60
61
+static inline int merge_detect_rename(struct merge_options *o)
62
+{
63
+ return o->merge_detect_rename >= 0 ? o->merge_detect_rename :
64
+ o->diff_detect_rename >= 0 ? o->diff_detect_rename : 1;
65
+}
66
+
67
/* merge_trees() but with recursive ancestor consolidation */
68
int merge_recursive(struct merge_options *o,
69
struct commit *h1,
t/t3034-merge-recursive-rename-options.sh
+18
@@ -309,4 +309,22 @@ test_expect_success 'last wins in --find-renames=<m> --rename-threshold=<n>' '
309
check_threshold_0
310
'
311
312
+test_expect_success 'merge.renames disables rename detection' '
313
+ git read-tree --reset -u HEAD &&
314
+ git -c merge.renames=false merge-recursive $tail &&
315
+ check_no_renames
316
+'
317
+
318
+test_expect_success 'merge.renames defaults to diff.renames' '
319
+ git read-tree --reset -u HEAD &&
320
+ git -c diff.renames=false merge-recursive $tail &&
321
+ check_no_renames
322
+'
323
+
324
+test_expect_success 'merge.renames overrides diff.renames' '
325
+ git read-tree --reset -u HEAD &&
326
+ test_must_fail git -c diff.renames=false -c merge.renames=true merge-recursive $tail &&
327
+ $check_50
328
+'
329
+
330
test_done