From d2b11eca7eccc4dfc22a8fc1182d9341458dd9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Wed, 17 Feb 2016 01:15:25 -0200 Subject: [PATCH 1/7] merge-recursive: option to disable renames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recursive strategy turns on rename detection by default. Add a strategy option to disable rename detection even for exact renames. Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- Documentation/merge-strategies.txt | 6 ++++++ merge-recursive.c | 7 +++++++ merge-recursive.h | 1 + 3 files changed, 14 insertions(+) diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 7bbd19b300..1a5e1974a5 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -81,8 +81,14 @@ no-renormalize;; Disables the `renormalize` option. This overrides the `merge.renormalize` configuration variable. +no-renames;; + Turn off rename detection. + See also linkgit:git-diff[1] `--no-renames`. + rename-threshold=;; Controls the similarity threshold used for rename detection. + Re-enables rename detection if disabled by a preceding + `no-renames`. See also linkgit:git-diff[1] `-M`. subtree[=];; diff --git a/merge-recursive.c b/merge-recursive.c index 8eabde20fb..6dd0a111f7 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -482,6 +482,9 @@ static struct string_list *get_renames(struct merge_options *o, struct diff_options opts; renames = xcalloc(1, sizeof(struct string_list)); + if (!o->detect_rename) + return renames; + diff_setup(&opts); DIFF_OPT_SET(&opts, RECURSIVE); DIFF_OPT_CLR(&opts, RENAME_EMPTY); @@ -2039,6 +2042,7 @@ 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; merge_recursive_config(o); if (getenv("GIT_MERGE_VERBOSITY")) o->verbosity = @@ -2088,9 +2092,12 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->renormalize = 1; else if (!strcmp(s, "no-renormalize")) o->renormalize = 0; + else if (!strcmp(s, "no-renames")) + o->detect_rename = 0; else if (skip_prefix(s, "rename-threshold=", &arg)) { if ((o->rename_score = parse_rename_score(&arg)) == -1 || *arg != 0) return -1; + o->detect_rename = 1; } else return -1; diff --git a/merge-recursive.h b/merge-recursive.h index 9e090a3470..52f0201f68 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -17,6 +17,7 @@ struct merge_options { unsigned renormalize : 1; long xdl_opts; int verbosity; + int detect_rename; int diff_rename_limit; int merge_rename_limit; int rename_score; From 1b47ad160b55f50a7a98c180e18d80f0f8f17a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Wed, 17 Feb 2016 01:15:26 -0200 Subject: [PATCH 2/7] merge-recursive: more consistent interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add strategy option find-renames, following git-diff interface. This makes the option rename-threshold redundant. Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- Documentation/merge-strategies.txt | 10 ++++++---- merge-recursive.c | 5 ++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 1a5e1974a5..ff359b6ca2 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -85,11 +85,13 @@ no-renames;; Turn off rename detection. See also linkgit:git-diff[1] `--no-renames`. +find-renames[=];; + Turn on rename detection, optionally setting the the similarity + threshold. This is the default. + See also linkgit:git-diff[1] `--find-renames`. + rename-threshold=;; - Controls the similarity threshold used for rename detection. - Re-enables rename detection if disabled by a preceding - `no-renames`. - See also linkgit:git-diff[1] `-M`. + Deprecated synonym for `find-renames=`. subtree[=];; This option is a more advanced form of 'subtree' strategy, where diff --git a/merge-recursive.c b/merge-recursive.c index 6dd0a111f7..7bff5be164 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2094,7 +2094,10 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->renormalize = 0; else if (!strcmp(s, "no-renames")) o->detect_rename = 0; - else if (skip_prefix(s, "rename-threshold=", &arg)) { + else if (!strcmp(s, "find-renames")) + o->detect_rename = 1; + 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; From 83837ec0b43bfd832ea00cd96e8b47c90991c473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Sun, 21 Feb 2016 19:59:01 -0300 Subject: [PATCH 3/7] merge-strategies.txt: fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- Documentation/merge-strategies.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index ff359b6ca2..2eb92b9327 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -86,8 +86,8 @@ no-renames;; See also linkgit:git-diff[1] `--no-renames`. find-renames[=];; - Turn on rename detection, optionally setting the the similarity - threshold. This is the default. + Turn on rename detection, optionally setting the similarity + threshold. This is the default. See also linkgit:git-diff[1] `--find-renames`. rename-threshold=;; From 87892f605be16037bc910ca2cf9fa21bb9467f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Sun, 21 Feb 2016 19:59:05 -0300 Subject: [PATCH 4/7] merge-recursive: find-renames resets threshold MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the find-renames option follow the behaviour in git-diff, where it resets the threshold when none is given. So, for instance, "--find-renames=25 --find-renames" should result in the default threshold (50%) instead of 25%. Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- merge-recursive.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/merge-recursive.c b/merge-recursive.c index 7bff5be164..b880ae50e7 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -2094,8 +2094,10 @@ int parse_merge_opt(struct merge_options *o, const char *s) o->renormalize = 0; else if (!strcmp(s, "no-renames")) o->detect_rename = 0; - else if (!strcmp(s, "find-renames")) + else if (!strcmp(s, "find-renames")) { o->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) From 63651e1a13f29abcffb1d197f3388924318d59d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Tue, 23 Feb 2016 22:41:29 -0300 Subject: [PATCH 5/7] t3034: add rename threshold tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 10ae752 (merge-recursive: option to specify rename threshold, 2010-09-27) introduced this feature but did not include any tests. The tests use the new option --find-renames, which replaces the then introduced and now deprecated option --rename-threshold. Also update name and description of t3032 for consistency: "merge-recursive options" -> "merge-recursive space options" Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- ...=> t3032-merge-recursive-space-options.sh} | 2 +- t/t3034-merge-recursive-rename-options.sh | 238 ++++++++++++++++++ 2 files changed, 239 insertions(+), 1 deletion(-) rename t/{t3032-merge-recursive-options.sh => t3032-merge-recursive-space-options.sh} (99%) create mode 100755 t/t3034-merge-recursive-rename-options.sh diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-space-options.sh similarity index 99% rename from t/t3032-merge-recursive-options.sh rename to t/t3032-merge-recursive-space-options.sh index 4029c9c8c0..b56180ee4a 100755 --- a/t/t3032-merge-recursive-options.sh +++ b/t/t3032-merge-recursive-space-options.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='merge-recursive options +test_description='merge-recursive space options * [master] Clarify ! [remote] Remove cruft diff --git a/t/t3034-merge-recursive-rename-options.sh b/t/t3034-merge-recursive-rename-options.sh new file mode 100755 index 0000000000..51c2f87202 --- /dev/null +++ b/t/t3034-merge-recursive-rename-options.sh @@ -0,0 +1,238 @@ +#!/bin/sh + +test_description='merge-recursive rename options + +Test rename detection by examining rename/delete conflicts. + +* (HEAD -> rename) rename +| * (master) delete +|/ +* base + +git diff --name-status base master +D 0-old +D 1-old +D 2-old +D 3-old + +git diff --name-status -M01 base rename +R025 0-old 0-new +R050 1-old 1-new +R075 2-old 2-new +R100 3-old 3-new + +Actual similarity indices are parsed from diff output. We rely on the fact that +they are rounded down (see, e.g., Documentation/diff-generate-patch.txt, which +mentions this in a different context). +' + +. ./test-lib.sh + +get_expected_stages () { + git checkout rename -- $1-new && + git ls-files --stage $1-new >expected-stages-undetected-$1 && + sed "s/ 0 / 2 /" expected-stages-detected-$1 && + git read-tree -u --reset HEAD +} + +rename_detected () { + git ls-files --stage $1-old $1-new >stages-actual-$1 && + test_cmp expected-stages-detected-$1 stages-actual-$1 +} + +rename_undetected () { + git ls-files --stage $1-old $1-new >stages-actual-$1 && + test_cmp expected-stages-undetected-$1 stages-actual-$1 +} + +check_common () { + git ls-files --stage >stages-actual && + test_line_count = 4 stages-actual +} + +check_threshold_0 () { + check_common && + rename_detected 0 && + rename_detected 1 && + rename_detected 2 && + rename_detected 3 +} + +check_threshold_1 () { + check_common && + rename_undetected 0 && + rename_detected 1 && + rename_detected 2 && + rename_detected 3 +} + +check_threshold_2 () { + check_common && + rename_undetected 0 && + rename_undetected 1 && + rename_detected 2 && + rename_detected 3 +} + +check_exact_renames () { + check_common && + rename_undetected 0 && + rename_undetected 1 && + rename_undetected 2 && + rename_detected 3 +} + +test_expect_success 'setup repo' ' + cat <<-\EOF >3-old && + 33a + 33b + 33c + 33d + EOF + sed s/33/22/ <3-old >2-old && + sed s/33/11/ <3-old >1-old && + sed s/33/00/ <3-old >0-old && + git add [0-3]-old && + git commit -m base && + git rm [0-3]-old && + git commit -m delete && + git checkout -b rename HEAD^ && + cp 3-old 3-new && + sed 1,1s/./x/ <2-old >2-new && + sed 1,2s/./x/ <1-old >1-new && + sed 1,3s/./x/ <0-old >0-new && + git add [0-3]-new && + git rm [0-3]-old && + git commit -m rename && + get_expected_stages 0 && + get_expected_stages 1 && + get_expected_stages 2 && + get_expected_stages 3 && + check_50="false" && + tail="HEAD^ -- HEAD master" +' + +test_expect_success 'setup thresholds' ' + git diff --name-status -M01 HEAD^ HEAD >diff-output && + test_debug "cat diff-output" && + test_line_count = 4 diff-output && + grep "R[0-9][0-9][0-9] \([0-3]\)-old \1-new" diff-output \ + >grep-output && + test_cmp diff-output grep-output && + th0=$(sed -n "s/R\(...\) 0-old 0-new/\1/p" diff-output-0 && + git diff --name-status -M$th1 --diff-filter=R HEAD^ HEAD \ + >diff-output-1 && + git diff --name-status -M$th2 --diff-filter=R HEAD^ HEAD \ + >diff-output-2 && + git diff --name-status -M100% --diff-filter=R HEAD^ HEAD \ + >diff-output-3 && + test_line_count = 4 diff-output-0 && + test_line_count = 3 diff-output-1 && + test_line_count = 2 diff-output-2 && + test_line_count = 1 diff-output-3 +' + +test_expect_success 'default similarity threshold is 50%' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive $tail && + $check_50 +' + +test_expect_success 'low rename threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=$th0 $tail && + check_threshold_0 +' + +test_expect_success 'medium rename threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=$th1 $tail && + check_threshold_1 +' + +test_expect_success 'high rename threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=$th2 $tail && + check_threshold_2 +' + +test_expect_success 'exact renames only' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=100% $tail && + check_exact_renames +' + +test_expect_success 'rename threshold is truncated' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=200% $tail && + check_exact_renames +' + +test_expect_success 'last wins in --find-renames= --find-renames=' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --find-renames=$th0 --find-renames=$th2 $tail && + check_threshold_2 +' + +test_expect_success '--find-renames resets threshold' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --find-renames=$th0 --find-renames $tail && + $check_50 +' + +test_expect_success 'assumption for further tests: trivial merge succeeds' ' + git read-tree --reset -u HEAD && + git merge-recursive HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --find-renames=$th0 HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --find-renames=$th2 HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --find-renames=100% HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success '--find-renames rejects negative argument' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=-25 \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success '--find-renames rejects non-numbers' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --find-renames=0xf \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_done From 2307211349e6fe83e3574c2e1a03bb34c24ed1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Tue, 23 Feb 2016 22:41:30 -0300 Subject: [PATCH 6/7] t3034: test option to disable renames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- t/t3034-merge-recursive-rename-options.sh | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/t/t3034-merge-recursive-rename-options.sh b/t/t3034-merge-recursive-rename-options.sh index 51c2f87202..247991034d 100755 --- a/t/t3034-merge-recursive-rename-options.sh +++ b/t/t3034-merge-recursive-rename-options.sh @@ -83,6 +83,14 @@ check_exact_renames () { rename_detected 3 } +check_no_renames () { + check_common && + rename_undetected 0 && + rename_undetected 1 && + rename_undetected 2 && + rename_undetected 3 +} + test_expect_success 'setup repo' ' cat <<-\EOF >3-old && 33a @@ -195,6 +203,12 @@ test_expect_success 'rename threshold is truncated' ' check_exact_renames ' +test_expect_success 'disabled rename detection' ' + git read-tree --reset -u HEAD && + git merge-recursive --no-renames $tail && + check_no_renames +' + test_expect_success 'last wins in --find-renames= --find-renames=' ' git read-tree --reset -u HEAD && test_must_fail git merge-recursive \ @@ -209,6 +223,18 @@ test_expect_success '--find-renames resets threshold' ' $check_50 ' +test_expect_success 'last wins in --no-renames --find-renames' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --no-renames --find-renames $tail && + $check_50 +' + +test_expect_success 'last wins in --find-renames --no-renames' ' + git read-tree --reset -u HEAD && + git merge-recursive --find-renames --no-renames $tail && + check_no_renames +' + test_expect_success 'assumption for further tests: trivial merge succeeds' ' git read-tree --reset -u HEAD && git merge-recursive HEAD -- HEAD HEAD && @@ -218,6 +244,8 @@ test_expect_success 'assumption for further tests: trivial merge succeeds' ' git merge-recursive --find-renames=$th2 HEAD -- HEAD HEAD && git diff --quiet --cached && git merge-recursive --find-renames=100% HEAD -- HEAD HEAD && + git diff --quiet --cached && + git merge-recursive --no-renames HEAD -- HEAD HEAD && git diff --quiet --cached ' From 44c74ecade186d7c7047642840d581709db3ba23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Gon=C3=A7alves=20Assis?= Date: Tue, 23 Feb 2016 22:41:31 -0300 Subject: [PATCH 7/7] t3034: test deprecated interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --find-renames= and --rename-threshold= should be aliases. Signed-off-by: Felipe Gonçalves Assis Signed-off-by: Junio C Hamano --- t/t3034-merge-recursive-rename-options.sh | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/t/t3034-merge-recursive-rename-options.sh b/t/t3034-merge-recursive-rename-options.sh index 247991034d..b9c4028496 100755 --- a/t/t3034-merge-recursive-rename-options.sh +++ b/t/t3034-merge-recursive-rename-options.sh @@ -263,4 +263,50 @@ test_expect_success '--find-renames rejects non-numbers' ' git diff --quiet --cached ' +test_expect_success 'rename-threshold= is a synonym for find-renames=' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --rename-threshold=$th0 $tail && + check_threshold_0 +' + +test_expect_success 'last wins in --no-renames --rename-threshold=' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --no-renames --rename-threshold=$th0 $tail && + check_threshold_0 +' + +test_expect_success 'last wins in --rename-threshold= --no-renames' ' + git read-tree --reset -u HEAD && + git merge-recursive --rename-threshold=$th0 --no-renames $tail && + check_no_renames +' + +test_expect_success '--rename-threshold= rejects negative argument' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --rename-threshold=-25 \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success '--rename-threshold= rejects non-numbers' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive --rename-threshold=0xf \ + HEAD -- HEAD HEAD && + git diff --quiet --cached +' + +test_expect_success 'last wins in --rename-threshold= --find-renames=' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --rename-threshold=$th0 --find-renames=$th2 $tail && + check_threshold_2 +' + +test_expect_success 'last wins in --find-renames= --rename-threshold=' ' + git read-tree --reset -u HEAD && + test_must_fail git merge-recursive \ + --find-renames=$th2 --rename-threshold=$th0 $tail && + check_threshold_0 +' + test_done