summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2020-03-26 14:16:41 +0100
committerPatrick Steinhardt <ps@pks.im>2020-03-26 14:21:35 +0100
commit5f47cb48d388279f92d339a5a791040254ee4d1c (patch)
tree5a2b1f7a3a96f12f19044ef52df88883c99d44d8
parentca782c913b7052712c7a6163c102a01733202ebf (diff)
downloadlibgit2-5f47cb48d388279f92d339a5a791040254ee4d1c.tar.gz
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.
-rw-r--r--src/diff_print.c14
-rw-r--r--src/patch_parse.c1
-rw-r--r--tests/patch/patch_common.h8
-rw-r--r--tests/patch/print.c6
4 files changed, 22 insertions, 7 deletions
diff --git a/src/diff_print.c b/src/diff_print.c
index 369e5c1e6..a78953c32 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -359,9 +359,9 @@ int diff_delta_format_similarity_header(
abort();
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_quote(&old_path)) < 0 ||
- (error = git_buf_quote(&new_path)) < 0)
+ (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
+ (error = git_buf_quote(&old_path)) < 0 ||
+ (error = git_buf_quote(&new_path)) < 0)
goto done;
git_buf_printf(out,
@@ -428,8 +428,11 @@ int git_diff_delta__format_file_header(
git_buf_printf(out, "diff --git %s %s\n",
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 ||
- (delta->status == GIT_DELTA_COPIED && unchanged)) {
+ (delta->status == GIT_DELTA_COPIED && unchanged)) {
if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
goto done;
}
@@ -444,9 +447,6 @@ int git_diff_delta__format_file_header(
"--- %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))
error = -1;
diff --git a/src/patch_parse.c b/src/patch_parse.c
index 9d089ad83..0e251cb88 100644
--- a/src/patch_parse.c
+++ b/src/patch_parse.c
@@ -411,6 +411,7 @@ static const parse_header_transition transitions[] = {
{ "GIT binary patch" , 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 },
{ "dissimilarity index ", STATE_DIFF, STATE_SIMILARITY, parse_header_dissimilarity },
{ "rename from " , STATE_SIMILARITY, STATE_RENAME, parse_header_renamefrom },
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index 731524767..1e03889fc 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -579,6 +579,14 @@
"rename from file.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 \
"diff --git a/file.txt b/newfile.txt\n" \
"similarity index 77%\n" \
diff --git a/tests/patch/print.c b/tests/patch/print.c
index c4ff479e9..b0a933943 100644
--- a/tests/patch/print.c
+++ b/tests/patch/print.c
@@ -107,6 +107,12 @@ void test_patch_print__rename_exact(void)
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)
{
patch_print_from_patchfile(PATCH_RENAME_SIMILAR,