The documentation for git's diff format does not expressly disallow changing the mode of a file without splitting it into a delete and create. Mercurial's `hg diff --git` in fact produces git diffs with such format. When applying such patches in Git, this assert can be hit. The check preventing this type of diff has been around since 2005 in 3cca928d4aae691572ef9a73dcc29a04f66900a1. Simply deleting the check that prevents changing the mode when not renaming allows such diffs to work out of the box, as the attached test case shows. --- apply.c | 18 ------------------ t/t4115-apply-symlink.sh | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apply.c b/apply.c index bdc008fae2..1b9d315771 100644 --- a/apply.c +++ b/apply.c @@ -3950,24 +3950,6 @@ static int check_patch(struct apply_state *state, struct patch *patch) } } - if (new_name && old_name) { - int same = !strcmp(old_name, new_name); - if (!patch->new_mode) - patch->new_mode = patch->old_mode; - if ((patch->old_mode ^ patch->new_mode) & S_IFMT) { - if (same) - return error(_("new mode (%o) of %s does not " - "match old mode (%o)"), - patch->new_mode, new_name, - patch->old_mode); - else - return error(_("new mode (%o) of %s does not " - "match old mode (%o) of %s"), - patch->new_mode, new_name, - patch->old_mode, old_name); - } - } - if (!state->unsafe_paths && check_unsafe_path(patch)) return -128; diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index 872fcda6cb..593e6142b4 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -44,4 +44,27 @@ test_expect_success 'apply --index symlink patch' ' ' +cat >move_patch <<\EOF +diff --git a/file_to_be_link b/file_to_be_link +old mode 100644 +new mode 120000 +--- a/file_to_be_link ++++ b/file_to_be_link +@@ -0,0 +1,1 @@ ++target +\ No newline at end of file +EOF + +test_expect_success 'apply file-to-symlink patch' ' + + git checkout -f master && + touch file_to_be_link && + git add file_to_be_link && + git commit -m initial && + + git apply move_patch && + test target = $(readlink file_to_be_link) + +' + test_done -- 2.25.1