Merge branch 'by/log-follow'
authorJunio C Hamano <gitster@pobox.com>
Fri, 21 May 2010 11:02:23 +0000 (04:02 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 21 May 2010 11:02:23 +0000 (04:02 -0700)
* by/log-follow:
tests: rename duplicate t4205
Make git log --follow find copies among unmodified files.
Make diffcore_std only can run once before a diff_flush
Add a macro DIFF_QUEUE_CLEAR.

Documentation/git-log.txt
diff.c
diffcore-break.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
t/t4206-log-follow-harder-copies.sh [new file with mode: 0755]
tree-diff.c
index 57aa57467537d38f2e3ddcd86f701a0ed74bb42f..a2d55f974525c59f3dd51684531861bf0dc49a23 100644 (file)
@@ -57,7 +57,7 @@ include::diff-options.txt[]
        commits, and doesn't limit diff for those commits.
 
 --follow::
-       Continue listing the history of a file beyond renames.
+       Continue listing the history of a file beyond renames/copies.
 
 --log-size::
        Before the log message print out its size in bytes. Intended
diff --git a/diff.c b/diff.c
index 502b301670a13ae146974d8ba4a956c2f6e3dbf3..494f5601e97e7395e647296bc7f8090331a47c43 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -2600,6 +2600,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
 void diff_setup(struct diff_options *options)
 {
        memset(options, 0, sizeof(*options));
+       memset(&diff_queued_diff, 0, sizeof(diff_queued_diff));
 
        options->file = stdout;
 
@@ -3541,8 +3542,7 @@ int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1)
                diff_free_filepair(q->queue[i]);
 
        free(q->queue);
-       q->queue = NULL;
-       q->nr = q->alloc = 0;
+       DIFF_QUEUE_CLEAR(q);
 
        return result;
 }
@@ -3670,8 +3670,7 @@ void diff_flush(struct diff_options *options)
                diff_free_filepair(q->queue[i]);
 free_queue:
        free(q->queue);
-       q->queue = NULL;
-       q->nr = q->alloc = 0;
+       DIFF_QUEUE_CLEAR(q);
        if (options->close_file)
                fclose(options->file);
 
@@ -3693,8 +3692,7 @@ static void diffcore_apply_filter(const char *filter)
        int i;
        struct diff_queue_struct *q = &diff_queued_diff;
        struct diff_queue_struct outq;
-       outq.queue = NULL;
-       outq.nr = outq.alloc = 0;
+       DIFF_QUEUE_CLEAR(&outq);
 
        if (!filter)
                return;
@@ -3762,8 +3760,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
        int i;
        struct diff_queue_struct *q = &diff_queued_diff;
        struct diff_queue_struct outq;
-       outq.queue = NULL;
-       outq.nr = outq.alloc = 0;
+       DIFF_QUEUE_CLEAR(&outq);
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
@@ -3824,6 +3821,12 @@ void diffcore_fix_diff_index(struct diff_options *options)
 
 void diffcore_std(struct diff_options *options)
 {
+       /* We never run this function more than one time, because the
+        * rename/copy detection logic can only run once.
+        */
+       if (diff_queued_diff.run)
+               return;
+
        if (options->skip_stat_unmatch)
                diffcore_skip_stat_unmatch(options);
        if (options->break_opt != -1)
@@ -3843,6 +3846,8 @@ void diffcore_std(struct diff_options *options)
                DIFF_OPT_SET(options, HAS_CHANGES);
        else
                DIFF_OPT_CLR(options, HAS_CHANGES);
+
+       diff_queued_diff.run = 1;
 }
 
 int diff_result_code(struct diff_options *opt, int status)
index 3a7b60a037b2e3c869afe76a23b671cfd5311338..44f8678d22ea466b0867591429bbcc3285cdaf91 100644 (file)
@@ -162,8 +162,7 @@ void diffcore_break(int break_score)
        if (!merge_score)
                merge_score = DEFAULT_MERGE_SCORE;
 
-       outq.nr = outq.alloc = 0;
-       outq.queue = NULL;
+       DIFF_QUEUE_CLEAR(&outq);
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
@@ -256,8 +255,7 @@ void diffcore_merge_broken(void)
        struct diff_queue_struct outq;
        int i, j;
 
-       outq.nr = outq.alloc = 0;
-       outq.queue = NULL;
+       DIFF_QUEUE_CLEAR(&outq);
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
index d0ef8397008824fb5139680856e3229ecf2c4eb1..929de15aa9228099b3a772be788d746e440a9e8c 100644 (file)
@@ -55,8 +55,7 @@ void diffcore_pickaxe(const char *needle, int opts)
        int i, has_changes;
        regex_t regex, *regexp = NULL;
        struct diff_queue_struct outq;
-       outq.queue = NULL;
-       outq.nr = outq.alloc = 0;
+       DIFF_QUEUE_CLEAR(&outq);
 
        if (opts & DIFF_PICKAXE_REGEX) {
                int err;
index d6fd3cacd6de4757994c61903dd07e0c4d74a9e9..df41be56deab60d4d39a45920a1e62b05d0474f6 100644 (file)
@@ -569,8 +569,7 @@ void diffcore_rename(struct diff_options *options)
        /* At this point, we have found some renames and copies and they
         * are recorded in rename_dst.  The original list is still in *q.
         */
-       outq.queue = NULL;
-       outq.nr = outq.alloc = 0;
+       DIFF_QUEUE_CLEAR(&outq);
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
                struct diff_filepair *pair_to_free = NULL;
index fcd00bf27aee4e1f2823f05ab3dba1d3c70a509d..491bea0b44963461cfce30b07ec96a9005a3c910 100644 (file)
@@ -91,7 +91,14 @@ struct diff_queue_struct {
        struct diff_filepair **queue;
        int alloc;
        int nr;
+       int run;
 };
+#define DIFF_QUEUE_CLEAR(q) \
+       do { \
+               (q)->queue = NULL; \
+               (q)->nr = (q)->alloc = 0; \
+               (q)->run = 0; \
+       } while(0);
 
 extern struct diff_queue_struct diff_queued_diff;
 extern struct diff_filepair *diff_queue(struct diff_queue_struct *,
diff --git a/t/t4206-log-follow-harder-copies.sh b/t/t4206-log-follow-harder-copies.sh
new file mode 100755 (executable)
index 0000000..ad29e65
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Bo Yang
+#
+
+test_description='Test --follow should always find copies hard in git log.
+
+'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/diff-lib.sh
+
+echo >path0 'Line 1
+Line 2
+Line 3
+'
+
+test_expect_success \
+    'add a file path0 and commit.' \
+    'git add path0 &&
+     git commit -m "Add path0"'
+
+echo >path0 'New line 1
+New line 2
+New line 3
+'
+test_expect_success \
+    'Change path0.' \
+    'git add path0 &&
+     git commit -m "Change path0"'
+
+cat <path0 >path1
+test_expect_success \
+    'copy path0 to path1.' \
+    'git add path1 &&
+     git commit -m "Copy path1 from path0"'
+
+test_expect_success \
+    'find the copy path0 -> path1 harder' \
+    'git log --follow --name-status --pretty="format:%s"  path1 > current'
+
+cat >expected <<\EOF
+Copy path1 from path0
+C100   path0   path1
+
+Change path0
+M      path0
+
+Add path0
+A      path0
+EOF
+
+test_expect_success \
+    'validate the output.' \
+    'compare_diff_patch current expected'
+
+test_done
index fe9f52c4796512f40869e511b55a2d97fa84532e..1fb3e94614de4973a242b1f039ee7711a74fad9d 100644 (file)
@@ -346,7 +346,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
 
        diff_setup(&diff_opts);
        DIFF_OPT_SET(&diff_opts, RECURSIVE);
-       diff_opts.detect_rename = DIFF_DETECT_RENAME;
+       DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = opt->paths[0];
        diff_opts.break_opt = opt->break_opt;