summaryrefslogtreecommitdiff
path: root/apply.c
diff options
context:
space:
mode:
authorJonathan Tan <jonathantanmy@google.com>2020-10-20 22:04:52 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-10-20 22:21:41 (GMT)
commitb0f266de11e9dc3a140ff9407a47604bef0e257f (patch)
tree9aeb6042ad47a337ddade81d125b82324d764564 /apply.c
parent69986e19ffcfb9af674ae5180689ab7bbf92ed28 (diff)
downloadgit-b0f266de11e9dc3a140ff9407a47604bef0e257f.zip
git-b0f266de11e9dc3a140ff9407a47604bef0e257f.tar.gz
git-b0f266de11e9dc3a140ff9407a47604bef0e257f.tar.bz2
apply: when -R, also reverse list of sections
A patch changing a symlink into a file is written with 2 sections (in the code, represented as "struct patch"): firstly, the deletion of the symlink, and secondly, the creation of the file. When applying that patch with -R, the sections are reversed, so we get: (1) creation of a symlink, then (2) deletion of a file. This causes an issue when the "deletion of a file" section is checked, because Git observes that the so-called file is not a file but a symlink, resulting in a "wrong type" error message. What we want is: (1) deletion of a file, then (2) creation of a symlink. In the code, this is reflected in the behavior of previous_patch() when invoked from check_preimage() when the deletion is checked. Creation then deletion means that when the deletion is checked, previous_patch() returns the creation section, triggering a mode conflict resulting in the "wrong type" error message. But deletion then creation means that when the deletion is checked, previous_patch() returns NULL, so the deletion mode is checked against lstat, which is what we want. There are also other ways a patch can contain 2 sections referencing the same file, for example, in 7a07841c0b ("git-apply: handle a patch that touches the same path more than once better", 2008-06-27). "git apply -R" fails in the same way, and this commit makes this case succeed. Therefore, when building the list of sections, build them in reverse order (by adding to the front of the list instead of the back) when -R is passed. Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'apply.c')
-rw-r--r--apply.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/apply.c b/apply.c
index 76dba93..359ceb6 100644
--- a/apply.c
+++ b/apply.c
@@ -4699,8 +4699,13 @@ static int apply_patch(struct apply_state *state,
reverse_patches(patch);
if (use_patch(state, patch)) {
patch_stats(state, patch);
- *listp = patch;
- listp = &patch->next;
+ if (!list || !state->apply_in_reverse) {
+ *listp = patch;
+ listp = &patch->next;
+ } else {
+ patch->next = list;
+ list = patch;
+ }
if ((patch->new_name &&
ends_with_path_components(patch->new_name,