X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=diff-tree.c;h=f55a35a9d5f9ae4e3f7d3fd778a953cc9cc533ad;hb=9acf322d69f54ff5bf9de8b2d6f9cd1dccf523a3;hp=da9c68c16f721eabbd80db1ec7483f92a2854e29;hpb=302ebfe52192fff9a2c1c612dff22325fd073acc;p=git.git diff --git a/diff-tree.c b/diff-tree.c index da9c68c1..f55a35a9 100644 --- a/diff-tree.c +++ b/diff-tree.c @@ -6,7 +6,10 @@ static int show_root_diff = 0; static int no_commit_id = 0; static int verbose_header = 0; static int ignore_merges = 1; +static int combine_merges = 0; +static int dense_combined_merges = 0; static int read_stdin = 0; +static int always_show_header = 0; static const char *header = NULL; static const char *header_prefix = ""; @@ -14,11 +17,6 @@ static enum cmit_fmt commit_format = CMIT_FMT_RAW; static struct diff_options diff_options; -static void call_diff_setup_done(void) -{ - diff_setup_done(&diff_options); -} - static int call_diff_flush(void) { diffcore_std(&diff_options); @@ -43,7 +41,6 @@ static int diff_tree_sha1_top(const unsigned char *old, { int ret; - call_diff_setup_done(); ret = diff_tree_sha1(old, new, base, &diff_options); call_diff_flush(); return ret; @@ -55,7 +52,6 @@ static int diff_root_tree(const unsigned char *new, const char *base) void *tree; struct tree_desc empty, real; - call_diff_setup_done(); tree = read_object_with_reference(new, "tree", &real.size, NULL); if (!tree) die("unable to read root tree (%s)", sha1_to_hex(new)); @@ -69,52 +65,71 @@ static int diff_root_tree(const unsigned char *new, const char *base) return retval; } -static const char *generate_header(const char *commit, const char *parent, const char *msg, unsigned long len) +static const char *generate_header(const unsigned char *commit_sha1, + const unsigned char *parent_sha1, + const struct commit *commit) { static char this_header[16384]; int offset; + unsigned long len; + int abbrev = diff_options.abbrev; + const char *msg = commit->buffer; if (!verbose_header) - return commit; - - offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent); - offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset); + return sha1_to_hex(commit_sha1); + + len = strlen(msg); + + offset = sprintf(this_header, "%s%s ", + header_prefix, + diff_unique_abbrev(commit_sha1, abbrev)); + if (commit_sha1 != parent_sha1) + offset += sprintf(this_header + offset, "(from %s)\n", + parent_sha1 + ? diff_unique_abbrev(parent_sha1, abbrev) + : "root"); + else + offset += sprintf(this_header + offset, "(from parents)\n"); + offset += pretty_print_commit(commit_format, commit, len, + this_header + offset, + sizeof(this_header) - offset, abbrev); + if (always_show_header) { + puts(this_header); + return NULL; + } return this_header; } -static int diff_tree_commit(const unsigned char *commit, const char *name) +static int diff_tree_commit(struct commit *commit) { - unsigned long size, offset; - char *buf = read_object_with_reference(commit, "commit", &size, NULL); - - if (!buf) - return -1; - - if (!name) { - static char commit_name[60]; - strcpy(commit_name, sha1_to_hex(commit)); - name = commit_name; - } + struct commit_list *parents; + unsigned const char *sha1 = commit->object.sha1; /* Root commit? */ - if (show_root_diff && memcmp(buf + 46, "parent ", 7)) { - header = generate_header(name, "root", buf, size); - diff_root_tree(commit, ""); + if (show_root_diff && !commit->parents) { + header = generate_header(sha1, NULL, commit); + diff_root_tree(sha1, ""); } /* More than one parent? */ - if (ignore_merges) { - if (!memcmp(buf + 46 + 48, "parent ", 7)) + if (commit->parents && commit->parents->next) { + if (ignore_merges) return 0; + else if (combine_merges) { + header = generate_header(sha1, sha1, commit); + header = diff_tree_combined_merge(sha1, header, + dense_combined_merges, + &diff_options); + if (!header && verbose_header) + header_prefix = "\ndiff-tree "; + return 0; + } } - offset = 46; - while (offset + 48 < size && !memcmp(buf + offset, "parent ", 7)) { - unsigned char parent[20]; - if (get_sha1_hex(buf + offset + 7, parent)) - return -1; - header = generate_header(name, sha1_to_hex(parent), buf, size); - diff_tree_sha1_top(parent, commit, ""); + for (parents = commit->parents; parents; parents = parents->next) { + struct commit *parent = parents->item; + header = generate_header(sha1, parent->object.sha1, commit); + diff_tree_sha1_top(parent->object.sha1, sha1, ""); if (!header && verbose_header) { header_prefix = "\ndiff-tree "; /* @@ -122,36 +137,58 @@ static int diff_tree_commit(const unsigned char *commit, const char *name) * don't print the diffs. */ } - offset += 48; } - free(buf); return 0; } +static int diff_tree_commit_sha1(const unsigned char *sha1) +{ + struct commit *commit = lookup_commit_reference(sha1); + if (!commit) + return -1; + return diff_tree_commit(commit); +} + static int diff_tree_stdin(char *line) { int len = strlen(line); - unsigned char commit[20], parent[20]; - static char this_header[1000]; + unsigned char sha1[20]; + struct commit *commit; if (!len || line[len-1] != '\n') return -1; line[len-1] = 0; - if (get_sha1_hex(line, commit)) + if (get_sha1_hex(line, sha1)) + return -1; + commit = lookup_commit(sha1); + if (!commit || parse_commit(commit)) return -1; - if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) { - line[40] = 0; - line[81] = 0; - sprintf(this_header, "%s (from %s)\n", line, line+41); - header = this_header; - return diff_tree_sha1_top(parent, commit, ""); + if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) { + /* Graft the fake parents locally to the commit */ + int pos = 41; + struct commit_list **pptr, *parents; + + /* Free the real parent list */ + for (parents = commit->parents; parents; ) { + struct commit_list *tmp = parents->next; + free(parents); + parents = tmp; + } + commit->parents = NULL; + pptr = &(commit->parents); + while (line[pos] && !get_sha1_hex(line + pos, sha1)) { + struct commit *parent = lookup_commit(sha1); + if (parent) { + pptr = &commit_list_insert(parent, pptr)->next; + } + pos += 41; + } } - line[40] = 0; - return diff_tree_commit(commit, line); + return diff_tree_commit(commit); } static const char diff_tree_usage[] = -"git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] [-r] [--root] " +"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " "[] [] [...]\n" " -r diff recursively\n" " --root include the initial commit as diff against /dev/null\n" @@ -214,6 +251,14 @@ int main(int argc, const char **argv) ignore_merges = 0; continue; } + if (!strcmp(arg, "-c")) { + combine_merges = 1; + continue; + } + if (!strcmp(arg, "--cc")) { + dense_combined_merges = combine_merges = 1; + continue; + } if (!strcmp(arg, "-v")) { verbose_header = 1; header_prefix = "diff-tree "; @@ -237,12 +282,25 @@ int main(int argc, const char **argv) no_commit_id = 1; continue; } + if (!strcmp(arg, "--always")) { + always_show_header = 1; + continue; + } usage(diff_tree_usage); } + + if (combine_merges) + ignore_merges = 0; + + /* We can only do dense combined merges with diff output */ + if (dense_combined_merges) + diff_options.output_format = DIFF_FORMAT_PATCH; + if (diff_options.output_format == DIFF_FORMAT_PATCH) diff_options.recursive = 1; diff_tree_setup_paths(get_pathspec(prefix, argv)); + diff_setup_done(&diff_options); switch (nr_sha1) { case 0: @@ -250,7 +308,7 @@ int main(int argc, const char **argv) usage(diff_tree_usage); break; case 1: - diff_tree_commit(sha1[0], NULL); + diff_tree_commit_sha1(sha1[0]); break; case 2: diff_tree_sha1_top(sha1[0], sha1[1], "");