diff-files: -c and --cc options.
authorJunio C Hamano <junkio@cox.net>
Sat, 28 Jan 2006 08:03:38 +0000 (00:03 -0800)
committerJunio C Hamano <junkio@cox.net>
Sat, 28 Jan 2006 08:08:29 +0000 (00:08 -0800)
This ports the "combined diff" to diff-files so that differences
to the working tree files since stage 2 and stage 3 are shown
the same way as combined diff output from diff-tree for the
merge commit would be shown if the current working tree files
are committed.

Signed-off-by: Junio C Hamano <junkio@cox.net>
combine-diff.c
diff-files.c
diff.h

index df52fa20ecb3ef1b3dfe5a57d15a91e69e266022..243f96775aaa058581491544f53f05a3bd038cc0 100644 (file)
@@ -4,14 +4,6 @@
 #include "diffcore.h"
 #include "quote.h"
 
-struct path_list {
-       struct path_list *next;
-       int len;
-       char *path;
-       unsigned char sha1[20];
-       unsigned char parent_sha1[FLEX_ARRAY][20];
-};
-
 static int uninteresting(struct diff_filepair *p)
 {
        if (diff_unmodified_pair(p))
@@ -21,15 +13,14 @@ static int uninteresting(struct diff_filepair *p)
        return 0;
 }
 
-static struct path_list *intersect_paths(struct path_list *curr,
-                                        int n, int num_parent)
+static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
-       struct path_list *p;
+       struct combine_diff_path *p;
        int i;
 
        if (!n) {
-               struct path_list *list = NULL, **tail = &list;
+               struct combine_diff_path *list = NULL, **tail = &list;
                for (i = 0; i < q->nr; i++) {
                        int len;
                        const char *path;
@@ -532,18 +523,52 @@ static void dump_sline(struct sline *sline, int cnt, int num_parent)
        }
 }
 
