From 60896c7bfed67f1c7364595213ef9239642f83c5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 22 May 2005 21:24:49 -0700 Subject: [PATCH] [PATCH] Be careful with symlinks when detecting renames and copies. Earlier round was not treating symbolic links carefully enough, and would have produced diff output that renamed/copied then edited the contents of a symbolic link, which made no practical sense. Change it to detect only pure renames. Signed-off-by: Junio C Hamano Signed-off-by: Linus Torvalds --- diffcore-rename.c | 24 +++++++------ t/t4004-diff-rename-symlink.sh | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 t/t4004-diff-rename-symlink.sh diff --git a/diffcore-rename.c b/diffcore-rename.c index 794e5cc7d..52f09d231 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -20,7 +20,7 @@ static void diff_rename_pool_add(struct diff_rename_pool *pool, struct diff_filespec *s) { if (S_ISDIR(s->mode)) - return; /* rename/copy patch for tree does not make sense. */ + return; /* no trees, please */ if (pool->alloc <= pool->nr) { pool->alloc = alloc_nr(pool->alloc); @@ -71,6 +71,13 @@ static int estimate_similarity(struct diff_filespec *src, unsigned long delta_size, base_size; int score; + /* We deal only with regular files. Symlink renames are handled + * only when they are exact matches --- in other words, no edits + * after renaming. + */ + if (!S_ISREG(src->mode) || !S_ISREG(dst->mode)) + return 0; + delta_size = ((src->size < dst->size) ? (dst->size - src->size) : (src->size - dst->size)); base_size = ((src->size < dst->size) ? src->size : dst->size); @@ -268,7 +275,7 @@ void diffcore_rename(int detect_rename, int minimum_score) struct diff_filepair *p = q->queue[i]; if (!DIFF_FILE_VALID(p->one)) if (!DIFF_FILE_VALID(p->two)) - continue; /* ignore nonsense */ + continue; /* unmerged */ else diff_rename_pool_add(&created, p->two); else if (!DIFF_FILE_VALID(p->two)) @@ -360,12 +367,9 @@ void diffcore_rename(int detect_rename, int minimum_score) for (i = 0; i < q->nr; i++) { struct diff_filepair *dp, *p = q->queue[i]; if (!DIFF_FILE_VALID(p->one)) { - if (DIFF_FILE_VALID(p->two)) { - /* creation */ - dp = diff_queue(&outq, p->one, p->two); - dp->xfrm_work = 4; - } - /* otherwise it is a nonsense; just ignore it */ + /* creation or unmerged entries */ + dp = diff_queue(&outq, p->one, p->two); + dp->xfrm_work = 4; } else if (!DIFF_FILE_VALID(p->two)) { /* deletion */ @@ -394,7 +398,7 @@ void diffcore_rename(int detect_rename, int minimum_score) for (i = 0; i < outq.nr; i++) { struct diff_filepair *p = outq.queue[i]; if (!DIFF_FILE_VALID(p->one)) { - /* created */ + /* created or unmerged */ if (p->two->xfrm_flags & RENAME_DST_MATCHED) ; /* rename/copy created it already */ else @@ -443,7 +447,7 @@ void diffcore_rename(int detect_rename, int minimum_score) else /* otherwise it is a modified (or stayed) entry */ diff_queue(q, p->one, p->two); - free(p); + diff_free_filepair(p); } free(outq.queue); diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh new file mode 100644 index 000000000..31fdc5065 --- /dev/null +++ b/t/t4004-diff-rename-symlink.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# + +test_description='More rename detection tests. + +The rename detection logic should be able to detect pure rename or +copy of symbolic links, but should not produce rename/copy followed +by an edit for them. +' +. ./test-lib.sh + +test_expect_success \ + 'prepare reference tree' \ + 'echo xyzzy | tr -d '\\\\'012 >yomin && + ln -s xyzzy frotz && + git-update-cache --add frotz yomin && + tree=$(git-write-tree) && + echo $tree' + +test_expect_success \ + 'prepare work tree' \ + 'mv frotz rezrov && + rm -f yomin && + ln -s xyzzy nitfol && + ln -s xzzzy bozbar && + git-update-cache --add --remove frotz rezrov nitfol bozbar yomin' + +# tree has frotz pointing at xyzzy, and yomin that contains xyzzy to +# confuse things. work tree has rezrov (xyzzy) nitfol (xyzzy) and +# bozbar (xzzzy). +# rezrov and nitfol are rename/copy of frotz and bozbar should be +# a new creation. + +GIT_DIFF_OPTS=--unified=0 git-diff-cache -M -p $tree >current +cat >expected <<\EOF +diff --git a/frotz b/nitfol +similarity index 100% +copy from frotz +copy to nitfol +diff --git a/frotz b/rezrov +similarity index 100% +rename old frotz +rename new rezrov +diff --git a/yomin b/yomin +deleted file mode 100644 +--- a/yomin ++++ /dev/null +@@ -1 +0,0 @@ +-xyzzy +\ No newline at end of file +diff --git a/bozbar b/bozbar +new file mode 120000 +--- /dev/null ++++ b/bozbar +@@ -0,0 +1 @@ ++xzzzy +\ No newline at end of file +EOF + +test_expect_success \ + 'validate diff output' \ + 'diff -u current expected' + +test_done -- 2.30.2