Merge pull request #1804 from ethomson/rewrites Minor changes for rewrites
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
diff --git a/include/git2/diff.h b/include/git2/diff.h
index c989ba4..5960985 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -454,6 +454,9 @@ typedef enum {
GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = (1 << 13),
/** measure similarity only by comparing SHAs (fast and cheap) */
GIT_DIFF_FIND_EXACT_MATCH_ONLY = (1 << 14),
+
+ /** do not break rewrites unless they contribute to a rename */
+ GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY = (1 << 15),
} git_diff_find_t;
/**
diff --git a/src/diff_tform.c b/src/diff_tform.c
index 6b8cf44..cbe8baf 100644
--- a/src/diff_tform.c
+++ b/src/diff_tform.c
@@ -799,6 +799,9 @@ int git_diff_find_similar(
if (is_rename_target(diff, &opts, t, sigcache))
++num_tgts;
+
+ if ((tgt->flags & GIT_DIFF_FLAG__TO_SPLIT) != 0)
+ num_rewrites++;
}
/* if there are no candidate srcs or tgts, we're done */
@@ -1036,7 +1039,8 @@ find_best_matches:
if (num_rewrites > 0 || num_updates > 0)
error = apply_splits_and_deletes(
diff, diff->deltas.length - num_rewrites,
- FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES));
+ FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES) &&
+ !FLAG_SET(&opts, GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY));
cleanup:
git__free(tgt2src);
diff --git a/src/status.c b/src/status.c
index b235325..4a0d650 100644
--- a/src/status.c
+++ b/src/status.c
@@ -284,8 +284,10 @@ int git_status_list_new(
diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES;
if ((flags & GIT_STATUS_OPT_RENAMES_FROM_REWRITES) != 0)
- findopt.flags = findopt.flags | GIT_DIFF_FIND_AND_BREAK_REWRITES |
- GIT_DIFF_FIND_RENAMES_FROM_REWRITES;
+ findopt.flags = findopt.flags |
+ GIT_DIFF_FIND_AND_BREAK_REWRITES |
+ GIT_DIFF_FIND_RENAMES_FROM_REWRITES |
+ GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY;
if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) {
if ((error = git_diff_tree_to_index(
diff --git a/tests-clar/diff/rename.c b/tests-clar/diff/rename.c
index 5a35495..ac3814d 100644
--- a/tests-clar/diff/rename.c
+++ b/tests-clar/diff/rename.c
@@ -1235,3 +1235,52 @@ void test_diff_rename__unmodified_can_be_renamed(void)
git_index_free(index);
git_tree_free(tree);
}
+
+void test_diff_rename__rewrite_on_single_file(void)
+{
+ git_index *index;
+ git_diff_list *diff = NULL;
+ diff_expects exp;
+ git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
+ git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT;
+
+ diffopts.flags = GIT_DIFF_INCLUDE_UNTRACKED;
+
+ findopts.flags = GIT_DIFF_FIND_FOR_UNTRACKED |
+ GIT_DIFF_FIND_AND_BREAK_REWRITES |
+ GIT_DIFF_FIND_RENAMES_FROM_REWRITES;
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ cl_git_rewritefile("renames/ikeepsix.txt",
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n");
+
+ cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, &diffopts));
+ cl_git_pass(git_diff_find_similar(diff, &findopts));
+
+ memset(&exp, 0, sizeof(exp));
+
+ cl_git_pass(git_diff_foreach(
+ diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
+ cl_assert_equal_i(2, exp.files);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
+ cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
+
+ git_diff_list_free(diff);
+ git_index_free(index);
+}
diff --git a/tests-clar/status/renames.c b/tests-clar/status/renames.c
index 836e65c..d72e563 100644
--- a/tests-clar/status/renames.c
+++ b/tests-clar/status/renames.c
@@ -403,6 +403,47 @@ void test_status_renames__both_rename_from_rewrite(void)
git_index_free(index);
}
+void test_status_renames__rewrites_only_for_renames(void)
+{
+ git_index *index;
+ git_status_list *statuslist;
+ git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ struct status_entry expected[] = {
+ { GIT_STATUS_WT_MODIFIED, "ikeepsix.txt", "ikeepsix.txt" },
+ };
+
+ opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED;
+ opts.flags |= GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
+ opts.flags |= GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR;
+ opts.flags |= GIT_STATUS_OPT_RENAMES_FROM_REWRITES;
+
+ cl_git_pass(git_repository_index(&index, g_repo));
+
+ cl_git_rewritefile("renames/ikeepsix.txt",
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n" \
+ "This is enough content for the file to be rewritten.\n");
+
+ cl_git_pass(git_status_list_new(&statuslist, g_repo, &opts));
+ test_status(statuslist, expected, 1);
+ git_status_list_free(statuslist);
+
+ git_index_free(index);
+}
+
void test_status_renames__both_casechange_one(void)
{
git_index *index;