Skip to content

Commit 5f47cb4

Browse files
committed
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.
1 parent ca782c9 commit 5f47cb4

File tree

4 files changed

+22
-7
lines changed

4 files changed

+22
-7
lines changed

src/diff_print.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,9 @@ int diff_delta_format_similarity_header(
359359
abort();
360360

361361
if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 ||
362-
(error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
363-
(error = git_buf_quote(&old_path)) < 0 ||
364-
(error = git_buf_quote(&new_path)) < 0)
362+
(error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
363+
(error = git_buf_quote(&old_path)) < 0 ||
364+
(error = git_buf_quote(&new_path)) < 0)
365365
goto done;
366366

367367
git_buf_printf(out,
@@ -428,8 +428,11 @@ int git_diff_delta__format_file_header(
428428
git_buf_printf(out, "diff --git %s %s\n",
429429
old_path.ptr, new_path.ptr);
430430

431+
if (unchanged && delta->old_file.mode != delta->new_file.mode)
432+
diff_print_modes(out, delta);
433+
431434
if (delta->status == GIT_DELTA_RENAMED ||
432-
(delta->status == GIT_DELTA_COPIED && unchanged)) {
435+
(delta->status == GIT_DELTA_COPIED && unchanged)) {
433436
if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
434437
goto done;
435438
}
@@ -444,9 +447,6 @@ int git_diff_delta__format_file_header(
444447
"--- %s\n+++ %s\n", old_path.ptr, new_path.ptr);
445448
}
446449

447-
if (unchanged && delta->old_file.mode != delta->new_file.mode)
448-
diff_print_modes(out, delta);
449-
450450
if (git_buf_oom(out))
451451
error = -1;
452452

src/patch_parse.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ static const parse_header_transition transitions[] = {
411411
{ "GIT binary patch" , STATE_INDEX, STATE_END, NULL },
412412
{ "Binary files " , STATE_INDEX, STATE_END, NULL },
413413

414+
{ "similarity index " , STATE_END, STATE_SIMILARITY, parse_header_similarity },
414415
{ "similarity index " , STATE_DIFF, STATE_SIMILARITY, parse_header_similarity },
415416
{ "dissimilarity index ", STATE_DIFF, STATE_SIMILARITY, parse_header_dissimilarity },
416417
{ "rename from " , STATE_SIMILARITY, STATE_RENAME, parse_header_renamefrom },

tests/patch/patch_common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,14 @@
579579
"rename from file.txt\n" \
580580
"rename to newfile.txt\n"
581581

582+
#define PATCH_RENAME_EXACT_WITH_MODE \
583+
"diff --git a/RENAMED.md b/README.md\n" \
584+
"old mode 100644\n" \
585+
"new mode 100755\n" \
586+
"similarity index 100%\n" \
587+
"rename from RENAMED.md\n" \
588+
"rename to README.md\n"
589+
582590
#define PATCH_RENAME_SIMILAR \
583591
"diff --git a/file.txt b/newfile.txt\n" \
584592
"similarity index 77%\n" \

tests/patch/print.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ void test_patch_print__rename_exact(void)
107107
strlen(PATCH_RENAME_EXACT));
108108
}
109109

110+
void test_patch_print__rename_exact_with_mode(void)
111+
{
112+
patch_print_from_patchfile(PATCH_RENAME_EXACT_WITH_MODE,
113+
strlen(PATCH_RENAME_EXACT_WITH_MODE));
114+
}
115+
110116
void test_patch_print__rename_similar(void)
111117
{
112118
patch_print_from_patchfile(PATCH_RENAME_SIMILAR,

0 commit comments

Comments
 (0)