Skip to content

Commit

Permalink
patch: correctly handle mode changes for renames
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pks-t committed Mar 26, 2020
1 parent ca782c9 commit 5f47cb4
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 7 deletions.
14 changes: 7 additions & 7 deletions src/diff_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;

Expand Down
1 change: 1 addition & 0 deletions src/patch_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
8 changes: 8 additions & 0 deletions tests/patch/patch_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
6 changes: 6 additions & 0 deletions tests/patch/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 5f47cb4

Please sign in to comment.