{"thread":{"id":"3837","subject":"[PATCH] log-tree: separate major part of diff-tree.","startedAt":"2006-04-09T09:03:29Z","lastAt":"2006-04-09T09:03:29Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"18493","messageId":"7vd5frce8u.fsf@assigned-by-dhcp.cox.net","threadId":"3837","inReplyTo":null,"subject":"[PATCH] log-tree: separate major part of diff-tree.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-04-09T09:03:29Z","receivedAt":"2006-04-09T09:03:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This separates out the part that deals with one-commit diff-tree\n(and --stdin form) into a separate log-tree module.\n\nThere are two goals with this.  The more important one is to be\nable to make this part available to \"git log --diff\", so that we\ncan have a native \"git whatchanged\" command.  Another is to\nsimplify the commit log generation part simpler.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n * I tried to be very careful while doing this, to make sure\n   there is no behaviour change.  This is a preparation step for\n   the next one, which is...\n\n Makefile    |    4 +\n diff-tree.c |  226 ++++++-----------------------------------------------------\n log-tree.c  |  175 ++++++++++++++++++++++++++++++++++++++++++++++\n log-tree.h  |   23 ++++++\n 4 files changed, 224 insertions(+), 204 deletions(-)\n create mode 100644 log-tree.c\n create mode 100644 log-tree.h\n\n5f1c3f07b7f4a8436c7773b8e7a04998190c125e\ndiff --git a/Makefile b/Makefile\nindex 6b10eaa..b272146 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -194,12 +194,12 @@ LIB_H = \\\n \tblob.h cache.h commit.h csum-file.h delta.h \\\n \tdiff.h object.h pack.h pkt-line.h quote.h refs.h \\\n \trun-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \\\n-\ttree-walk.h\n+\ttree-walk.h log-tree.h\n \n DIFF_OBJS = \\\n \tdiff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \\\n \tdiffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \\\n-\tdiffcore-delta.o\n+\tdiffcore-delta.o log-tree.o\n \n LIB_OBJS = \\\n \tblob.o commit.o connect.o csum-file.o \\\ndiff --git a/diff-tree.c b/diff-tree.c\nindex d1265d7..2a088d1 100644\n--- a/diff-tree.c\n+++ b/diff-tree.c\n@@ -1,152 +1,16 @@\n #include \"cache.h\"\n #include \"diff.h\"\n #include \"commit.h\"\n+#include \"log-tree.h\"\n \n-static int show_root_diff = 0;\n-static int no_commit_id = 0;\n-static int verbose_header = 0;\n-static int ignore_merges = 1;\n-static int combine_merges = 0;\n-static int dense_combined_merges = 0;\n-static int read_stdin = 0;\n-static int always_show_header = 0;\n+static struct log_tree_opt log_tree_opt;\n \n-static const char *header = NULL;\n-static const char *header_prefix = \"\";\n-static enum cmit_fmt commit_format = CMIT_FMT_RAW;\n-\n-static struct diff_options diff_options;\n-\n-static int call_diff_flush(void)\n-{\n-\tdiffcore_std(&diff_options);\n-\tif (diff_queue_is_empty()) {\n-\t\tint saved_fmt = diff_options.output_format;\n-\t\tdiff_options.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\t\tdiff_flush(&diff_options);\n-\t\tdiff_options.output_format = saved_fmt;\n-\t\treturn 0;\n-\t}\n-\tif (header) {\n-\t\tif (!no_commit_id)\n-\t\t\tprintf(\"%s%c\", header, diff_options.line_termination);\n-\t\theader = NULL;\n-\t}\n-\tdiff_flush(&diff_options);\n-\treturn 1;\n-}\n-\n-static int diff_tree_sha1_top(const unsigned char *old,\n-\t\t\t      const unsigned char *new, const char *base)\n-{\n-\tint ret;\n-\n-\tret = diff_tree_sha1(old, new, base, &diff_options);\n-\tcall_diff_flush();\n-\treturn ret;\n-}\n-\n-static int diff_root_tree(const unsigned char *new, const char *base)\n-{\n-\tint retval;\n-\tvoid *tree;\n-\tstruct tree_desc empty, real;\n-\n-\ttree = read_object_with_reference(new, tree_type, &real.size, NULL);\n-\tif (!tree)\n-\t\tdie(\"unable to read root tree (%s)\", sha1_to_hex(new));\n-\treal.buf = tree;\n-\n-\tempty.buf = \"\";\n-\tempty.size = 0;\n-\tretval = diff_tree(&empty, &real, base, &diff_options);\n-\tfree(tree);\n-\tcall_diff_flush();\n-\treturn retval;\n-}\n-\n-static const char *generate_header(const unsigned char *commit_sha1,\n-\t\t\t\t   const unsigned char *parent_sha1,\n-\t\t\t\t   const struct commit *commit)\n-{\n-\tstatic char this_header[16384];\n-\tint offset;\n-\tunsigned long len;\n-\tint abbrev = diff_options.abbrev;\n-\tconst char *msg = commit->buffer;\n-\n-\tif (!verbose_header)\n-\t\treturn sha1_to_hex(commit_sha1);\n-\n-\tlen = strlen(msg);\n-\n-\toffset = sprintf(this_header, \"%s%s \",\n-\t\t\t header_prefix,\n-\t\t\t diff_unique_abbrev(commit_sha1, abbrev));\n-\tif (commit_sha1 != parent_sha1)\n-\t\toffset += sprintf(this_header + offset, \"(from %s)\\n\",\n-\t\t\t\t  parent_sha1\n-\t\t\t\t  ? diff_unique_abbrev(parent_sha1, abbrev)\n-\t\t\t\t  : \"root\");\n-\telse\n-\t\toffset += sprintf(this_header + offset, \"(from parents)\\n\");\n-\toffset += pretty_print_commit(commit_format, commit, len,\n-\t\t\t\t      this_header + offset,\n-\t\t\t\t      sizeof(this_header) - offset, abbrev);\n-\tif (always_show_header) {\n-\t\tputs(this_header);\n-\t\treturn NULL;\n-\t}\n-\treturn this_header;\n-}\n-\n-static int diff_tree_commit(struct commit *commit)\n-{\n-\tstruct commit_list *parents;\n-\tunsigned const char *sha1 = commit->object.sha1;\n-\n-\t/* Root commit? */\n-\tif (show_root_diff && !commit->parents) {\n-\t\theader = generate_header(sha1, NULL, commit);\n-\t\tdiff_root_tree(sha1, \"\");\n-\t}\n-\n-\t/* More than one parent? */\n-\tif (commit->parents && commit->parents->next) {\n-\t\tif (ignore_merges)\n-\t\t\treturn 0;\n-\t\telse if (combine_merges) {\n-\t\t\theader = generate_header(sha1, sha1, commit);\n-\t\t\theader = diff_tree_combined_merge(sha1, header,\n-\t\t\t\t\t\t\tdense_combined_merges,\n-\t\t\t\t\t\t\t&diff_options);\n-\t\t\tif (!header && verbose_header)\n-\t\t\t\theader_prefix = \"\\ndiff-tree \";\n-\t\t\treturn 0;\n-\t\t}\n-\t}\n-\n-\tfor (parents = commit->parents; parents; parents = parents->next) {\n-\t\tstruct commit *parent = parents->item;\n-\t\theader = generate_header(sha1, parent->object.sha1, commit);\n-\t\tdiff_tree_sha1_top(parent->object.sha1, sha1, \"\");\n-\t\tif (!header && verbose_header) {\n-\t\t\theader_prefix = \"\\ndiff-tree \";\n-\t\t\t/*\n-\t\t\t * Don't print multiple merge entries if we\n-\t\t\t * don't print the diffs.\n-\t\t\t */\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n static int diff_tree_commit_sha1(const unsigned char *sha1)\n {\n \tstruct commit *commit = lookup_commit_reference(sha1);\n \tif (!commit)\n \t\treturn -1;\n-\treturn diff_tree_commit(commit);\n+\treturn log_tree_commit(&log_tree_opt, commit);\n }\n \n static int diff_tree_stdin(char *line)\n@@ -184,7 +48,7 @@ static int diff_tree_stdin(char *line)\n \t\t\tpos += 41;\n \t\t}\n \t}\n-\treturn diff_tree_commit(commit);\n+\treturn log_tree_commit(&log_tree_opt, commit);\n }\n \n static const char diff_tree_usage[] =\n@@ -200,13 +64,15 @@ int main(int argc, const char **argv)\n \tchar line[1000];\n \tunsigned char sha1[2][20];\n \tconst char *prefix = setup_git_directory();\n+\tstatic struct log_tree_opt *opt = &log_tree_opt;\n+\tint read_stdin = 0;\n \n \tgit_config(git_diff_config);\n \tnr_sha1 = 0;\n-\tdiff_setup(&diff_options);\n+\tinit_log_tree_opt(opt);\n \n \tfor (;;) {\n-\t\tint diff_opt_cnt;\n+\t\tint opt_cnt;\n \t\tconst char *arg;\n \n \t\targv++;\n@@ -223,84 +89,39 @@ int main(int argc, const char **argv)\n \t\t\tbreak;\n \t\t}\n \n-\t\tdiff_opt_cnt = diff_opt_parse(&diff_options, argv, argc);\n-\t\tif (diff_opt_cnt < 0)\n+\t\topt_cnt = log_tree_opt_parse(opt, argv, argc);\n+\t\tif (opt_cnt < 0)\n \t\t\tusage(diff_tree_usage);\n-\t\telse if (diff_opt_cnt) {\n-\t\t\targv += diff_opt_cnt - 1;\n-\t\t\targc -= diff_opt_cnt - 1;\n+\t\telse if (opt_cnt) {\n+\t\t\targv += opt_cnt - 1;\n+\t\t\targc -= opt_cnt - 1;\n \t\t\tcontinue;\n \t\t}\n \n-\n \t\tif (!strcmp(arg, \"--\")) {\n \t\t\targv++;\n \t\t\targc--;\n \t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(arg, \"-r\")) {\n-\t\t\tdiff_options.recursive = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"-t\")) {\n-\t\t\tdiff_options.recursive = 1;\n-\t\t\tdiff_options.tree_in_recursive = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"-m\")) {\n-\t\t\tignore_merges = 0;\n-\t\t\tcontinue;\n \t\t}\n-\t\tif (!strcmp(arg, \"-c\")) {\n-\t\t\tcombine_merges = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--cc\")) {\n-\t\t\tdense_combined_merges = combine_merges = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"-v\")) {\n-\t\t\tverbose_header = 1;\n-\t\t\theader_prefix = \"diff-tree \";\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strncmp(arg, \"--pretty\", 8)) {\n-\t\t\tverbose_header = 1;\n-\t\t\theader_prefix = \"diff-tree \";\n-\t\t\tcommit_format = get_commit_format(arg+8);\n-\t\t\tcontinue;\n-\t\t}\n \t\tif (!strcmp(arg, \"--stdin\")) {\n \t\t\tread_stdin = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--root\")) {\n-\t\t\tshow_root_diff = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--no-commit-id\")) {\n-\t\t\tno_commit_id = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--always\")) {\n-\t\t\talways_show_header = 1;\n \t\t\tcontinue;\n \t\t}\n \t\tusage(diff_tree_usage);\n \t}\n \n-\tif (combine_merges)\n-\t\tignore_merges = 0;\n+\tif (opt->combine_merges)\n+\t\topt->ignore_merges = 0;\n \n \t/* We can only do dense combined merges with diff output */\n-\tif (dense_combined_merges)\n-\t\tdiff_options.output_format = DIFF_FORMAT_PATCH;\n+\tif (opt->dense_combined_merges)\n+\t\topt->diffopt.output_format = DIFF_FORMAT_PATCH;\n \n-\tif (diff_options.output_format == DIFF_FORMAT_PATCH)\n-\t\tdiff_options.recursive = 1;\n+\tif (opt->diffopt.output_format == DIFF_FORMAT_PATCH)\n+\t\topt->diffopt.recursive = 1;\n \n \tdiff_tree_setup_paths(get_pathspec(prefix, argv));\n-\tdiff_setup_done(&diff_options);\n+\tdiff_setup_done(&opt->diffopt);\n \n \tswitch (nr_sha1) {\n \tcase 0:\n@@ -311,15 +132,16 @@ int main(int argc, const char **argv)\n \t\tdiff_tree_commit_sha1(sha1[0]);\n \t\tbreak;\n \tcase 2:\n-\t\tdiff_tree_sha1_top(sha1[0], sha1[1], \"\");\n+\t\tdiff_tree_sha1(sha1[0], sha1[1], \"\", &opt->diffopt);\n+\t\tlog_tree_diff_flush(opt);\n \t\tbreak;\n \t}\n \n \tif (!read_stdin)\n \t\treturn 0;\n \n-\tif (diff_options.detect_rename)\n-\t\tdiff_options.setup |= (DIFF_SETUP_USE_SIZE_CACHE |\n+\tif (opt->diffopt.detect_rename)\n+\t\topt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |\n \t\t\t\t       DIFF_SETUP_USE_CACHE);\n \twhile (fgets(line, sizeof(line), stdin))\n \t\tdiff_tree_stdin(line);\ndiff --git a/log-tree.c b/log-tree.c\nnew file mode 100644\nindex 0000000..3d40482\n--- /dev/null\n+++ b/log-tree.c\n@@ -0,0 +1,175 @@\n+#include \"cache.h\"\n+#include \"diff.h\"\n+#include \"commit.h\"\n+#include \"log-tree.h\"\n+\n+void init_log_tree_opt(struct log_tree_opt *opt)\n+{\n+\tmemset(opt, 0, sizeof *opt);\n+\topt->ignore_merges = 1;\n+\topt->header_prefix = \"\";\n+\topt->commit_format = CMIT_FMT_RAW;\n+\tdiff_setup(&opt->diffopt);\n+}\n+\n+int log_tree_opt_parse(struct log_tree_opt *opt, const char **av, int ac)\n+{\n+\tconst char *arg;\n+\tint cnt = diff_opt_parse(&opt->diffopt, av, ac);\n+\tif (0 < cnt)\n+\t\treturn cnt;\n+\targ = *av;\n+\tif (!strcmp(arg, \"-r\"))\n+\t\topt->diffopt.recursive = 1;\n+\telse if (!strcmp(arg, \"-t\")) {\n+\t\topt->diffopt.recursive = 1;\n+\t\topt->diffopt.tree_in_recursive = 1;\n+\t}\n+\telse if (!strcmp(arg, \"-m\"))\n+\t\topt->ignore_merges = 0;\n+\telse if (!strcmp(arg, \"-c\"))\n+\t\topt->combine_merges = 1;\n+\telse if (!strcmp(arg, \"--cc\")) {\n+\t\topt->dense_combined_merges = 1;\n+\t\topt->combine_merges = 1;\n+\t}\n+\telse if (!strcmp(arg, \"-v\")) {\n+\t\topt->verbose_header = 1;\n+\t\topt->header_prefix = \"diff-tree \";\n+\t}\n+\telse if (!strncmp(arg, \"--pretty\", 8)) {\n+\t\topt->verbose_header = 1;\n+\t\topt->header_prefix = \"diff-tree \";\n+\t\topt->commit_format = get_commit_format(arg+8);\n+\t}\n+\telse if (!strcmp(arg, \"--root\"))\n+\t\topt->show_root_diff = 1;\n+\telse if (!strcmp(arg, \"--no-commit-id\"))\n+\t\topt->no_commit_id = 1;\n+\telse if (!strcmp(arg, \"--always\"))\n+\t\topt->always_show_header = 1;\n+\telse\n+\t\treturn 0;\n+\treturn 1;\n+}\n+\n+int log_tree_diff_flush(struct log_tree_opt *opt)\n+{\n+\tdiffcore_std(&opt->diffopt);\n+\tif (diff_queue_is_empty()) {\n+\t\tint saved_fmt = opt->diffopt.output_format;\n+\t\topt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;\n+\t\tdiff_flush(&opt->diffopt);\n+\t\topt->diffopt.output_format = saved_fmt;\n+\t\treturn 0;\n+\t}\n+\tif (opt->header) {\n+\t\tif (!opt->no_commit_id)\n+\t\t\tprintf(\"%s%c\", opt->header,\n+\t\t\t       opt->diffopt.line_termination);\n+\t\topt->header = NULL;\n+\t}\n+\tdiff_flush(&opt->diffopt);\n+\treturn 1;\n+}\n+\n+static int diff_root_tree(struct log_tree_opt *opt,\n+\t\t\t  const unsigned char *new, const char *base)\n+{\n+\tint retval;\n+\tvoid *tree;\n+\tstruct tree_desc empty, real;\n+\n+\ttree = read_object_with_reference(new, tree_type, &real.size, NULL);\n+\tif (!tree)\n+\t\tdie(\"unable to read root tree (%s)\", sha1_to_hex(new));\n+\treal.buf = tree;\n+\n+\tempty.buf = \"\";\n+\tempty.size = 0;\n+\tretval = diff_tree(&empty, &real, base, &opt->diffopt);\n+\tfree(tree);\n+\tlog_tree_diff_flush(opt);\n+\treturn retval;\n+}\n+\n+static const char *generate_header(struct log_tree_opt *opt,\n+\t\t\t\t   const unsigned char *commit_sha1,\n+\t\t\t\t   const unsigned char *parent_sha1,\n+\t\t\t\t   const struct commit *commit)\n+{\n+\tstatic char this_header[16384];\n+\tint offset;\n+\tunsigned long len;\n+\tint abbrev = opt->diffopt.abbrev;\n+\tconst char *msg = commit->buffer;\n+\n+\tif (!opt->verbose_header)\n+\t\treturn sha1_to_hex(commit_sha1);\n+\n+\tlen = strlen(msg);\n+\n+\toffset = sprintf(this_header, \"%s%s \",\n+\t\t\t opt->header_prefix,\n+\t\t\t diff_unique_abbrev(commit_sha1, abbrev));\n+\tif (commit_sha1 != parent_sha1)\n+\t\toffset += sprintf(this_header + offset, \"(from %s)\\n\",\n+\t\t\t\t  parent_sha1\n+\t\t\t\t  ? diff_unique_abbrev(parent_sha1, abbrev)\n+\t\t\t\t  : \"root\");\n+\telse\n+\t\toffset += sprintf(this_header + offset, \"(from parents)\\n\");\n+\toffset += pretty_print_commit(opt->commit_format, commit, len,\n+\t\t\t\t      this_header + offset,\n+\t\t\t\t      sizeof(this_header) - offset, abbrev);\n+\tif (opt->always_show_header) {\n+\t\tputs(this_header);\n+\t\treturn NULL;\n+\t}\n+\treturn this_header;\n+}\n+\n+static int do_diff_combined(struct log_tree_opt *opt, struct commit *commit)\n+{\n+\tunsigned const char *sha1 = commit->object.sha1;\n+\n+\topt->header = generate_header(opt, sha1, sha1, commit);\n+\topt->header = diff_tree_combined_merge(sha1, opt->header,\n+\t\t\t\t\t\topt->dense_combined_merges,\n+\t\t\t\t\t\t&opt->diffopt);\n+\tif (!opt->header && opt->verbose_header)\n+\t\topt->header_prefix = \"\\ndiff-tree \";\n+\treturn 0;\n+}\n+\n+int log_tree_commit(struct log_tree_opt *opt, struct commit *commit)\n+{\n+\tstruct commit_list *parents;\n+\tunsigned const char *sha1 = commit->object.sha1;\n+\n+\t/* Root commit? */\n+\tif (opt->show_root_diff && !commit->parents) {\n+\t\topt->header = generate_header(opt, sha1, NULL, commit);\n+\t\tdiff_root_tree(opt, sha1, \"\");\n+\t}\n+\n+\t/* More than one parent? */\n+\tif (commit->parents && commit->parents->next) {\n+\t\tif (opt->ignore_merges)\n+\t\t\treturn 0;\n+\t\telse if (opt->combine_merges)\n+\t\t\treturn do_diff_combined(opt, commit);\n+\t}\n+\n+\tfor (parents = commit->parents; parents; parents = parents->next) {\n+\t\tstruct commit *parent = parents->item;\n+\t\tunsigned const char *psha1 = parent->object.sha1;\n+\t\topt->header = generate_header(opt, sha1, psha1, commit);\n+\t\tdiff_tree_sha1(psha1, sha1, \"\", &opt->diffopt);\n+\t\tlog_tree_diff_flush(opt);\t\t\n+\n+\t\tif (!opt->header && opt->verbose_header)\n+\t\t\topt->header_prefix = \"\\ndiff-tree \";\n+\t}\n+\treturn 0;\n+}\ndiff --git a/log-tree.h b/log-tree.h\nnew file mode 100644\nindex 0000000..da166c6\n--- /dev/null\n+++ b/log-tree.h\n@@ -0,0 +1,23 @@\n+#ifndef LOG_TREE_H\n+#define LOG_TREE_H\n+\n+struct log_tree_opt {\n+\tstruct diff_options diffopt;\n+\tint show_root_diff;\n+\tint no_commit_id;\n+\tint verbose_header;\n+\tint ignore_merges;\n+\tint combine_merges;\n+\tint dense_combined_merges;\n+\tint always_show_header;\n+\tconst char *header_prefix;\n+\tconst char *header;\n+\tenum cmit_fmt commit_format;\n+};\n+\n+void init_log_tree_opt(struct log_tree_opt *);\n+int log_tree_diff_flush(struct log_tree_opt *);\n+int log_tree_commit(struct log_tree_opt *, struct commit *);\n+int log_tree_opt_parse(struct log_tree_opt *, const char **, int);\n+\n+#endif\n-- \n1.2.6.gad0b\n"}]}