fix git commit --amend -m "new message"
[gitweb.git] / tree-diff.c
index 42924e9b63919a74fa08b17d24700325c7700f11..e1e2e6c6ce3c4effffb26e9aed7c6bdd2b00a5ae 100644 (file)
@@ -39,7 +39,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
                show_entry(opt, "+", t2, base, baselen);
                return 1;
        }
-       if (!opt->find_copies_harder && !hashcmp(sha1, sha2) && mode1 == mode2)
+       if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2)
                return 0;
 
        /*
@@ -52,10 +52,10 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
                return 0;
        }
 
-       if (opt->recursive && S_ISDIR(mode1)) {
+       if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
                int retval;
                char *newbase = malloc_base(base, baselen, path1, pathlen1);
-               if (opt->tree_in_recursive)
+               if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
                        opt->change(opt, mode1, mode2,
                                    sha1, sha2, base, path1);
                retval = diff_tree_sha1(sha1, sha2, newbase, opt);
@@ -206,7 +206,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
        const char *path;
        const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
 
-       if (opt->recursive && S_ISDIR(mode)) {
+       if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {
                enum object_type type;
                int pathlen = tree_entry_len(path, sha1);
                char *newbase = malloc_base(base, baselen, path, pathlen);
@@ -257,7 +257,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
        int baselen = strlen(base);
 
        for (;;) {
-               if (opt->quiet && opt->has_changes)
+               if (DIFF_OPT_TST(opt, QUIET) && DIFF_OPT_TST(opt, HAS_CHANGES))
                        break;
                if (opt->nr_paths) {
                        skip_uninteresting(t1, base, baselen, opt);
@@ -305,32 +305,45 @@ static inline int diff_might_be_rename(void)
 static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
 {
        struct diff_options diff_opts;
-       const char *paths[2];
+       struct diff_queue_struct *q = &diff_queued_diff;
+       struct diff_filepair *choice;
+       const char *paths[1];
        int i;
 
+       /* Remove the file creation entry from the diff queue, and remember it */
+       choice = q->queue[0];
+       q->nr = 0;
+
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = opt->paths[0];
+       diff_opts.break_opt = opt->break_opt;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
        if (diff_setup_done(&diff_opts) < 0)
                die("unable to set up diff options to follow renames");
        diff_tree(t1, t2, base, &diff_opts);
        diffcore_std(&diff_opts);
+       diff_tree_release_paths(&diff_opts);
 
-       /* NOTE! Ignore the first diff! That was the old one! */
-       for (i = 1; i < diff_queued_diff.nr; i++) {
-               struct diff_filepair *p = diff_queued_diff.queue[i];
+       /* Go through the new set of filepairing, and see if we find a more interesting one */
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p = q->queue[i];
 
                /*
                 * Found a source? Not only do we use that for the new
-                * diff_queued_diff, we also use that as the path in
+                * diff_queued_diff, we will also use that as the path in
                 * the future!
                 */
                if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) {
-                       diff_queued_diff.queue[0] = p;
+                       /* Switch the file-pairs around */
+                       q->queue[i] = choice;
+                       choice = p;
+
+                       /* Update the path we use from now on.. */
+                       diff_tree_release_paths(opt);
                        opt->paths[0] = xstrdup(p->one->path);
                        diff_tree_setup_paths(opt->paths, opt);
                        break;
@@ -338,10 +351,19 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        }
 
        /*
-        * Then, ignore any but the first entry! It might be the old one,
-        * or it might be the rename/copy we found
+        * Then, discard all the non-relevane file pairs...
+        */
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p = q->queue[i];
+               diff_free_filepair(p);
+       }
+
+       /*
+        * .. and re-instate the one we want (which might be either the
+        * original one, or the rename/copy we found)
         */
-       diff_queued_diff.nr = 1;
+       q->queue[0] = choice;
+       q->nr = 1;
 }
 
 int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)
@@ -360,7 +382,7 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha
        init_tree_desc(&t1, tree1, size1);
        init_tree_desc(&t2, tree2, size2);
        retval = diff_tree(&t1, &t2, base, opt);
-       if (opt->follow_renames && diff_might_be_rename()) {
+       if (DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) {
                init_tree_desc(&t1, tree1, size1);
                init_tree_desc(&t2, tree2, size2);
                try_to_follow_renames(&t1, &t2, base, opt);