diff options
author | Colin Stolley <ccstolley@github.com> | 2021-09-09 15:21:48 -0500 |
---|---|---|
committer | Colin Stolley <ccstolley@github.com> | 2021-09-15 17:09:17 -0500 |
commit | 479a38bf153f13966a423124994e4ed91561e595 (patch) | |
tree | 61416c40eb6aa230707dab1f2fad4443844a9eea | |
parent | 7d195b9c3ddffb9f9af94dcabaeb4fc77fafa378 (diff) | |
download | libgit2-479a38bf153f13966a423124994e4ed91561e595.tar.gz |
merge: Check file mode when resolving renames.
When determining if ours or theirs changed, we check the oids but not
their respective file modes. This can lead to merges introducing incorrect
file mode changes (eg., in a revert). A simple linear example might be:
commit A - introduces file `foo` with chmod 0755
commit B - updates some unrelated file
commit C - renames `foo` to `bar` and chmod 0644
If B is reverted, `bar` will unexpectedly acquire mode 0755.
-rw-r--r-- | src/merge.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/src/merge.c b/src/merge.c index 191fb98ba..1c841bdfb 100644 --- a/src/merge.c +++ b/src/merge.c @@ -816,8 +816,11 @@ static int merge_conflict_resolve_one_renamed( conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) return 0; - ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0); - theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0); + ours_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->our_entry.id) != 0) || + (conflict->ancestor_entry.mode != conflict->our_entry.mode); + + theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.id, &conflict->their_entry.id) != 0) || + (conflict->ancestor_entry.mode != conflict->their_entry.mode); /* if both are modified (and not to a common target) require a merge */ if (ours_changed && theirs_changed && |