Commit 5f47cb48 by Patrick Steinhardt

patch: correctly handle mode changes for renames

When generating a patch for a renamed file whose mode bits have changed
in addition to the rename, then we currently fail to parse the generated
patch. Furthermore, when generating a diff we output mode bits after the
similarity metric, which is different to how upstream git handles it.

Fix both issues by adding another state transition that allows
similarity indices after mode changes and by printing mode changes
before the similarity index.
parent ca782c91
...@@ -359,9 +359,9 @@ int diff_delta_format_similarity_header( ...@@ -359,9 +359,9 @@ int diff_delta_format_similarity_header(
abort(); abort();
if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 || if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 ||
(error = git_buf_puts(&new_path, delta->new_file.path)) < 0 || (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
(error = git_buf_quote(&old_path)) < 0 || (error = git_buf_quote(&old_path)) < 0 ||
(error = git_buf_quote(&new_path)) < 0) (error = git_buf_quote(&new_path)) < 0)
goto done; goto done;
git_buf_printf(out, git_buf_printf(out,
...@@ -428,8 +428,11 @@ int git_diff_delta__format_file_header( ...@@ -428,8 +428,11 @@ int git_diff_delta__format_file_header(
git_buf_printf(out, "diff --git %s %s\n", git_buf_printf(out, "diff --git %s %s\n",
old_path.ptr, new_path.ptr); old_path.ptr, new_path.ptr);
if (unchanged && delta->old_file.mode != delta->new_file.mode)
diff_print_modes(out, delta);
if (delta->status == GIT_DELTA_RENAMED || if (delta->status == GIT_DELTA_RENAMED ||
(delta->status == GIT_DELTA_COPIED && unchanged)) { (delta->status == GIT_DELTA_COPIED && unchanged)) {
if ((error = diff_delta_format_similarity_header(out, delta)) < 0) if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
goto done; goto done;
} }
...@@ -444,9 +447,6 @@ int git_diff_delta__format_file_header( ...@@ -444,9 +447,6 @@ int git_diff_delta__format_file_header(
"--- %s\n+++ %s\n", old_path.ptr, new_path.ptr); "--- %s\n+++ %s\n", old_path.ptr, new_path.ptr);
} }
if (unchanged && delta->old_file.mode != delta->new_file.mode)
diff_print_modes(out, delta);
if (git_buf_oom(out)) if (git_buf_oom(out))
error = -1; error = -1;
......
...@@ -411,6 +411,7 @@ static const parse_header_transition transitions[] = { ...@@ -411,6 +411,7 @@ static const parse_header_transition transitions[] = {
{ "GIT binary patch" , STATE_INDEX, STATE_END, NULL }, { "GIT binary patch" , STATE_INDEX, STATE_END, NULL },
{ "Binary files " , STATE_INDEX, STATE_END, NULL }, { "Binary files " , STATE_INDEX, STATE_END, NULL },
{ "similarity index " , STATE_END, STATE_SIMILARITY, parse_header_similarity },
{ "similarity index " , STATE_DIFF, STATE_SIMILARITY, parse_header_similarity }, { "similarity index " , STATE_DIFF, STATE_SIMILARITY, parse_header_similarity },
{ "dissimilarity index ", STATE_DIFF, STATE_SIMILARITY, parse_header_dissimilarity }, { "dissimilarity index ", STATE_DIFF, STATE_SIMILARITY, parse_header_dissimilarity },
{ "rename from " , STATE_SIMILARITY, STATE_RENAME, parse_header_renamefrom }, { "rename from " , STATE_SIMILARITY, STATE_RENAME, parse_header_renamefrom },
......
...@@ -579,6 +579,14 @@ ...@@ -579,6 +579,14 @@
"rename from file.txt\n" \ "rename from file.txt\n" \
"rename to newfile.txt\n" "rename to newfile.txt\n"
#define PATCH_RENAME_EXACT_WITH_MODE \
"diff --git a/RENAMED.md b/README.md\n" \
"old mode 100644\n" \
"new mode 100755\n" \
"similarity index 100%\n" \
"rename from RENAMED.md\n" \
"rename to README.md\n"
#define PATCH_RENAME_SIMILAR \ #define PATCH_RENAME_SIMILAR \
"diff --git a/file.txt b/newfile.txt\n" \ "diff --git a/file.txt b/newfile.txt\n" \
"similarity index 77%\n" \ "similarity index 77%\n" \
......
...@@ -107,6 +107,12 @@ void test_patch_print__rename_exact(void) ...@@ -107,6 +107,12 @@ void test_patch_print__rename_exact(void)
strlen(PATCH_RENAME_EXACT)); strlen(PATCH_RENAME_EXACT));
} }
void test_patch_print__rename_exact_with_mode(void)
{
patch_print_from_patchfile(PATCH_RENAME_EXACT_WITH_MODE,
strlen(PATCH_RENAME_EXACT_WITH_MODE));
}
void test_patch_print__rename_similar(void) void test_patch_print__rename_similar(void)
{ {
patch_print_from_patchfile(PATCH_RENAME_SIMILAR, patch_print_from_patchfile(PATCH_RENAME_SIMILAR,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment