Merge branch 'en/directory-renames-nothanks'

Recent addition of "directory rename" heuristics to the
merge-recursive backend makes the command susceptible to false
positives and false negatives.  In the context of "git am -3",
which does not know about surrounding unmodified paths and thus
cannot inform the merge machinery about the full trees involved,
this risk is particularly severe.  As such, the heuristic is
disabled for "git am -3" to keep the machinery "more stupid but
predictable".

* en/directory-renames-nothanks:
  am: avoid directory rename detection when calling recursive merge machinery
  merge-recursive: add ability to turn off directory rename detection
  t3401: add another directory rename testcase for rebase and am
This commit is contained in:
Junio C Hamano 2018-09-04 14:31:38 -07:00
Родитель 064e0b2d4c 6aba117d5c
Коммит ca676b9bd3
4 изменённых файлов: 124 добавлений и 6 удалений

Просмотреть файл

@ -1598,6 +1598,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
o.branch1 = "HEAD";
their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
o.branch2 = their_tree_name;
o.detect_directory_renames = 0;
if (state->quiet)
o.verbosity = 0;

Просмотреть файл

@ -2869,12 +2869,19 @@ static int detect_and_process_renames(struct merge_options *o,
head_pairs = get_diffpairs(o, common, head);
merge_pairs = get_diffpairs(o, common, merge);
dir_re_head = get_directory_renames(head_pairs, head);
dir_re_merge = get_directory_renames(merge_pairs, merge);
if (o->detect_directory_renames) {
dir_re_head = get_directory_renames(head_pairs, head);
dir_re_merge = get_directory_renames(merge_pairs, merge);
handle_directory_level_conflicts(o,
dir_re_head, head,
dir_re_merge, merge);
handle_directory_level_conflicts(o,
dir_re_head, head,
dir_re_merge, merge);
} else {
dir_re_head = xmalloc(sizeof(*dir_re_head));
dir_re_merge = xmalloc(sizeof(*dir_re_merge));
dir_rename_init(dir_re_head);
dir_rename_init(dir_re_merge);
}
ri->head_renames = get_renames(o, head_pairs,
dir_re_merge, dir_re_head, head,
@ -3586,6 +3593,7 @@ void init_merge_options(struct merge_options *o)
o->renormalize = 0;
o->diff_detect_rename = -1;
o->merge_detect_rename = -1;
o->detect_directory_renames = 1;
merge_recursive_config(o);
merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
if (merge_verbosity)

Просмотреть файл

@ -20,6 +20,7 @@ struct merge_options {
unsigned renormalize : 1;
long xdl_opts;
int verbosity;
int detect_directory_renames;
int diff_detect_rename;
int merge_detect_rename;
int diff_rename_limit;

Просмотреть файл

@ -5,7 +5,7 @@ test_description='git rebase + directory rename tests'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
test_expect_success 'setup testcase' '
test_expect_success 'setup testcase where directory rename should be detected' '
test_create_repo dir-rename &&
(
cd dir-rename &&
@ -102,4 +102,112 @@ test_expect_failure 'am: directory rename detected' '
)
'
test_expect_success 'setup testcase where directory rename should NOT be detected' '
test_create_repo no-dir-rename &&
(
cd no-dir-rename &&
mkdir x &&
test_seq 1 10 >x/a &&
test_seq 11 20 >x/b &&
test_seq 21 30 >x/c &&
echo original >project_info &&
git add x project_info &&
git commit -m "Initial" &&
git branch O &&
git branch A &&
git branch B &&
git checkout A &&
echo v2 >project_info &&
git add project_info &&
git commit -m "Modify project_info" &&
git checkout B &&
mkdir y &&
git mv x/c y/c &&
echo v1 >project_info &&
git add project_info &&
git commit -m "Rename x/c to y/c, modify project_info"
)
'
test_expect_success 'rebase --interactive: NO directory rename' '
test_when_finished "git -C no-dir-rename rebase --abort" &&
(
cd no-dir-rename &&
git checkout B^0 &&
set_fake_editor &&
test_must_fail env FAKE_LINES="1" git rebase --interactive A &&
git ls-files -s >out &&
test_line_count = 6 out &&
test_path_is_file x/a &&
test_path_is_file x/b &&
test_path_is_missing x/c
)
'
test_expect_success 'rebase (am): NO directory rename' '
test_when_finished "git -C no-dir-rename rebase --abort" &&
(
cd no-dir-rename &&
git checkout B^0 &&
set_fake_editor &&
test_must_fail git rebase A &&
git ls-files -s >out &&
test_line_count = 6 out &&
test_path_is_file x/a &&
test_path_is_file x/b &&
test_path_is_missing x/c
)
'
test_expect_success 'rebase --merge: NO directory rename' '
test_when_finished "git -C no-dir-rename rebase --abort" &&
(
cd no-dir-rename &&
git checkout B^0 &&
set_fake_editor &&
test_must_fail git rebase --merge A &&
git ls-files -s >out &&
test_line_count = 6 out &&
test_path_is_file x/a &&
test_path_is_file x/b &&
test_path_is_missing x/c
)
'
test_expect_success 'am: NO directory rename' '
test_when_finished "git -C no-dir-rename am --abort" &&
(
cd no-dir-rename &&
git checkout A^0 &&
git format-patch -1 B &&
test_must_fail git am --3way 0001*.patch &&
git ls-files -s >out &&
test_line_count = 6 out &&
test_path_is_file x/a &&
test_path_is_file x/b &&
test_path_is_missing x/c
)
'
test_done