{"thread":{"id":"21268","subject":"[PATCH] Add the --submodule option to the diff option family","startedAt":"2009-10-17T18:46:20Z","lastAt":"2009-10-19T12:38:32Z","messageCount":4,"participants":["Jens Lehmann","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"125255","messageId":"4ADA10FC.40708@web.de","threadId":"21268","inReplyTo":null,"subject":"[PATCH] Add the --submodule option to the diff option family","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2009-10-17T18:46:20Z","receivedAt":"2009-10-17T18:46:20Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"When you use the option --submodule=left-right-log you can see the submodule\nsummaries inlined in the diff, instead of not-quite-helpful SHA-1 pairs.\n\nThe format imitates what \"git submodule summary\" shows.\n\nTo do that, <path>/.git/objects/ is added to the alternate object\ndatabases (if that directory exists).\n\nThis option was requested by Jens Lehmann at the GitTogether in Berlin.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nIn this patch i tried to address all the issues mentioned so far, please\nlet me know if anything is missing.\n\n\n Documentation/diff-options.txt |    7 +++\n Makefile                       |    2 +\n diff.c                         |   16 ++++++\n diff.h                         |    1 +\n submodule.c                    |  112 ++++++++++++++++++++++++++++++++++++++++\n submodule.h                    |    8 +++\n 6 files changed, 146 insertions(+), 0 deletions(-)\n create mode 100644 submodule.c\n create mode 100644 submodule.h\n\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 9276fae..99cb517 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -87,6 +87,13 @@ endif::git-format-patch[]\n \tShow only names and status of changed files. See the description\n \tof the `--diff-filter` option on what the status letters mean.\n\n+--submodule[=<format>]::\n+\tChose the output format for submodule differences. <format> can be one of\n+\t'short' and 'left-right-log'. 'short' is the default value for this\n+\toption and and shows pairs of commit names. 'left-right-log' lists the\n+\tcommits in that commit range like the 'summary' option of\n+\tlinkgit:git-submodule[1] does.\n+\n --color::\n \tShow colored diff.\n\ndiff --git a/Makefile b/Makefile\nindex c0eff64..2f61e17 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -453,6 +453,7 @@ LIB_H += sideband.h\n LIB_H += sigchain.h\n LIB_H += strbuf.h\n LIB_H += string-list.h\n+LIB_H += submodule.h\n LIB_H += tag.h\n LIB_H += transport.h\n LIB_H += tree.h\n@@ -551,6 +552,7 @@ LIB_OBJS += sideband.o\n LIB_OBJS += sigchain.o\n LIB_OBJS += strbuf.o\n LIB_OBJS += string-list.o\n+LIB_OBJS += submodule.o\n LIB_OBJS += symlinks.o\n LIB_OBJS += tag.o\n LIB_OBJS += trace.o\ndiff --git a/diff.c b/diff.c\nindex c719ce2..8af1ae2 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -13,6 +13,7 @@\n #include \"utf8.h\"\n #include \"userdiff.h\"\n #include \"sigchain.h\"\n+#include \"submodule.h\"\n\n #ifdef NO_FAST_WORKING_DIRECTORY\n #define FAST_WORKING_DIRECTORY 0\n@@ -1557,6 +1558,17 @@ static void builtin_diff(const char *name_a,\n \tconst char *a_prefix, *b_prefix;\n \tconst char *textconv_one = NULL, *textconv_two = NULL;\n\n+\tif (DIFF_OPT_TST(o, SUBMODULE_LEFT_RIGHT_LOG) &&\n+\t\t\t(!one->mode || S_ISGITLINK(one->mode)) &&\n+\t\t\t(!two->mode || S_ISGITLINK(two->mode))) {\n+\t\tconst char *del = diff_get_color_opt(o, DIFF_FILE_OLD);\n+\t\tconst char *add = diff_get_color_opt(o, DIFF_FILE_NEW);\n+\t\tshow_submodule_summary(o->file, one ? one->path : two->path,\n+\t\t\t\tone->sha1, two->sha1,\n+\t\t\t\tdel, add, reset);\n+\t\treturn;\n+\t}\n+\n \tif (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {\n \t\ttextconv_one = get_textconv(one);\n \t\ttextconv_two = get_textconv(two);\n@@ -2771,6 +2783,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n \t\tDIFF_OPT_CLR(options, ALLOW_TEXTCONV);\n \telse if (!strcmp(arg, \"--ignore-submodules\"))\n \t\tDIFF_OPT_SET(options, IGNORE_SUBMODULES);\n+\telse if (!prefixcmp(arg, \"--submodule=\")) {\n+\t\tif (!strcmp(arg + 12, \"left-right-log\"))\n+\t\t\tDIFF_OPT_SET(options, SUBMODULE_LEFT_RIGHT_LOG);\n+\t}\n\n \t/* misc options */\n \telse if (!strcmp(arg, \"-z\"))\ndiff --git a/diff.h b/diff.h\nindex a7e7ccb..8079f5b 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -67,6 +67,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,\n #define DIFF_OPT_DIRSTAT_BY_FILE     (1 << 20)\n #define DIFF_OPT_ALLOW_TEXTCONV      (1 << 21)\n #define DIFF_OPT_DIFF_FROM_CONTENTS  (1 << 22)\n+#define DIFF_OPT_SUBMODULE_LEFT_RIGHT_LOG (1 << 23)\n #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)\n #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)\n #define DIFF_OPT_CLR(opts, flag)    ((opts)->flags &= ~DIFF_OPT_##flag)\ndiff --git a/submodule.c b/submodule.c\nnew file mode 100644\nindex 0000000..206386f\n--- /dev/null\n+++ b/submodule.c\n@@ -0,0 +1,112 @@\n+#include \"cache.h\"\n+#include \"submodule.h\"\n+#include \"dir.h\"\n+#include \"diff.h\"\n+#include \"commit.h\"\n+#include \"revision.h\"\n+\n+int add_submodule_odb(const char *path)\n+{\n+\tstruct strbuf objects_directory = STRBUF_INIT;\n+\tstruct alternate_object_database *alt_odb;\n+\n+\tstrbuf_addf(&objects_directory, \"%s/.git/objects/\", path);\n+\tif (!is_directory(objects_directory.buf))\n+\t\treturn -1;\n+\n+\t/* avoid adding it twice */\n+\tfor (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)\n+\t\tif (alt_odb->name - alt_odb->base == objects_directory.len &&\n+\t\t\t\t!strncmp(alt_odb->base, objects_directory.buf,\n+\t\t\t\t\tobjects_directory.len))\n+\t\t\treturn 0;\n+\n+\talt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));\n+\talt_odb->next = alt_odb_list;\n+\tstrcpy(alt_odb->base, objects_directory.buf);\n+\talt_odb->name = alt_odb->base + objects_directory.len;\n+\talt_odb->name[2] = '/';\n+\talt_odb->name[40] = '\\0';\n+\talt_odb->name[41] = '\\0';\n+\talt_odb_list = alt_odb;\n+\tprepare_alt_odb();\n+\treturn 0;\n+}\n+\n+void show_submodule_summary(FILE *f, const char *path,\n+\t\tunsigned char one[20], unsigned char two[20],\n+\t\tconst char *del, const char *add, const char *reset)\n+{\n+\tstruct rev_info rev;\n+\tstruct commit *commit, *left = left, *right;\n+\tstruct commit_list *merge_bases, *list;\n+\tconst char *message = NULL;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstatic const char *format = \"  %m %s\";\n+\tint fast_forward = 0, fast_backward = 0;\n+\n+\tif (is_null_sha1(two))\n+\t\tmessage = \"(submodule deleted)\";\n+\telse if (add_submodule_odb(path))\n+\t\tmessage = \"(not checked out)\";\n+\telse if (is_null_sha1(one))\n+\t\tmessage = \"(new submodule)\";\n+\telse if (!(left = lookup_commit_reference(one)) ||\n+\t\t !(right = lookup_commit_reference(two)))\n+\t\tmessage = \"(commits not present)\";\n+\n+\tif (!message) {\n+\t\tinit_revisions(&rev, NULL);\n+\t\tsetup_revisions(0, NULL, &rev, NULL);\n+\t\trev.left_right = 1;\n+\t\trev.first_parent_only = 1;\n+\t\tleft->object.flags |= SYMMETRIC_LEFT;\n+\t\tadd_pending_object(&rev, &left->object, path);\n+\t\tadd_pending_object(&rev, &right->object, path);\n+\t\tmerge_bases = get_merge_bases(left, right, 1);\n+\t\tif (merge_bases) {\n+\t\t\tif (merge_bases->item == left)\n+\t\t\t\tfast_forward = 1;\n+\t\t\telse if (merge_bases->item == right)\n+\t\t\t\tfast_backward = 1;\n+\t\t}\n+\t\tfor (list = merge_bases; list; list = list->next) {\n+\t\t\tlist->item->object.flags |= UNINTERESTING;\n+\t\t\tadd_pending_object(&rev, &list->item->object,\n+\t\t\t\tsha1_to_hex(list->item->object.sha1));\n+\t\t}\n+\t\tif (prepare_revision_walk(&rev))\n+\t\t\tmessage = \"(revision walker failed)\";\n+\t}\n+\n+\tstrbuf_addf(&sb, \"Submodule %s %s..\", path,\n+\t\t\tfind_unique_abbrev(one, DEFAULT_ABBREV));\n+\tif (!fast_backward && !fast_forward)\n+\t\tstrbuf_addch(&sb, '.');\n+\tstrbuf_addf(&sb, \"%s\", find_unique_abbrev(two, DEFAULT_ABBREV));\n+\tif (message)\n+\t\tstrbuf_addf(&sb, \" %s\\n\", message);\n+\telse\n+\t\tstrbuf_addf(&sb, \"%s:\\n\", fast_backward ? \" (rewind)\" : \"\");\n+\tfwrite(sb.buf, sb.len, 1, f);\n+\n+\tif (!message) {\n+\t\twhile ((commit = get_revision(&rev))) {\n+\t\t\tstrbuf_setlen(&sb, 0);\n+\t\t\tif (commit->object.flags & SYMMETRIC_LEFT) {\n+\t\t\t\tif (del)\n+\t\t\t\t\tstrbuf_addstr(&sb, del);\n+\t\t\t}\n+\t\t\telse if (add)\n+\t\t\t\tstrbuf_addstr(&sb, add);\n+\t\t\tformat_commit_message(commit, format, &sb,\n+\t\t\t\t\trev.date_mode);\n+\t\t\tif (reset)\n+\t\t\t\tstrbuf_addstr(&sb, reset);\n+\t\t\tstrbuf_addch(&sb, '\\n');\n+\t\t\tfprintf(f, \"%s\", sb.buf);\n+\t\t}\n+\t\tclear_commit_marks(left, ~0);\n+\t\tclear_commit_marks(right, ~0);\n+\t}\n+}\ndiff --git a/submodule.h b/submodule.h\nnew file mode 100644\nindex 0000000..4c0269d\n--- /dev/null\n+++ b/submodule.h\n@@ -0,0 +1,8 @@\n+#ifndef SUBMODULE_H\n+#define SUBMODULE_H\n+\n+void show_submodule_summary(FILE *f, const char *path,\n+\t\tunsigned char one[20], unsigned char two[20],\n+\t\tconst char *del, const char *add, const char *reset);\n+\n+#endif\n-- \n1.6.5.3.g464e1.dirty\n"},{"id":"125322","messageId":"7v3a5gdr1c.fsf@alter.siamese.dyndns.org","threadId":"21268","inReplyTo":"4ADA10FC.40708@web.de","subject":"Re: [PATCH] Add the --submodule option to the diff option family","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-10-19T03:02:55Z","receivedAt":"2009-10-19T03:02:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> When you use the option --submodule=left-right-log you can see the submodule\n> summaries inlined in the diff, instead of not-quite-helpful SHA-1 pairs.\n>\n> The format imitates what \"git submodule summary\" shows.\n>\n> To do that, <path>/.git/objects/ is added to the alternate object\n> databases (if that directory exists).\n>\n> This option was requested by Jens Lehmann at the GitTogether in Berlin.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n> ---\n\nThanks.\n\nI have four patches queued on js/diff-verbose-submodule topic and I think\nthis corresponds to the first three, correct?\n\n> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\n> index 9276fae..99cb517 100644\n> --- a/Documentation/diff-options.txt\n> +++ b/Documentation/diff-options.txt\n> @@ -87,6 +87,13 @@ endif::git-format-patch[]\n>  \tShow only names and status of changed files. See the description\n>  \tof the `--diff-filter` option on what the status letters mean.\n>\n> +--submodule[=<format>]::\n> +\tChose the output format for submodule differences. <format> can be one of\n> +\t'short' and 'left-right-log'. 'short' is the default value for this\n> +\toption and and shows pairs of commit names. 'left-right-log' lists the\n> +\tcommits in that commit range like the 'summary' option of\n> +\tlinkgit:git-submodule[1] does.\n> +\n\nWell, while left-right-log may be logically the most correct name for this\noption, I think it is too long to be practical.  Because it is not like we\nwould want to have an option to have full log there when we are showing\n\"diff\", I think it would make sense to making left-right-log the default\nwhen \"--submodule\" (without format specification) is given, and possibly\ngive \"--submodule=log\" as the synonym for this format.\n\nAfter all, if you do not give --submodule, we will give the traditional\nshort format, no?\n\n> diff --git a/diff.c b/diff.c\n> index c719ce2..8af1ae2 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -2771,6 +2783,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n>  \t\tDIFF_OPT_CLR(options, ALLOW_TEXTCONV);\n>  \telse if (!strcmp(arg, \"--ignore-submodules\"))\n>  \t\tDIFF_OPT_SET(options, IGNORE_SUBMODULES);\n> +\telse if (!prefixcmp(arg, \"--submodule=\")) {\n> +\t\tif (!strcmp(arg + 12, \"left-right-log\"))\n> +\t\t\tDIFF_OPT_SET(options, SUBMODULE_LEFT_RIGHT_LOG);\n> +\t}\n\nI do not see --submodule (without \"=<format>\") supported here as the\ndocumentation claims, but this is the logical place to do so.\n\n> diff --git a/submodule.c b/submodule.c\n> new file mode 100644\n> index 0000000..206386f\n> --- /dev/null\n> +++ b/submodule.c\n> @@ -0,0 +1,112 @@\n> +...\n> +void show_submodule_summary(FILE *f, const char *path,\n> +\t\tunsigned char one[20], unsigned char two[20],\n> +\t\tconst char *del, const char *add, const char *reset)\n> +{\n> ...\n> +\tfwrite(sb.buf, sb.len, 1, f);\n> +\n> +\tif (!message) {\n> +\t\twhile ((commit = get_revision(&rev))) {\n> + ...\n> +\t\t}\n> +\t\tclear_commit_marks(left, ~0);\n> +\t\tclear_commit_marks(right, ~0);\n> +\t}\n> +}\n\nI thought we had strbuf_release(&sb) here...  Where did it go?\n"},{"id":"125376","messageId":"4ADC5BB7.5090207@web.de","threadId":"21268","inReplyTo":"7v3a5gdr1c.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Add the --submodule option to the diff option family","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2009-10-19T12:29:43Z","receivedAt":"2009-10-19T12:29:43Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Junio C Hamano schrieb:\n> I have four patches queued on js/diff-verbose-submodule topic and I think\n> this corresponds to the first three, correct?\n\nYes.\n\n\n>> +--submodule[=<format>]::\n>> +\tChose the output format for submodule differences. <format> can be one of\n>> +\t'short' and 'left-right-log'. 'short' is the default value for this\n>> +\toption and and shows pairs of commit names. 'left-right-log' lists the\n>> +\tcommits in that commit range like the 'summary' option of\n>> +\tlinkgit:git-submodule[1] does.\n>> +\n> \n> Well, while left-right-log may be logically the most correct name for this\n> option, I think it is too long to be practical.  Because it is not like we\n> would want to have an option to have full log there when we are showing\n> \"diff\", I think it would make sense to making left-right-log the default\n> when \"--submodule\" (without format specification) is given, and possibly\n> give \"--submodule=log\" as the synonym for this format.\n\nO.k., \"--submodule=log\" it is.\n\n\n> After all, if you do not give --submodule, we will give the traditional\n> short format, no?\n\nYes. Will make the documentation clearer on this.\n\n\n>> diff --git a/diff.c b/diff.c\n>> index c719ce2..8af1ae2 100644\n>> --- a/diff.c\n>> +++ b/diff.c\n>> @@ -2771,6 +2783,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n>>  \t\tDIFF_OPT_CLR(options, ALLOW_TEXTCONV);\n>>  \telse if (!strcmp(arg, \"--ignore-submodules\"))\n>>  \t\tDIFF_OPT_SET(options, IGNORE_SUBMODULES);\n>> +\telse if (!prefixcmp(arg, \"--submodule=\")) {\n>> +\t\tif (!strcmp(arg + 12, \"left-right-log\"))\n>> +\t\t\tDIFF_OPT_SET(options, SUBMODULE_LEFT_RIGHT_LOG);\n>> +\t}\n> \n> I do not see --submodule (without \"=<format>\") supported here as the\n> documentation claims, but this is the logical place to do so.\n\nWill change that.\n\n\n>> diff --git a/submodule.c b/submodule.c\n>> new file mode 100644\n>> index 0000000..206386f\n>> --- /dev/null\n>> +++ b/submodule.c\n>> @@ -0,0 +1,112 @@\n>> +...\n>> +void show_submodule_summary(FILE *f, const char *path,\n>> +\t\tunsigned char one[20], unsigned char two[20],\n>> +\t\tconst char *del, const char *add, const char *reset)\n>> +{\n>> ...\n>> +\tfwrite(sb.buf, sb.len, 1, f);\n>> +\n>> +\tif (!message) {\n>> +\t\twhile ((commit = get_revision(&rev))) {\n>> + ...\n>> +\t\t}\n>> +\t\tclear_commit_marks(left, ~0);\n>> +\t\tclear_commit_marks(right, ~0);\n>> +\t}\n>> +}\n> \n> I thought we had strbuf_release(&sb) here...  Where did it go?\n\n*blush* ... thanks for catching this, will put it back where it belongs.\n"},{"id":"125377","messageId":"4ADC5DC8.7040508@web.de","threadId":"21268","inReplyTo":"4ADC5BB7.5090207@web.de","subject":"[PATCH v2] Add the --submodule option to the diff option family","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2009-10-19T12:38:32Z","receivedAt":"2009-10-19T12:38:32Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"When you use the option --submodule=log you can see the submodule\nsummaries inlined in the diff, instead of not-quite-helpful SHA-1 pairs.\n\nThe format imitates what \"git submodule summary\" shows.\n\nTo do that, <path>/.git/objects/ is added to the alternate object\ndatabases (if that directory exists).\n\nThis option was requested by Jens Lehmann at the GitTogether in Berlin.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\nChanges since v1:\n- Changed the option name from \"left-right-log\" to \"log\"\n- Handling \"--submodule\"-option without extra arguments now\n- Re-added a \"strbuf_release(&sb);\" being accidentally dropped\n- Changed the wording in the Documentation\n\n\n Documentation/diff-options.txt |    7 +++\n Makefile                       |    2 +\n diff.c                         |   18 ++++++\n diff.h                         |    1 +\n submodule.c                    |  113 ++++++++++++++++++++++++++++++++++++++++\n submodule.h                    |    8 +++\n 6 files changed, 149 insertions(+), 0 deletions(-)\n create mode 100644 submodule.c\n create mode 100644 submodule.h\n\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 9276fae..e26b847 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -87,6 +87,13 @@ endif::git-format-patch[]\n \tShow only names and status of changed files. See the description\n \tof the `--diff-filter` option on what the status letters mean.\n\n+--submodule[=<format>]::\n+\tChose the output format for submodule differences. <format> can be one of\n+\t'short' and 'log'. 'short' just shows pairs of commit names, this format\n+\tis used when this option is not given. 'log' is the default value for this\n+\toption and lists the commits in that commit range like the 'summary'\n+\toption of linkgit:git-submodule[1] does.\n+\n --color::\n \tShow colored diff.\n\ndiff --git a/Makefile b/Makefile\nindex c0eff64..2f61e17 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -453,6 +453,7 @@ LIB_H += sideband.h\n LIB_H += sigchain.h\n LIB_H += strbuf.h\n LIB_H += string-list.h\n+LIB_H += submodule.h\n LIB_H += tag.h\n LIB_H += transport.h\n LIB_H += tree.h\n@@ -551,6 +552,7 @@ LIB_OBJS += sideband.o\n LIB_OBJS += sigchain.o\n LIB_OBJS += strbuf.o\n LIB_OBJS += string-list.o\n+LIB_OBJS += submodule.o\n LIB_OBJS += symlinks.o\n LIB_OBJS += tag.o\n LIB_OBJS += trace.o\ndiff --git a/diff.c b/diff.c\nindex c719ce2..5fc9f37 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -13,6 +13,7 @@\n #include \"utf8.h\"\n #include \"userdiff.h\"\n #include \"sigchain.h\"\n+#include \"submodule.h\"\n\n #ifdef NO_FAST_WORKING_DIRECTORY\n #define FAST_WORKING_DIRECTORY 0\n@@ -1557,6 +1558,17 @@ static void builtin_diff(const char *name_a,\n \tconst char *a_prefix, *b_prefix;\n \tconst char *textconv_one = NULL, *textconv_two = NULL;\n\n+\tif (DIFF_OPT_TST(o, SUBMODULE_LEFT_RIGHT_LOG) &&\n+\t\t\t(!one->mode || S_ISGITLINK(one->mode)) &&\n+\t\t\t(!two->mode || S_ISGITLINK(two->mode))) {\n+\t\tconst char *del = diff_get_color_opt(o, DIFF_FILE_OLD);\n+\t\tconst char *add = diff_get_color_opt(o, DIFF_FILE_NEW);\n+\t\tshow_submodule_summary(o->file, one ? one->path : two->path,\n+\t\t\t\tone->sha1, two->sha1,\n+\t\t\t\tdel, add, reset);\n+\t\treturn;\n+\t}\n+\n \tif (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {\n \t\ttextconv_one = get_textconv(one);\n \t\ttextconv_two = get_textconv(two);\n@@ -2771,6 +2783,12 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n \t\tDIFF_OPT_CLR(options, ALLOW_TEXTCONV);\n \telse if (!strcmp(arg, \"--ignore-submodules\"))\n \t\tDIFF_OPT_SET(options, IGNORE_SUBMODULES);\n+\telse if (!strcmp(arg, \"--submodule\"))\n+\t\tDIFF_OPT_SET(options, SUBMODULE_LEFT_RIGHT_LOG);\n+\telse if (!prefixcmp(arg, \"--submodule=\")) {\n+\t\tif (!strcmp(arg + 12, \"log\"))\n+\t\t\tDIFF_OPT_SET(options, SUBMODULE_LEFT_RIGHT_LOG);\n+\t}\n\n \t/* misc options */\n \telse if (!strcmp(arg, \"-z\"))\ndiff --git a/diff.h b/diff.h\nindex a7e7ccb..8079f5b 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -67,6 +67,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,\n #define DIFF_OPT_DIRSTAT_BY_FILE     (1 << 20)\n #define DIFF_OPT_ALLOW_TEXTCONV      (1 << 21)\n #define DIFF_OPT_DIFF_FROM_CONTENTS  (1 << 22)\n+#define DIFF_OPT_SUBMODULE_LEFT_RIGHT_LOG (1 << 23)\n #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)\n #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)\n #define DIFF_OPT_CLR(opts, flag)    ((opts)->flags &= ~DIFF_OPT_##flag)\ndiff --git a/submodule.c b/submodule.c\nnew file mode 100644\nindex 0000000..d5fce7a\n--- /dev/null\n+++ b/submodule.c\n@@ -0,0 +1,113 @@\n+#include \"cache.h\"\n+#include \"submodule.h\"\n+#include \"dir.h\"\n+#include \"diff.h\"\n+#include \"commit.h\"\n+#include \"revision.h\"\n+\n+int add_submodule_odb(const char *path)\n+{\n+\tstruct strbuf objects_directory = STRBUF_INIT;\n+\tstruct alternate_object_database *alt_odb;\n+\n+\tstrbuf_addf(&objects_directory, \"%s/.git/objects/\", path);\n+\tif (!is_directory(objects_directory.buf))\n+\t\treturn -1;\n+\n+\t/* avoid adding it twice */\n+\tfor (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)\n+\t\tif (alt_odb->name - alt_odb->base == objects_directory.len &&\n+\t\t\t\t!strncmp(alt_odb->base, objects_directory.buf,\n+\t\t\t\t\tobjects_directory.len))\n+\t\t\treturn 0;\n+\n+\talt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));\n+\talt_odb->next = alt_odb_list;\n+\tstrcpy(alt_odb->base, objects_directory.buf);\n+\talt_odb->name = alt_odb->base + objects_directory.len;\n+\talt_odb->name[2] = '/';\n+\talt_odb->name[40] = '\\0';\n+\talt_odb->name[41] = '\\0';\n+\talt_odb_list = alt_odb;\n+\tprepare_alt_odb();\n+\treturn 0;\n+}\n+\n+void show_submodule_summary(FILE *f, const char *path,\n+\t\tunsigned char one[20], unsigned char two[20],\n+\t\tconst char *del, const char *add, const char *reset)\n+{\n+\tstruct rev_info rev;\n+\tstruct commit *commit, *left = left, *right;\n+\tstruct commit_list *merge_bases, *list;\n+\tconst char *message = NULL;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstatic const char *format = \"  %m %s\";\n+\tint fast_forward = 0, fast_backward = 0;\n+\n+\tif (is_null_sha1(two))\n+\t\tmessage = \"(submodule deleted)\";\n+\telse if (add_submodule_odb(path))\n+\t\tmessage = \"(not checked out)\";\n+\telse if (is_null_sha1(one))\n+\t\tmessage = \"(new submodule)\";\n+\telse if (!(left = lookup_commit_reference(one)) ||\n+\t\t !(right = lookup_commit_reference(two)))\n+\t\tmessage = \"(commits not present)\";\n+\n+\tif (!message) {\n+\t\tinit_revisions(&rev, NULL);\n+\t\tsetup_revisions(0, NULL, &rev, NULL);\n+\t\trev.left_right = 1;\n+\t\trev.first_parent_only = 1;\n+\t\tleft->object.flags |= SYMMETRIC_LEFT;\n+\t\tadd_pending_object(&rev, &left->object, path);\n+\t\tadd_pending_object(&rev, &right->object, path);\n+\t\tmerge_bases = get_merge_bases(left, right, 1);\n+\t\tif (merge_bases) {\n+\t\t\tif (merge_bases->item == left)\n+\t\t\t\tfast_forward = 1;\n+\t\t\telse if (merge_bases->item == right)\n+\t\t\t\tfast_backward = 1;\n+\t\t}\n+\t\tfor (list = merge_bases; list; list = list->next) {\n+\t\t\tlist->item->object.flags |= UNINTERESTING;\n+\t\t\tadd_pending_object(&rev, &list->item->object,\n+\t\t\t\tsha1_to_hex(list->item->object.sha1));\n+\t\t}\n+\t\tif (prepare_revision_walk(&rev))\n+\t\t\tmessage = \"(revision walker failed)\";\n+\t}\n+\n+\tstrbuf_addf(&sb, \"Submodule %s %s..\", path,\n+\t\t\tfind_unique_abbrev(one, DEFAULT_ABBREV));\n+\tif (!fast_backward && !fast_forward)\n+\t\tstrbuf_addch(&sb, '.');\n+\tstrbuf_addf(&sb, \"%s\", find_unique_abbrev(two, DEFAULT_ABBREV));\n+\tif (message)\n+\t\tstrbuf_addf(&sb, \" %s\\n\", message);\n+\telse\n+\t\tstrbuf_addf(&sb, \"%s:\\n\", fast_backward ? \" (rewind)\" : \"\");\n+\tfwrite(sb.buf, sb.len, 1, f);\n+\n+\tif (!message) {\n+\t\twhile ((commit = get_revision(&rev))) {\n+\t\t\tstrbuf_setlen(&sb, 0);\n+\t\t\tif (commit->object.flags & SYMMETRIC_LEFT) {\n+\t\t\t\tif (del)\n+\t\t\t\t\tstrbuf_addstr(&sb, del);\n+\t\t\t}\n+\t\t\telse if (add)\n+\t\t\t\tstrbuf_addstr(&sb, add);\n+\t\t\tformat_commit_message(commit, format, &sb,\n+\t\t\t\t\trev.date_mode);\n+\t\t\tif (reset)\n+\t\t\t\tstrbuf_addstr(&sb, reset);\n+\t\t\tstrbuf_addch(&sb, '\\n');\n+\t\t\tfprintf(f, \"%s\", sb.buf);\n+\t\t}\n+\t\tclear_commit_marks(left, ~0);\n+\t\tclear_commit_marks(right, ~0);\n+\t}\n+\tstrbuf_release(&sb);\n+}\ndiff --git a/submodule.h b/submodule.h\nnew file mode 100644\nindex 0000000..4c0269d\n--- /dev/null\n+++ b/submodule.h\n@@ -0,0 +1,8 @@\n+#ifndef SUBMODULE_H\n+#define SUBMODULE_H\n+\n+void show_submodule_summary(FILE *f, const char *path,\n+\t\tunsigned char one[20], unsigned char two[20],\n+\t\tconst char *del, const char *add, const char *reset);\n+\n+#endif\n-- \n1.6.5.104.gd732a\n"}]}