From ca4e3ca029def86b7b29451d4ba77ef76574949e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZEDER=20G=C3=A1bor?= Date: Wed, 30 Mar 2016 10:35:07 +0200 Subject: diffcore: fix iteration order of identical files during rename detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the two paths 'dir/A/file' and 'dir/B/file' have identical content and the parent directory is renamed, e.g. 'git mv dir other-dir', then diffcore reports the following exact renames: renamed: dir/B/file -> other-dir/A/file renamed: dir/A/file -> other-dir/B/file While technically not wrong, this is confusing not only for the user, but also for git commands that make decisions based on rename information, e.g. 'git log --follow other-dir/A/file' follows 'dir/B/file' past the rename. This behavior is a side effect of commit v2.0.0-rc4~8^2~14 (diffcore-rename.c: simplify finding exact renames, 2013-11-14): the hashmap storing sources returns entries from the same bucket, i.e. sources matching the current destination, in LIFO order. Thus the iteration first examines 'other-dir/A/file' and 'dir/B/file' and, upon finding identical content and basename, reports an exact rename. Other hashmap users are apparently happy with the current iteration order over the entries of a bucket. Changing the iteration order would risk upsetting other hashmap users and would increase the memory footprint of each bucket by a pointer to the tail element. Fill the hashmap with source entries in reverse order to restore the original exact rename detection behavior. Reported-by: Bill Okara Signed-off-by: SZEDER Gábor Signed-off-by: Junio C Hamano --- diffcore-rename.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'diffcore-rename.c') diff --git a/diffcore-rename.c b/diffcore-rename.c index af1fe0886..69fcf77be 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -340,9 +340,11 @@ static int find_exact_renames(struct diff_options *options) int i, renames = 0; struct hashmap file_table; - /* Add all sources to the hash table */ + /* Add all sources to the hash table in reverse order, because + * later on they will be retrieved in LIFO order. + */ hashmap_init(&file_table, NULL, rename_src_nr); - for (i = 0; i < rename_src_nr; i++) + for (i = rename_src_nr-1; i >= 0; i--) insert_file_table(&file_table, i, rename_src[i].p->one); /* Walk the destinations and find best source match */ -- cgit v1.2.1