-static int show_combined_diff(struct path_list *elem, int num_parent,
-                             int dense, const char *header, int show_empty)
+int show_combined_diff(struct combine_diff_path *elem, int num_parent,
+                      int dense, const char *header, int show_empty)
 {
        unsigned long size, cnt, lno;
        char *result, *cp, *ep;
        struct sline *sline; /* survived lines */
        int i, show_hunks, shown_header = 0;
-       char ourtmp[TMPPATHLEN];
+       char ourtmp_buf[TMPPATHLEN];
+       char *ourtmp = ourtmp_buf;
 
        /* Read the result of merge first */
-       result = grab_blob(elem->sha1, &size);
-       write_to_temp_file(ourtmp, result, size);
+       if (memcmp(elem->sha1, null_sha1, 20)) {
+               result = grab_blob(elem->sha1, &size);
+               write_to_temp_file(ourtmp, result, size);
+       }
+       else {
+               struct stat st;
+               int fd;
+               ourtmp = elem->path;
+               if (0 <= (fd = open(ourtmp, O_RDONLY)) &&
+                   !fstat(fd, &st)) {
+                       int len = st.st_size;
+                       int cnt = 0;
+
+                       size = len;
+                       result = xmalloc(len + 1);
+                       while (cnt < len) {
+                               int done = xread(fd, result+cnt, len-cnt);
+                               if (done == 0)
+                                       break;
+                               if (done < 0)
+                                       die("read error '%s'", ourtmp);
+                               cnt += done;
+                       }
+                       result[len] = 0;
+               }
+               else {
+                       /* deleted file */
+                       size = 0;
+                       result = xmalloc(1);
+                       result[0] = 0;
+                       ourtmp = "/dev/null";
+               }
+               if (0 <= fd)
+                       close(fd);
+       }
 
        for (cnt = 0, cp = result; cp - result < size; cp++) {
                if (*cp == '\n')
@@ -589,7 +614,8 @@ static int show_combined_diff(struct path_list *elem, int num_parent,
                putchar('\n');
                dump_sline(sline, cnt, num_parent);
        }
-       unlink(ourtmp);
+       if (ourtmp == ourtmp_buf)
+               unlink(ourtmp);
        free(result);
 
        for (i = 0; i < cnt; i++) {
@@ -613,7 +639,7 @@ int diff_tree_combined_merge(const unsigned char *sha1,
        struct commit *commit = lookup_commit(sha1);
        struct diff_options diffopts;
        struct commit_list *parents;
-       struct path_list *p, *paths = NULL;
+       struct combine_diff_path *p, *paths = NULL;
        int num_parent, i, num_paths;
 
        diff_setup(&diffopts);
@@ -654,7 +680,7 @@ int diff_tree_combined_merge(const unsigned char *sha1,
 
        /* Clean things up */
        while (paths) {
-               struct path_list *tmp = paths;
+               struct combine_diff_path *tmp = paths;
                paths = paths->next;
                free(tmp);
        }
index 6c0696c34f0af95acbfe06f644f7df7fb1e93509..4a30c56f8471c4a816e989dfb63ea66db93c8b3f 100644 (file)
@@ -7,12 +7,14 @@
 #include "diff.h"
 
 static const char diff_files_usage[] =
-"git-diff-files [-q] [-0/-1/2/3] [<common diff options>] [<path>...]"
+"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 static struct diff_options diff_options;
 static int silent = 0;
 static int diff_unmerged_stage = 2;
+static int combine_merges = 0;
+static int dense_combined_merges = 0;
 
 static void show_unmerge(const char *path)
 {
@@ -66,6 +68,10 @@ int main(int argc, const char **argv)
                        ; /* no-op */
                else if (!strcmp(argv[1], "-s"))
                        ; /* no-op */
+               else if (!strcmp(argv[1], "-c"))
+                       combine_merges = 1;
+               else if (!strcmp(argv[1], "--cc"))
+                       dense_combined_merges = combine_merges = 1;
                else {
                        int diff_opt_cnt;
                        diff_opt_cnt = diff_opt_parse(&diff_options,
@@ -82,6 +88,9 @@ int main(int argc, const char **argv)
                }
                argv++; argc--;
        }
+       if (combine_merges) {
+               diff_options.output_format = DIFF_FORMAT_PATCH;
+       }
 
        /* Find the directory, and set up the pathspec */
        pathspec = get_pathspec(prefix, argv + 1);
@@ -108,14 +117,35 @@ int main(int argc, const char **argv)
                        continue;
 
                if (ce_stage(ce)) {
-                       show_unmerge(ce->name);
+                       struct {
+                               struct combine_diff_path p;
+                               unsigned char fill[4][20];
+                       } combine;
+
+                       combine.p.next = NULL;
+                       combine.p.len = ce_namelen(ce);
+                       combine.p.path = xmalloc(combine.p.len + 1);
+                       memcpy(combine.p.path, ce->name, combine.p.len);
+                       combine.p.path[combine.p.len] = 0;
+                       memset(combine.p.sha1, 0, 100);
+
                        while (i < entries) {
                                struct cache_entry *nce = active_cache[i];
+                               int stage;
 
                                if (strcmp(ce->name, nce->name))
                                        break;
+
+                               /* Stage #2 (ours) is the first parent,
+                                * stage #3 (theirs) is the second.
+                                */
+                               stage = ce_stage(nce);
+                               if (2 <= stage)
+                                       memcpy(combine.p.parent_sha1[stage-2],
+                                              nce->sha1, 20);
+
                                /* diff against the proper unmerged stage */
-                               if (ce_stage(nce) == diff_unmerged_stage)
+                               if (stage == diff_unmerged_stage)
                                        ce = nce;
                                i++;
                        }
@@ -123,10 +153,19 @@ int main(int argc, const char **argv)
                         * Compensate for loop update
                         */
                        i--;
+
+                       if (combine_merges) {
+                               show_combined_diff(&combine.p, 2,
+                                                  dense_combined_merges,
+                                                  NULL, 0);
+                               continue;
+                       }
+
                        /*
                         * Show the diff for the 'ce' if we found the one
                         * from the desired stage.
                         */
+                       show_unmerge(ce->name);
                        if (ce_stage(ce) != diff_unmerged_stage)
                                continue;
                }
diff --git a/diff.h b/diff.h
index ab0d47b982ac462843f6fbde555ea902f332b97d..539bd2f5ce98b779885b9a3fdc2e838b5b293d6b 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -56,6 +56,17 @@ extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
 extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
                          const char *base, struct diff_options *opt);
 
+struct combine_diff_path {
+       struct combine_diff_path *next;
+       int len;
+       char *path;
+       unsigned char sha1[20];
+       unsigned char parent_sha1[FLEX_ARRAY][20];
+};
+
+int show_combined_diff(struct combine_diff_path *elem, int num_parent,
+                      int dense, const char *header, int show_empty);
+
 extern int diff_tree_combined_merge(const unsigned char *sha1, const char *, int, int);
 
 extern void diff_addremove(struct diff_options *,