{"thread":{"id":"22911","subject":"[PATCH RESEND] git diff --submodule: Show detailed dirty status of submodules","startedAt":"2010-03-04T21:20:33Z","lastAt":"2010-03-04T21:20:33Z","messageCount":1,"participants":["Jens Lehmann"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"136171","messageId":"4B902421.9090402@web.de","threadId":"22911","inReplyTo":null,"subject":"[PATCH RESEND] git diff --submodule: Show detailed dirty status of submodules","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-03-04T21:20:33Z","receivedAt":"2010-03-04T21:20:33Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"When encountering a dirty submodule while doing \"git diff --submodule\"\nprint an extra line for new untracked content and another for modified\nbut already tracked content. And if the HEAD of the submodule is equal\nto the ref diffed against in the superproject, drop the output which\nwould just show the same SHA1s and no commit message headlines.\n\nTo achieve that, the dirty_submodule bitfield is expanded to two bits.\nThe output of \"git status\" inside the submodule is parsed to set the\naccording bits.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\n\nAs i didn't receive any responses two weeks ago, here is a resend.\n\n\n diff-lib.c                |   16 ++++++++--------\n diffcore.h                |    4 +++-\n submodule.c               |   40 +++++++++++++++++++++++++++++++++++-----\n submodule.h               |    2 +-\n t/t4041-diff-submodule.sh |   17 +++++++++++------\n 5 files changed, 58 insertions(+), 21 deletions(-)\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex d7e13cb..15ca7cd 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -180,10 +180,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\tchanged = ce_match_stat(ce, &st, ce_option);\n \t\tif (S_ISGITLINK(ce->ce_mode)\n \t\t    && !DIFF_OPT_TST(&revs->diffopt, IGNORE_SUBMODULES)\n-\t\t    && (!changed || (revs->diffopt.output_format & DIFF_FORMAT_PATCH))\n-\t\t    && is_submodule_modified(ce->name)) {\n-\t\t\tchanged = 1;\n-\t\t\tdirty_submodule = 1;\n+\t\t    && (!changed || (revs->diffopt.output_format & DIFF_FORMAT_PATCH))) {\n+\t\t\tdirty_submodule = is_submodule_modified(ce->name);\n+\t\t\tif (dirty_submodule)\n+\t\t\t\tchanged = 1;\n \t\t}\n \t\tif (!changed) {\n \t\t\tce_mark_uptodate(ce);\n@@ -243,10 +243,10 @@ static int get_stat_data(struct cache_entry *ce,\n \t\tchanged = ce_match_stat(ce, &st, 0);\n \t\tif (S_ISGITLINK(ce->ce_mode)\n \t\t    && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)\n-\t\t    && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH))\n-\t\t    && is_submodule_modified(ce->name)) {\n-\t\t\tchanged = 1;\n-\t\t\t*dirty_submodule = 1;\n+\t\t    && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH))) {\n+\t\t\t*dirty_submodule = is_submodule_modified(ce->name);\n+\t\t\tif (*dirty_submodule)\n+\t\t\t\tchanged = 1;\n \t\t}\n \t\tif (changed) {\n \t\t\tmode = ce_mode_from_stat(ce, st.st_mode);\ndiff --git a/diffcore.h b/diffcore.h\nindex 66687c3..fcd00bf 100644\n--- a/diffcore.h\n+++ b/diffcore.h\n@@ -42,7 +42,9 @@ struct diff_filespec {\n #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)\n \tunsigned should_free : 1; /* data should be free()'ed */\n \tunsigned should_munmap : 1; /* data should be munmap()'ed */\n-\tunsigned dirty_submodule : 1;  /* For submodules: its work tree is dirty */\n+\tunsigned dirty_submodule : 2;  /* For submodules: its work tree is dirty */\n+#define DIRTY_SUBMODULE_UNTRACKED 1\n+#define DIRTY_SUBMODULE_MODIFIED  2\n\n \tstruct userdiff_driver *driver;\n \t/* data should be considered \"binary\"; -1 means \"don't know yet\" */\ndiff --git a/submodule.c b/submodule.c\nindex 5d286e4..714ca97 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -5,6 +5,7 @@\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"run-command.h\"\n+#include \"diffcore.h\"\n\n static int add_submodule_odb(const char *path)\n {\n@@ -85,13 +86,21 @@ void show_submodule_summary(FILE *f, const char *path,\n \t\t\tmessage = \"(revision walker failed)\";\n \t}\n\n+\tif (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n+\t\tfprintf(f, \"Submodule %s contains untracked content\\n\", path);\n+\tif (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n+\t\tfprintf(f, \"Submodule %s contains modified content\\n\", path);\n+\n+\tif (!hashcmp(one, two)) {\n+\t\tstrbuf_release(&sb);\n+\t\treturn;\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 (dirty_submodule)\n-\t\tstrbuf_add(&sb, \"-dirty\", 6);\n \tif (message)\n \t\tstrbuf_addf(&sb, \" %s\\n\", message);\n \telse\n@@ -121,9 +130,10 @@ void show_submodule_summary(FILE *f, const char *path,\n \tstrbuf_release(&sb);\n }\n\n-int is_submodule_modified(const char *path)\n+unsigned is_submodule_modified(const char *path)\n {\n-\tint len, i;\n+\tint i;\n+\tssize_t len;\n \tstruct child_process cp;\n \tconst char *argv[] = {\n \t\t\"status\",\n@@ -132,6 +142,8 @@ int is_submodule_modified(const char *path)\n \t};\n \tconst char *env[LOCAL_REPO_ENV_SIZE + 3];\n \tstruct strbuf buf = STRBUF_INIT;\n+\tunsigned dirty_submodule = 0;\n+\tconst char *line, *next_line;\n\n \tfor (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)\n \t\tenv[i] = local_repo_env[i];\n@@ -161,6 +173,24 @@ int is_submodule_modified(const char *path)\n \t\tdie(\"Could not run git status --porcelain\");\n\n \tlen = strbuf_read(&buf, cp.out, 1024);\n+\tline = buf.buf;\n+\twhile (len > 2) {\n+\t\tif ((line[0] == '?') && (line[1] == '?')) {\n+\t\t\tdirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;\n+\t\t\tif (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)\n+\t\t\t\tbreak;\n+\t\t} else {\n+\t\t\tdirty_submodule |= DIRTY_SUBMODULE_MODIFIED;\n+\t\t\tif (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\tnext_line = strchr(line, '\\n');\n+\t\tif (!next_line)\n+\t\t\tbreak;\n+\t\tnext_line++;\n+\t\tlen -= (next_line - line);\n+\t\tline = next_line;\n+\t}\n \tclose(cp.out);\n\n \tif (finish_command(&cp))\n@@ -169,5 +199,5 @@ int is_submodule_modified(const char *path)\n \tfor (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)\n \t\tfree((char *)env[i]);\n \tstrbuf_release(&buf);\n-\treturn len != 0;\n+\treturn dirty_submodule;\n }\ndiff --git a/submodule.h b/submodule.h\nindex 2336965..267881c 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -5,6 +5,6 @@ void show_submodule_summary(FILE *f, const char *path,\n \t\tunsigned char one[20], unsigned char two[20],\n \t\tunsigned dirty_submodule,\n \t\tconst char *del, const char *add, const char *reset);\n-int is_submodule_modified(const char *path);\n+unsigned is_submodule_modified(const char *path);\n\n #endif\ndiff --git a/t/t4041-diff-submodule.sh b/t/t4041-diff-submodule.sh\nindex 4643054..11b1997 100755\n--- a/t/t4041-diff-submodule.sh\n+++ b/t/t4041-diff-submodule.sh\n@@ -201,7 +201,7 @@ test_expect_success 'submodule contains untracked content' \"\n \techo new > sm1/new-file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tdiff actual - <<-EOF\n-Submodule sm1 $head6..$head6-dirty:\n+Submodule sm1 contains untracked content\n EOF\n \"\n\n@@ -209,7 +209,8 @@ test_expect_success 'submodule contains untracked and modifed content' \"\n \techo new > sm1/foo6 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tdiff actual - <<-EOF\n-Submodule sm1 $head6..$head6-dirty:\n+Submodule sm1 contains untracked content\n+Submodule sm1 contains modified content\n EOF\n \"\n\n@@ -217,7 +218,7 @@ test_expect_success 'submodule contains modifed content' \"\n \trm -f sm1/new-file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tdiff actual - <<-EOF\n-Submodule sm1 $head6..$head6-dirty:\n+Submodule sm1 contains modified content\n EOF\n \"\n\n@@ -235,7 +236,8 @@ test_expect_success 'modified submodule contains untracked content' \"\n \techo new > sm1/new-file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tdiff actual - <<-EOF\n-Submodule sm1 $head6..$head8-dirty:\n+Submodule sm1 contains untracked content\n+Submodule sm1 $head6..$head8:\n   > change\n EOF\n \"\n@@ -244,7 +246,9 @@ test_expect_success 'modified submodule contains untracked and modifed content'\n \techo modification >> sm1/foo6 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tdiff actual - <<-EOF\n-Submodule sm1 $head6..$head8-dirty:\n+Submodule sm1 contains untracked content\n+Submodule sm1 contains modified content\n+Submodule sm1 $head6..$head8:\n   > change\n EOF\n \"\n@@ -253,7 +257,8 @@ test_expect_success 'modified submodule contains modifed content' \"\n \trm -f sm1/new-file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tdiff actual - <<-EOF\n-Submodule sm1 $head6..$head8-dirty:\n+Submodule sm1 contains modified content\n+Submodule sm1 $head6..$head8:\n   > change\n EOF\n \"\n-- \n1.7.0.1.335.g17865.dirty\n"}]}