{"thread":{"id":"24531","subject":"[PATCH 0/2] Submodules: Add the new config option \"ignore\"","startedAt":"2010-07-26T18:26:07Z","lastAt":"2010-08-09T16:57:08Z","messageCount":15,"participants":["Jens Lehmann","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"146407","messageId":"4C4DD33F.4020104@web.de","threadId":"24531","inReplyTo":null,"subject":"[PATCH 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-07-26T18:26:07Z","receivedAt":"2010-07-26T18:26:07Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"These two patches are extremly useful for those users who chose submodules\nbecause they wanted to reduce the time it takes for \"git status\" and \"git\ndiff\" to recurse through the whole work tree by putting sometimes large\namounts of files into submodules, which weren't scanned in the past.\n\nSince 1.7.0 \"git status\" and \"git diff\" recurse through submodule work\ntrees, which has a - sometimes drastic - performance impact when large\nsubmodules are present. Using the \"ignore=dirty\" config option restores\nthe former behaviour.\n\nThis option can be set in the .gitmodules file or in .git/config, any\nsettings found in the latter override those from .gitmodules. This\nenables the distribution of a default setting for this option by simply\ncommitting a modified .gitmodules file without each developer having to\ncall \"git submodule sync\". When using \"git status\" or \"git diff\" with\n\"--ignore-submodules=none\" option the default behavior of scanning all\nsubmodules work trees can be restored temporarily.\n\n\nComments?\n\n\nJens Lehmann (2):\n  Submodules: Add the new \"ignore\" config option for diff and status\n  Submodules: Use \"ignore\" settings from .gitmodules too for diff and\n    status\n\n Documentation/config.txt       |   13 ++++\n Documentation/diff-options.txt |    6 ++-\n Documentation/git-status.txt   |    6 ++-\n Documentation/gitmodules.txt   |   15 ++++\n builtin/commit.c               |    2 +\n builtin/diff-files.c           |    2 +\n builtin/diff-index.c           |    2 +\n builtin/diff-tree.c            |    2 +\n builtin/diff.c                 |    2 +\n diff-lib.c                     |   15 +++--\n diff.c                         |   35 ++++++++--\n diff.h                         |    1 +\n submodule.c                    |   63 ++++++++++++++++-\n submodule.h                    |    4 +\n t/t4027-diff-submodule.sh      |  139 ++++++++++++++++++++++++++++++++++++\n t/t7508-status.sh              |  154 ++++++++++++++++++++++++++++++++++++++-\n wt-status.c                    |    8 ++-\n 17 files changed, 449 insertions(+), 20 deletions(-)\n\n-- \n1.7.2.223.g830604.dirty\n"},{"id":"146408","messageId":"4C4DD3A6.7050401@web.de","threadId":"24531","inReplyTo":"4C4DD33F.4020104@web.de","subject":"[PATCH 1/2] Submodules: Add the new \"ignore\" config option for diff and status","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-07-26T18:27:50Z","receivedAt":"2010-07-26T18:27:50Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"The new \"ignore\" config option controls the default behavior for \"git\nstatus\" and the diff family. It specifies under what circumstances they\nconsider submodules as modified and can be set separately for each\nsubmodule.\n\nThe command line option \"--ignore-submodules=\" has been extended to accept\nthe new parameter \"none\" for both status and diff.\n\nUsers that chose submodules to get rid of long work tree scanning times\nmight want to set the \"dirty\" option for those submodules. This brings\nback the pre 1.7.0 behavior, where submodule work trees were never\nscanned for modifications. By using \"--ignore-submodules=none\" on the\ncommand line the status and diff commands can be told to do a full scan.\n\nThis option can be set to the following values (which have the same name\nand meaning as for the \"--ignore-submodules\" option of status and diff):\n\n\"all\": All changes to the submodule will be ignored.\n\n\"dirty\": Only differences of the commit recorded in the superproject and\n\tthe submodules HEAD will be considered modifications, all changes\n\tto the work tree of the submodule will be ignored. When using this\n\tvalue, the submodule will not be scanned for work tree changes at\n\tall, leading to a performance benefit on large submodules.\n\n\"untracked\": Only untracked files in the submodules work tree are ignored,\n\ta changed HEAD and/or modified files in the submodule will mark it\n\tas modified.\n\n\"none\" (which is the default): Either untracked or modified files in a\n\tsubmodules work tree or a difference between the subdmodules HEAD\n\tand the commit recorded in the superproject will make it show up\n\tas changed. This value is added as a new parameter for the\n\t\"--ignore-submodules\" option of the diff family and \"git status\"\n\tso the user can override the settings in the configuration.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/config.txt       |   10 ++++\n Documentation/diff-options.txt |    6 ++-\n Documentation/git-status.txt   |    6 ++-\n diff-lib.c                     |   15 ++++--\n diff.c                         |   35 ++++++++++++---\n diff.h                         |    1 +\n submodule.c                    |   51 +++++++++++++++++++++-\n submodule.h                    |    3 +\n t/t4027-diff-submodule.sh      |   73 +++++++++++++++++++++++++++++++\n t/t7508-status.sh              |   93 ++++++++++++++++++++++++++++++++++++++--\n wt-status.c                    |    8 +++-\n 11 files changed, 281 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f81fb91..783f264 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1747,6 +1747,16 @@ submodule.<name>.update::\n \tURL and other values found in the `.gitmodules` file.  See\n \tlinkgit:git-submodule[1] and linkgit:gitmodules[5] for details.\n\n+submodule.<submodulename>.ignore::\n+\tDefines under what circumstances \"git status\" and the diff family show\n+\ta submodule as modified. When set to \"all\", it will never be considered\n+\tmodified, \"dirty\" will ignore all changes to the submodules work tree and\n+\ttakes only differences between the HEAD of the submodule and the commit\n+\trecorded in the superproject into account. \"untracked\" will additionally\n+\tlet submodules with modified tracked files in their work tree show up.\n+\tUsing \"none\" (the default when this option is not set) also shows\n+\tsubmodules that have untracked files in their work tree as changed.\n+\n tar.umask::\n \tThis variable can be used to restrict the permission bits of\n \ttar archive entries.  The default is 0002, which turns off the\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 2371262..9cf7506 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -330,7 +330,11 @@ endif::git-format-patch[]\n\n --ignore-submodules[=<when>]::\n \tIgnore changes to submodules in the diff generation. <when> can be\n-\teither \"untracked\", \"dirty\" or \"all\", which is the default. When\n+\teither \"none\", \"untracked\", \"dirty\" or \"all\", which is the default\n+\tUsing \"none\" will consider the submodule modified when it either contains\n+\tuntracked or modified files or its HEAD differs from the commit recorded\n+\tin the superproject and can be used to override any settings of the\n+\t'ignore' option in linkgit:git-config[1]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/Documentation/git-status.txt b/Documentation/git-status.txt\nindex 2fd054c..a7a5d79 100644\n--- a/Documentation/git-status.txt\n+++ b/Documentation/git-status.txt\n@@ -55,7 +55,11 @@ specified.\n\n --ignore-submodules[=<when>]::\n \tIgnore changes to submodules when looking for changes. <when> can be\n-\teither \"untracked\", \"dirty\" or \"all\", which is the default. When\n+\teither \"none\", \"untracked\", \"dirty\" or \"all\", which is the default.\n+\tUsing \"none\" will consider the submodule modified when it either contains\n+\tuntracked or modified files or its HEAD differs from the commit recorded\n+\tin the superproject and can be used to override any settings of the\n+\t'ignore' option in linkgit:git-config[1]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 8b8978a..392ce2b 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -68,11 +68,16 @@ static int match_stat_with_submodule(struct diff_options *diffopt,\n \t\t\t\t      unsigned ce_option, unsigned *dirty_submodule)\n {\n \tint changed = ce_match_stat(ce, st, ce_option);\n-\tif (S_ISGITLINK(ce->ce_mode)\n-\t    && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)\n-\t    && !DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)\n-\t    && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) {\n-\t\t*dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));\n+\tif (S_ISGITLINK(ce->ce_mode)) {\n+\t\tunsigned orig_flags = diffopt->flags;\n+\t\tif (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))\n+\t\t\tset_diffopt_flags_from_submodule_config(diffopt, ce->name);\n+\t\tif (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))\n+\t\t\tchanged = 0;\n+\t\telse if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)\n+\t\t    && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))\n+\t\t\t*dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));\n+\t\tdiffopt->flags = orig_flags;\n \t}\n \treturn changed;\n }\ndiff --git a/diff.c b/diff.c\nindex 17873f3..8206047 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -141,6 +141,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n\n+\tif (!prefixcmp(var, \"submodule.\"))\n+\t\treturn parse_submodule_config_option(var, value);\n+\n \treturn git_color_default_config(var, value, cb);\n }\n\n@@ -3166,11 +3169,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n \t\tDIFF_OPT_SET(options, ALLOW_TEXTCONV);\n \telse if (!strcmp(arg, \"--no-textconv\"))\n \t\tDIFF_OPT_CLR(options, ALLOW_TEXTCONV);\n-\telse if (!strcmp(arg, \"--ignore-submodules\"))\n+\telse if (!strcmp(arg, \"--ignore-submodules\")) {\n+\t\tDIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(options, \"all\");\n-\telse if (!prefixcmp(arg, \"--ignore-submodules=\"))\n+\t} else if (!prefixcmp(arg, \"--ignore-submodules=\")) {\n+\t\tDIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(options, arg + 20);\n-\telse if (!strcmp(arg, \"--submodule\"))\n+\t} else if (!strcmp(arg, \"--submodule\"))\n \t\tDIFF_OPT_SET(options, SUBMODULE_LOG);\n \telse if (!prefixcmp(arg, \"--submodule=\")) {\n \t\tif (!strcmp(arg + 12, \"log\"))\n@@ -4103,6 +4108,24 @@ int diff_result_code(struct diff_options *opt, int status)\n \treturn result;\n }\n\n+/*\n+ * Shall changes to this submodule be ignored?\n+ *\n+ * Submodule changes can be configured to be ignored separately for each path,\n+ * but that configuration can be overridden from the command line.\n+ */\n+static int is_submodule_ignored(const char *path, struct diff_options *options)\n+{\n+\tint ignored = 0;\n+\tunsigned orig_flags = options->flags;\n+\tif (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))\n+\t\tset_diffopt_flags_from_submodule_config(options, path);\n+\tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES))\n+\t\tignored = 1;\n+\toptions->flags = orig_flags;\n+\treturn ignored;\n+}\n+\n void diff_addremove(struct diff_options *options,\n \t\t    int addremove, unsigned mode,\n \t\t    const unsigned char *sha1,\n@@ -4110,7 +4133,7 @@ void diff_addremove(struct diff_options *options,\n {\n \tstruct diff_filespec *one, *two;\n\n-\tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode))\n+\tif (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options))\n \t\treturn;\n\n \t/* This may look odd, but it is a preparation for\n@@ -4157,8 +4180,8 @@ void diff_change(struct diff_options *options,\n {\n \tstruct diff_filespec *one, *two;\n\n-\tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode)\n-\t\t\t&& S_ISGITLINK(new_mode))\n+\tif (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&\n+\t    is_submodule_ignored(concatpath, options))\n \t\treturn;\n\n \tif (DIFF_OPT_TST(options, REVERSE_DIFF)) {\ndiff --git a/diff.h b/diff.h\nindex 063d10a..53ad345 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -77,6 +77,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)\n #define DIFF_OPT_DIRTY_SUBMODULES    (1 << 24)\n #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)\n #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)\n+#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)\n\n #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)\n #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)\ndiff --git a/submodule.c b/submodule.c\nindex 61cb6e2..d35a14d 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -6,6 +6,9 @@\n #include \"revision.h\"\n #include \"run-command.h\"\n #include \"diffcore.h\"\n+#include \"string-list.h\"\n+\n+struct string_list config_ignore;\n\n static int add_submodule_odb(const char *path)\n {\n@@ -46,6 +49,52 @@ done:\n \treturn ret;\n }\n\n+void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n+\t\t\t\t\t     const char *path)\n+{\n+\tstruct string_list_item *ignore_option;\n+\tignore_option = unsorted_string_list_lookup(&config_ignore, path);\n+\tif (ignore_option)\n+\t\thandle_ignore_submodules_arg(diffopt, ignore_option->util);\n+}\n+\n+static int submodule_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!prefixcmp(var, \"submodule.\"))\n+\t\treturn parse_submodule_config_option(var, value);\n+\treturn 0;\n+}\n+\n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\tint len;\n+\tstruct string_list_item *ignore_option;\n+\tstruct strbuf path = STRBUF_INIT;\n+\n+\tvar += 10;\t\t/* Skip \"submodule.\" */\n+\n+\tlen = strlen(var);\n+\tif ((len > 7) && !strcmp(var + len - 7, \".ignore\")) {\n+\t\tif (strcmp(value, \"untracked\") && strcmp(value, \"dirty\") &&\n+\t\t    strcmp(value, \"all\") && strcmp(value, \"none\")) {\n+\t\t\twarning(\"Invalid parameter \\\"%s\\\" for config option \\\"submodule.%s.ignore\\\"\", value, var);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\tstrbuf_add(&path, var, len - 7);\n+\t\tignore_option = unsorted_string_list_lookup(&config_ignore, path.buf);\n+\t\tif (ignore_option)\n+\t\t\tfree(ignore_option->util);\n+\t\telse\n+\t\t\tignore_option = string_list_append(&config_ignore,\n+\t\t\t\t\t strbuf_detach(&path, NULL));\n+\t\tstrbuf_release(&path);\n+\t\tignore_option->util = xstrdup(value);\n+\t\treturn 0;\n+\t}\n+\treturn 0;\n+}\n+\n void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\t\t\t  const char *arg)\n {\n@@ -55,7 +104,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\tDIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);\n \telse if (!strcmp(arg, \"dirty\"))\n \t\tDIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);\n-\telse\n+\telse if (strcmp(arg, \"none\"))\n \t\tdie(\"bad --ignore-submodules argument: %s\", arg);\n }\n\ndiff --git a/submodule.h b/submodule.h\nindex 6fd3bb4..185a5ce 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -3,6 +3,9 @@\n\n struct diff_options;\n\n+void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n+\t\tconst char *path);\n+int parse_submodule_config_option(const char *var, const char *value);\n void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tunsigned char one[20], unsigned char two[20],\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 1bd8e5e..5022fa0 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -114,6 +114,30 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)'\n \t! test -s actual4\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' '\n+\tgit config submodule.sub.ignore none &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config submodule.sub.ignore all &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config submodule.sub.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual3.body &&\n+\tgit config submodule.sub.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit diff HEAD --ignore-submodules=none >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.sub\n+'\n+\n test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' '\n \t(\n \t\tcd sub &&\n@@ -146,6 +170,55 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n \t! test -s actual4\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.git/config]' '\n+\tgit config submodule.sub.ignore all &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config submodule.sub.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\t! test -s actual3 &&\n+\tgit config submodule.sub.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit diff --ignore-submodules=none HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.sub\n+'\n+\n+test_expect_success 'git diff between submodule commits' '\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit diff --ignore-submodules=dirty HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit diff --ignore-submodules HEAD^..HEAD >actual &&\n+\t! test -s actual\n+'\n+\n+test_expect_success 'git diff between submodule commits [.git/config]' '\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config submodule.sub.ignore dirty &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config submodule.sub.ignore all &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\t! test -s actual &&\n+\tgit diff --ignore-submodules=dirty HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\tgit config --remove-section submodule.sub\n+'\n+\n test_expect_success 'git diff (empty submodule dir)' '\n \t: >empty &&\n \trm -rf sub/* sub/.git &&\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex a72fe3a..3896808 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -808,24 +808,38 @@ test_expect_success POSIXPERM 'status succeeds in a read-only repository' '\n \t(exit $status)\n '\n\n+(cd sm && echo > bar && git add bar && git commit -q -m 'Add bar' && cd .. && git add sm)\n+new_head=$(cd sm && git rev-parse --short=7 --verify HEAD)\n+touch .gitmodules\n+\n cat > expect << EOF\n # On branch master\n+# Changes to be committed:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#\n+#\tmodified:   sm\n+#\n # Changed but not updated:\n #   (use \"git add <file>...\" to update what will be committed)\n #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n #\n #\tmodified:   dir1/modified\n #\n+# Submodule changes to be committed:\n+#\n+# * sm $head...$new_head (1):\n+#   > Add bar\n+#\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n #\texpect\n #\toutput\n #\tuntracked\n-no changes added to commit (use \"git add\" and/or \"git commit -a\")\n EOF\n\n test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' '\n@@ -834,19 +848,45 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un\n \ttest_cmp expect output\n '\n\n+test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '\n+\tgit config --add submodule.sm.ignore untracked &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' '\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n\n+test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '\n+\tgit config --add submodule.sm.ignore dirty &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' '\n \techo modified > sm/foo &&\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n\n+test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' '\n+\tgit config --add submodule.sm.ignore dirty &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n cat > expect << EOF\n # On branch master\n+# Changes to be committed:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#\n+#\tmodified:   sm\n+#\n # Changed but not updated:\n #   (use \"git add <file>...\" to update what will be committed)\n #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n@@ -855,16 +895,21 @@ cat > expect << EOF\n #\tmodified:   dir1/modified\n #\tmodified:   sm (modified content)\n #\n+# Submodule changes to be committed:\n+#\n+# * sm $head...$new_head (1):\n+#   > Add bar\n+#\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n #\texpect\n #\toutput\n #\tuntracked\n-no changes added to commit (use \"git add\" and/or \"git commit -a\")\n EOF\n\n test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules with modified content\" '\n@@ -872,10 +917,22 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules w\n \ttest_cmp expect output\n '\n\n+test_expect_success \".git/config ignore=untracked doesn't suppress submodules with modified content\" '\n+\tgit config --add submodule.sm.ignore untracked &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n head2=$(cd sm && git commit -q -m \"2nd commit\" foo && git rev-parse --short=7 --verify HEAD)\n\n cat > expect << EOF\n # On branch master\n+# Changes to be committed:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#\n+#\tmodified:   sm\n+#\n # Changed but not updated:\n #   (use \"git add <file>...\" to update what will be committed)\n #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n@@ -883,21 +940,26 @@ cat > expect << EOF\n #\tmodified:   dir1/modified\n #\tmodified:   sm (new commits)\n #\n+# Submodule changes to be committed:\n+#\n+# * sm $head...$new_head (1):\n+#   > Add bar\n+#\n # Submodules changed but not updated:\n #\n-# * sm $head...$head2 (1):\n+# * sm $new_head...$head2 (1):\n #   > 2nd commit\n #\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n #\texpect\n #\toutput\n #\tuntracked\n-no changes added to commit (use \"git add\" and/or \"git commit -a\")\n EOF\n\n test_expect_success \"--ignore-submodules=untracked doesn't suppress submodule summary\" '\n@@ -905,11 +967,26 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodule su\n \ttest_cmp expect output\n '\n\n+test_expect_success \".git/config ignore=untracked doesn't suppress submodule summary\" '\n+\tgit config --add submodule.sm.ignore untracked &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n test_expect_success \"--ignore-submodules=dirty doesn't suppress submodule summary\" '\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n\n+test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\" '\n+\tgit config --add submodule.sm.ignore dirty &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n+\n cat > expect << EOF\n # On branch master\n # Changed but not updated:\n@@ -921,6 +998,7 @@ cat > expect << EOF\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n@@ -935,4 +1013,11 @@ test_expect_success \"--ignore-submodules=all suppresses submodule summary\" '\n \ttest_cmp expect output\n '\n\n+test_expect_failure '.git/config ignore=all suppresses submodule summary' '\n+\tgit config --add submodule.sm.ignore all &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.sm\n+'\n+\n test_done\ndiff --git a/wt-status.c b/wt-status.c\nindex 2f9e33c..54b6b03 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -313,8 +313,10 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)\n \tDIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);\n \tif (!s->show_untracked_files)\n \t\tDIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);\n-\tif (s->ignore_submodule_arg)\n+\tif (s->ignore_submodule_arg) {\n+\t\tDIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);\n+    }\n \trev.diffopt.format_callback = wt_status_collect_changed_cb;\n \trev.diffopt.format_callback_data = s;\n \trev.prune_data = s->pathspec;\n@@ -331,8 +333,10 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \topt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;\n \tsetup_revisions(0, NULL, &rev, &opt);\n\n-\tif (s->ignore_submodule_arg)\n+\tif (s->ignore_submodule_arg) {\n+\t\tDIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);\n+\t}\n\n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = wt_status_collect_updated_cb;\n-- \n1.7.2.223.g830604.dirty\n"},{"id":"146409","messageId":"4C4DD3CF.9070906@web.de","threadId":"24531","inReplyTo":"4C4DD33F.4020104@web.de","subject":"[PATCH 2/2] Submodules: Use \"ignore\" settings from .gitmodules too for diff and status","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-07-26T18:28:31Z","receivedAt":"2010-07-26T18:28:31Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"The .gitmodules file is parsed for \"submodule.<name>.ignore\" entries\nbefore looking for them in .git/config. Thus settings found in .git/config\nwill override those from .gitmodules, thereby allowing the local developer\nto ignore settings given by the remote side while also letting upstream\nset defaults for those users who don't have special needs.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/config.txt       |    3 ++\n Documentation/diff-options.txt |    2 +-\n Documentation/git-status.txt   |    2 +-\n Documentation/gitmodules.txt   |   15 +++++++++\n builtin/commit.c               |    2 +\n builtin/diff-files.c           |    2 +\n builtin/diff-index.c           |    2 +\n builtin/diff-tree.c            |    2 +\n builtin/diff.c                 |    2 +\n submodule.c                    |   12 +++++++\n submodule.h                    |    1 +\n t/t4027-diff-submodule.sh      |   66 ++++++++++++++++++++++++++++++++++++++++\n t/t7508-status.sh              |   63 +++++++++++++++++++++++++++++++++++++-\n 13 files changed, 171 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 783f264..06e70cb 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1756,6 +1756,9 @@ submodule.<submodulename>.ignore::\n \tlet submodules with modified tracked files in their work tree show up.\n \tUsing \"none\" (the default when this option is not set) also shows\n \tsubmodules that have untracked files in their work tree as changed.\n+\tThis setting overrides any setting made in .gitmodules for this submodule,\n+\tboth settings can be overriden on the command line by using the\n+\t\"--ignore-submodule\" option.\n\n tar.umask::\n \tThis variable can be used to restrict the permission bits of\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 9cf7506..faa467b 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -334,7 +334,7 @@ endif::git-format-patch[]\n \tUsing \"none\" will consider the submodule modified when it either contains\n \tuntracked or modified files or its HEAD differs from the commit recorded\n \tin the superproject and can be used to override any settings of the\n-\t'ignore' option in linkgit:git-config[1]. When\n+\t'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/Documentation/git-status.txt b/Documentation/git-status.txt\nindex a7a5d79..dae190a 100644\n--- a/Documentation/git-status.txt\n+++ b/Documentation/git-status.txt\n@@ -59,7 +59,7 @@ specified.\n \tUsing \"none\" will consider the submodule modified when it either contains\n \tuntracked or modified files or its HEAD differs from the commit recorded\n \tin the superproject and can be used to override any settings of the\n-\t'ignore' option in linkgit:git-config[1]. When\n+\t'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex 72a13d1..8ae107d 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -44,6 +44,21 @@ submodule.<name>.update::\n \tThis config option is overridden if 'git submodule update' is given\n \tthe '--merge' or '--rebase' options.\n\n+submodule.<name>.ignore::\n+\tDefines under what circumstances \"git status\" and the diff family show\n+\ta submodule as modified. When set to \"all\", it will never be considered\n+\tmodified, \"dirty\" will ignore all changes to the submodules work tree and\n+\ttakes only differences between the HEAD of the submodule and the commit\n+\trecorded in the superproject into account. \"untracked\" will additionally\n+\tlet submodules with modified tracked files in their work tree show up.\n+\tUsing \"none\" (the default when this option is not set) also shows\n+\tsubmodules that have untracked files in their work tree as changed.\n+\tIf this option is also present in the submodules entry in .git/config of\n+\tthe superproject, the setting there will override the one found in\n+\t.gitmodules.\n+\tBoth settings can be overriden on the command line by using the\n+\t\"--ignore-submodule\" option.\n+\n\n EXAMPLES\n --------\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex a78dbd8..9456f4a 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -25,6 +25,7 @@\n #include \"rerere.h\"\n #include \"unpack-trees.h\"\n #include \"quote.h\"\n+#include \"submodule.h\"\n\n static const char * const builtin_commit_usage[] = {\n \t\"git commit [options] [--] <filepattern>...\",\n@@ -1073,6 +1074,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\tstatus_format = STATUS_FORMAT_PORCELAIN;\n\n \twt_status_prepare(&s);\n+\tgitmodules_config();\n \tgit_config(git_status_config, &s);\n \tin_merge = file_exists(git_path(\"MERGE_HEAD\"));\n \targc = parse_options(argc, argv, prefix,\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 5b64011..951c7c8 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -8,6 +8,7 @@\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n static const char diff_files_usage[] =\n \"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]\"\n@@ -20,6 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \tunsigned options = 0;\n\n \tinit_revisions(&rev, prefix);\n+\tgitmodules_config();\n \tgit_config(git_diff_basic_config, NULL); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n\ndiff --git a/builtin/diff-index.c b/builtin/diff-index.c\nindex 0483749..2eb32bd 100644\n--- a/builtin/diff-index.c\n+++ b/builtin/diff-index.c\n@@ -3,6 +3,7 @@\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n static const char diff_cache_usage[] =\n \"git diff-index [-m] [--cached] \"\n@@ -17,6 +18,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)\n \tint result;\n\n \tinit_revisions(&rev, prefix);\n+\tgitmodules_config();\n \tgit_config(git_diff_basic_config, NULL); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n\ndiff --git a/builtin/diff-tree.c b/builtin/diff-tree.c\nindex 3c78bda..0d2a3e9 100644\n--- a/builtin/diff-tree.c\n+++ b/builtin/diff-tree.c\n@@ -3,6 +3,7 @@\n #include \"commit.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n static struct rev_info log_tree_opt;\n\n@@ -112,6 +113,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)\n \tint read_stdin = 0;\n\n \tinit_revisions(opt, prefix);\n+\tgitmodules_config();\n \tgit_config(git_diff_basic_config, NULL); /* no \"diff\" UI options */\n \topt->abbrev = 0;\n \topt->diff = 1;\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 89ae89c..a43d326 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -13,6 +13,7 @@\n #include \"revision.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n struct blobinfo {\n \tunsigned char sha1[20];\n@@ -279,6 +280,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t */\n\n \tprefix = setup_git_directory_gently(&nongit);\n+\tgitmodules_config();\n \tgit_config(git_diff_ui_config, NULL);\n\n \tif (diff_use_color_default == -1)\ndiff --git a/submodule.c b/submodule.c\nindex d35a14d..1bcb0e9 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -65,6 +65,18 @@ static int submodule_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n\n+void gitmodules_config()\n+{\n+\tconst char *work_tree = get_git_work_tree();\n+\tif (work_tree) {\n+\t\tstruct strbuf gitmodules_path = STRBUF_INIT;\n+\t\tstrbuf_addstr(&gitmodules_path, work_tree);\n+\t\tstrbuf_addstr(&gitmodules_path, \"/.gitmodules\");\n+\t\tgit_config_from_file(submodule_config, gitmodules_path.buf, NULL);\n+\t\tstrbuf_release(&gitmodules_path);\n+\t}\n+}\n+\n int parse_submodule_config_option(const char *var, const char *value)\n {\n \tint len;\ndiff --git a/submodule.h b/submodule.h\nindex 185a5ce..8ac4037 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -5,6 +5,7 @@ struct diff_options;\n\n void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \t\tconst char *path);\n+void gitmodules_config();\n int parse_submodule_config_option(const char *var, const char *value);\n void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n void show_submodule_summary(FILE *f, const char *path,\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 5022fa0..dccdd23 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -138,6 +138,32 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \tgit config --remove-section submodule.sub\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' '\n+\tgit config --add -f .gitmodules submodule.sub.ignore none &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config -f .gitmodules submodule.sub.ignore all &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config -f .gitmodules submodule.sub.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual3.body &&\n+\tgit config -f .gitmodules submodule.sub.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit config submodule.sub.ignore none &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.sub &&\n+\trm .gitmodules\n+'\n+\n test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' '\n \t(\n \t\tcd sub &&\n@@ -187,6 +213,25 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)\n \tgit config --remove-section submodule.sub\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n+\tgit config --add -f .gitmodules submodule.sub.ignore all &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config -f .gitmodules submodule.sub.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\t! test -s actual3 &&\n+\tgit config -f .gitmodules submodule.sub.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit config submodule.sub.ignore none &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.sub &&\n+\trm .gitmodules\n+'\n+\n test_expect_success 'git diff between submodule commits' '\n \tgit diff HEAD^..HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n@@ -219,6 +264,27 @@ test_expect_success 'git diff between submodule commits [.git/config]' '\n \tgit config --remove-section submodule.sub\n '\n\n+test_expect_success 'git diff between submodule commits [.gitmodules]' '\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --add -f .gitmodules submodule.sub.ignore dirty &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config -f .gitmodules submodule.sub.ignore all &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\t! test -s actual &&\n+\tgit config submodule.sub.ignore dirty &&\n+\tgit diff  HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\tgit config --remove-section submodule.sub &&\n+\trm .gitmodules\n+'\n+\n test_expect_success 'git diff (empty submodule dir)' '\n \t: >empty &&\n \trm -rf sub/* sub/.git &&\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 3896808..bc3138c 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -848,10 +848,19 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un\n \ttest_cmp expect output\n '\n\n+test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore untracked &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n+\n test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore untracked &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n@@ -860,10 +869,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac\n \ttest_cmp expect output\n '\n\n+test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore dirty &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n+\n test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore dirty &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n@@ -873,10 +891,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi\n \ttest_cmp expect output\n '\n\n+test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore dirty &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n+\n test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore dirty &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n@@ -917,10 +944,19 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules w\n \ttest_cmp expect output\n '\n\n+test_expect_success \".gitmodules ignore=untracked doesn't suppress submodules with modified content\" '\n+\tgit config --add -f .gitmodules submodule.sm.ignore untracked &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n+\n test_expect_success \".git/config ignore=untracked doesn't suppress submodules with modified content\" '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore untracked &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n@@ -967,10 +1003,19 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodule su\n \ttest_cmp expect output\n '\n\n+test_expect_success \".gitmodules ignore=untracked doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.sm.ignore untracked &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n+\n test_expect_success \".git/config ignore=untracked doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore untracked &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n@@ -978,15 +1023,22 @@ test_expect_success \"--ignore-submodules=dirty doesn't suppress submodule summar\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n+test_expect_success \".gitmodules ignore=dirty doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.sm.ignore dirty &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n\n test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore dirty &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n-\n cat > expect << EOF\n # On branch master\n # Changed but not updated:\n@@ -1013,10 +1065,19 @@ test_expect_success \"--ignore-submodules=all suppresses submodule summary\" '\n \ttest_cmp expect output\n '\n\n+test_expect_failure '.gitmodules ignore=all suppresses submodule summary' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore all &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm\n+'\n+\n test_expect_failure '.git/config ignore=all suppresses submodule summary' '\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n \tgit config --add submodule.sm.ignore all &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.sm &&\n \tgit config --remove-section submodule.sm\n '\n\n-- \n1.7.2.223.g830604.dirty\n"},{"id":"146657","messageId":"7vhbjjware.fsf@alter.siamese.dyndns.org","threadId":"24531","inReplyTo":"4C4DD3CF.9070906@web.de","subject":"Re: [PATCH 2/2] Submodules: Use \"ignore\" settings from .gitmodules too for diff and status","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-07-28T21:35:01Z","receivedAt":"2010-07-28T21:35:01Z","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> The .gitmodules file is parsed for \"submodule.<name>.ignore\" entries\n> before looking for them in .git/config. Thus settings found in .git/config\n> will override those from .gitmodules,...\n\nHmph.\n\nThe value of \"submodule.<name>.path\" does not have to be \"<name>\".  There\nseems to be a bit of confusion here.\n\nI thought that [PATCH 1/2] used the path to the submodule, not its name,\nas the key.  Even though the patch to Documentation/config.txt talks about\n\"submodule.<submodulename>.ignore\", what the code actually seems to do in\nset-from-submodule-config is to use path.  \n\nBut this patch seems to key off of <name>.\n\nI suspect that it would make more sense to use <name> so that once the\nuser configures ignore in .git/config, it will persist across moving of\nthe submodule in the superproject tree.\n\nIn either case, we would want to be consistent between the two, no?\n"},{"id":"147159","messageId":"alpine.DEB.1.00.1008051025451.2983@bonsai2","threadId":"24531","inReplyTo":"4C4DD33F.4020104@web.de","subject":"Re: [PATCH 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2010-08-05T09:21:36Z","receivedAt":"2010-08-05T09:21:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 26 Jul 2010, Jens Lehmann wrote:\n\n> These two patches are extremly useful for those users who chose \n> submodules because they wanted to reduce the time it takes for \"git \n> status\" and \"git diff\" to recurse through the whole work tree by putting \n> sometimes large amounts of files into submodules, which weren't scanned \n> in the past.\n> \n> Since 1.7.0 \"git status\" and \"git diff\" recurse through submodule work \n> trees, which has a - sometimes drastic - performance impact when large \n> submodules are present. Using the \"ignore=dirty\" config option restores \n> the former behaviour.\n> \n> This option can be set in the .gitmodules file or in .git/config, any \n> settings found in the latter override those from .gitmodules. This \n> enables the distribution of a default setting for this option by simply \n> committing a modified .gitmodules file without each developer having to \n> call \"git submodule sync\". When using \"git status\" or \"git diff\" with \n> \"--ignore-submodules=none\" option the default behavior of scanning all \n> submodules work trees can be restored temporarily.\n\nThis is incredibly useful stuff. Indeed, the time for one \"git status\" \nwent down from > 50 sec to < 2 sec again in my project. (I have the \nimpression that it still does a little too much, but I will have to have \nsome time for strace()ing to find out for real.) Therefore, I applied it \nto 4msysgit.git's 'devel' branch.\n\nHowever, one thing is inconvenient: there are config options per \nsubmodule, but no single option to just turn the behavior back to before. \nI know the reasoning behind showing dirty submodules, so I am fine with \nthat feature being opt-out, but for my real world scenario, it just slows \nme down, so I _need_ to turn it off.\n\nTo put my money where my mouth is (since I need it myself, I also pushed \nit to 4msysgit.git's 'devel' branch):\n\n-- snipsnap --\nFrom f7b1e98a0d850e5b1bc56a825fcfe5c87076dfa9 Mon Sep 17 00:00:00 2001\nFrom: Johannes Schindelin <johannes.schindelin@gmx.de>\nDate: Thu, 5 Aug 2010 10:49:55 +0200\nSubject: [PATCH] Add the 'diff.ignoreSubmodules' config setting\n\nWhen you have a lot of submodules checked out, the time penalty to check\nfor dirty submodules can easily imply a multiplication of the total time\nby the factor 20. This makes the difference between almost instantaneous\n(< 2 seconds) and unbearably slow (> 50 seconds) here, since the disk\ncaches are constantly overloaded.\n\nTo this end, the submodule.*.ignore config option was introduced, but it\nis per-submodule.\n\nThis commit introduces a global config setting to set a default\n(porcelain) value for the --ignore-submodules option, keeping the\ndefault at 'none'. It can be overridden by the submodule.*.ignore\nsetting and by the --ignore-submodules option.\n\nIncidentally, this commit fixes an issue with the overriding logic:\nmultiple --ignore-submodules options would not clear the previously\nset flags.\n\nWhile at it, fix a typo in the documentation for submodule.*.ignore.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/config.txt |    7 ++++++-\n diff.c                   |    6 +++++-\n submodule.c              |    4 ++++\n 3 files changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5594ce0..8384d12 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -832,6 +832,11 @@ diff.renames::\n \twill enable basic rename detection.  If set to \"copies\" or\n \t\"copy\", it will detect copies, as well.\n \n+diff.ignoreSubmodules::\n+\tSets the default value of --ignore-submodules. Note that this\n+\taffects only 'git diff' Porcelain, and not lower level 'diff'\n+\tcommands such as 'git diff-files'.\n+\n diff.suppressBlankEmpty::\n \tA boolean to inhibit the standard behavior of printing a space\n \tbefore each empty output line. Defaults to false.\n@@ -1769,7 +1774,7 @@ submodule.<submodulename>.ignore::\n \tsubmodules that have untracked files in their work tree as changed.\n \tThis setting overrides any setting made in .gitmodules for this submodule,\n \tboth settings can be overriden on the command line by using the\n-\t\"--ignore-submodule\" option.\n+\t\"--ignore-submodules\" option.\n \n tar.umask::\n \tThis variable can be used to restrict the permission bits of\ndiff --git a/diff.c b/diff.c\nindex 8206047..1ddfdfb 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;\n int diff_auto_refresh_index = 1;\n static int diff_mnemonic_prefix;\n static int diff_no_prefix;\n+static struct diff_options default_diff_options;\n \n static char diff_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n@@ -107,6 +108,9 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)\n \tif (!strcmp(var, \"diff.wordregex\"))\n \t\treturn git_config_string(&diff_word_regex_cfg, var, value);\n \n+\tif (!strcmp(var, \"diff.ignoresubmodules\"))\n+\t\thandle_ignore_submodules_arg(&default_diff_options, value);\n+\n \treturn git_diff_basic_config(var, value, cb);\n }\n \n@@ -2816,7 +2820,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)\n \n void diff_setup(struct diff_options *options)\n {\n-\tmemset(options, 0, sizeof(*options));\n+\tmemcpy(options, &default_diff_options, sizeof(*options));\n \tmemset(&diff_queued_diff, 0, sizeof(diff_queued_diff));\n \n \toptions->file = stdout;\ndiff --git a/submodule.c b/submodule.c\nindex 1bcb0e9..75f3368 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -110,6 +110,10 @@ int parse_submodule_config_option(const char *var, const char *value)\n void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\t\t\t  const char *arg)\n {\n+\tDIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES);\n+\tDIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);\n+\tDIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES);\n+\n \tif (!strcmp(arg, \"all\"))\n \t\tDIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);\n \telse if (!strcmp(arg, \"untracked\"))\n-- \n1.7.2.1.2240.gde5dd\n"},{"id":"147220","messageId":"7vlj8ldmyj.fsf@alter.siamese.dyndns.org","threadId":"24531","inReplyTo":"alpine.DEB.1.00.1008051025451.2983@bonsai2","subject":"Re: [PATCH 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-08-05T16:49:08Z","receivedAt":"2010-08-05T16:49:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Date: Thu, 5 Aug 2010 10:49:55 +0200\n> Subject: [PATCH] Add the 'diff.ignoreSubmodules' config setting\n> ...\n> This commit introduces a global config setting to set a default\n> (porcelain) value for the --ignore-submodules option, keeping the\n> default at 'none'. It can be overridden by the submodule.*.ignore\n> setting and by the --ignore-submodules option.\n> ...\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n\nNice, at least from a cursory look.  \n\ndiff_setup() is shared by everybody both plumbing and Porcelain that use\ndiff and log, but you placed the smudging of the default based on config\nis in diff_ui_config(), so this patch looks safe.\n\nAnd the default setting can be overriden with --ignore-submodules from the\ncommand line during diff_opt_parse(), which is also safe and sane.\n\nThanks; will queue.\n\n> diff --git a/diff.c b/diff.c\n> index 8206047..1ddfdfb 100644\n> --- a/diff.c\n> +++ b/diff.c\n> @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;\n>  int diff_auto_refresh_index = 1;\n>  static int diff_mnemonic_prefix;\n>  static int diff_no_prefix;\n> +static struct diff_options default_diff_options;\n>  \n>  static char diff_colors[][COLOR_MAXLEN] = {\n>  \tGIT_COLOR_RESET,\n> @@ -107,6 +108,9 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)\n>  \tif (!strcmp(var, \"diff.wordregex\"))\n>  \t\treturn git_config_string(&diff_word_regex_cfg, var, value);\n>  \n> +\tif (!strcmp(var, \"diff.ignoresubmodules\"))\n> +\t\thandle_ignore_submodules_arg(&default_diff_options, value);\n> +\n>  \treturn git_diff_basic_config(var, value, cb);\n>  }\n>  \n> @@ -2816,7 +2820,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)\n>  \n>  void diff_setup(struct diff_options *options)\n>  {\n> -\tmemset(options, 0, sizeof(*options));\n> +\tmemcpy(options, &default_diff_options, sizeof(*options));\n>  \tmemset(&diff_queued_diff, 0, sizeof(diff_queued_diff));\n>  \n>  \toptions->file = stdout;\n> diff --git a/submodule.c b/submodule.c\n> index 1bcb0e9..75f3368 100644\n> --- a/submodule.c\n> +++ b/submodule.c\n> @@ -110,6 +110,10 @@ int parse_submodule_config_option(const char *var, const char *value)\n>  void handle_ignore_submodules_arg(struct diff_options *diffopt,\n>  \t\t\t\t  const char *arg)\n>  {\n> +\tDIFF_OPT_CLR(diffopt, IGNORE_SUBMODULES);\n> +\tDIFF_OPT_CLR(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);\n> +\tDIFF_OPT_CLR(diffopt, IGNORE_DIRTY_SUBMODULES);\n> +\n>  \tif (!strcmp(arg, \"all\"))\n>  \t\tDIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);\n>  \telse if (!strcmp(arg, \"untracked\"))\n> -- \n> 1.7.2.1.2240.gde5dd\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"147236","messageId":"4C5B0C13.6020809@web.de","threadId":"24531","inReplyTo":"7vlj8ldmyj.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-08-05T19:08:03Z","receivedAt":"2010-08-05T19:08:03Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 05.08.2010 18:49, schrieb Junio C Hamano:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n>> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> Date: Thu, 5 Aug 2010 10:49:55 +0200\n>> Subject: [PATCH] Add the 'diff.ignoreSubmodules' config setting\n>> ...\n>> This commit introduces a global config setting to set a default\n>> (porcelain) value for the --ignore-submodules option, keeping the\n>> default at 'none'. It can be overridden by the submodule.*.ignore\n>> setting and by the --ignore-submodules option.\n>> ...\n>> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> ---\n> \n> Nice, at least from a cursory look.  \n\nYup, makes sense to me too.\n\nAcked-by: Jens Lehmann <Jens.Lehmann@web.de>\n"},{"id":"147263","messageId":"4C5B3D36.1060902@web.de","threadId":"24531","inReplyTo":"7vhbjjware.fsf@alter.siamese.dyndns.org","subject":"[PATCH v2 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-08-05T22:37:42Z","receivedAt":"2010-08-05T22:37:42Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 28.07.2010 23:35, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> The .gitmodules file is parsed for \"submodule.<name>.ignore\" entries\n>> before looking for them in .git/config. Thus settings found in .git/config\n>> will override those from .gitmodules,...\n> \n> Hmph.\n> \n> The value of \"submodule.<name>.path\" does not have to be \"<name>\".  There\n> seems to be a bit of confusion here.\n\nThanks for clearing up my confusion, this is v2 of this patch using the\npath configured for the submodule instead of its name.\n\n\nJens Lehmann (2):\n  Submodules: Add the new \"ignore\" config option for diff and status\n  Submodules: Use \"ignore\" settings from .gitmodules too for diff and\n    status\n\n Documentation/config.txt       |   13 +++\n Documentation/diff-options.txt |    6 +-\n Documentation/git-status.txt   |    6 +-\n Documentation/gitmodules.txt   |   15 ++++\n builtin/commit.c               |    2 +\n builtin/diff-files.c           |    2 +\n builtin/diff-index.c           |    2 +\n builtin/diff-tree.c            |    2 +\n builtin/diff.c                 |    2 +\n diff-lib.c                     |   15 +++-\n diff.c                         |   35 +++++++--\n diff.h                         |    1 +\n submodule.c                    |   76 +++++++++++++++++-\n submodule.h                    |    4 +\n t/t4027-diff-submodule.sh      |  152 ++++++++++++++++++++++++++++++++++\n t/t7508-status.sh              |  175 +++++++++++++++++++++++++++++++++++++++-\n wt-status.c                    |    8 ++-\n 17 files changed, 496 insertions(+), 20 deletions(-)\n\n-- \n1.7.2.1.54.g6bed1\n"},{"id":"147264","messageId":"4C5B3D9D.60806@web.de","threadId":"24531","inReplyTo":"4C5B3D36.1060902@web.de","subject":"[PATCH v2 1/2] Submodules: Add the new \"ignore\" config option for diff and status","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-08-05T22:39:25Z","receivedAt":"2010-08-05T22:39:25Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"The new \"ignore\" config option controls the default behavior for \"git\nstatus\" and the diff family. It specifies under what circumstances they\nconsider submodules as modified and can be set separately for each\nsubmodule.\n\nThe command line option \"--ignore-submodules=\" has been extended to accept\nthe new parameter \"none\" for both status and diff.\n\nUsers that chose submodules to get rid of long work tree scanning times\nmight want to set the \"dirty\" option for those submodules. This brings\nback the pre 1.7.0 behavior, where submodule work trees were never\nscanned for modifications. By using \"--ignore-submodules=none\" on the\ncommand line the status and diff commands can be told to do a full scan.\n\nThis option can be set to the following values (which have the same name\nand meaning as for the \"--ignore-submodules\" option of status and diff):\n\n\"all\": All changes to the submodule will be ignored.\n\n\"dirty\": Only differences of the commit recorded in the superproject and\n\tthe submodules HEAD will be considered modifications, all changes\n\tto the work tree of the submodule will be ignored. When using this\n\tvalue, the submodule will not be scanned for work tree changes at\n\tall, leading to a performance benefit on large submodules.\n\n\"untracked\": Only untracked files in the submodules work tree are ignored,\n\ta changed HEAD and/or modified files in the submodule will mark it\n\tas modified.\n\n\"none\" (which is the default): Either untracked or modified files in a\n\tsubmodules work tree or a difference between the subdmodules HEAD\n\tand the commit recorded in the superproject will make it show up\n\tas changed. This value is added as a new parameter for the\n\t\"--ignore-submodules\" option of the diff family and \"git status\"\n\tso the user can override the settings in the configuration.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/config.txt       |   10 ++++\n Documentation/diff-options.txt |    6 ++-\n Documentation/git-status.txt   |    6 ++-\n diff-lib.c                     |   15 ++++--\n diff.c                         |   35 ++++++++++++--\n diff.h                         |    1 +\n submodule.c                    |   57 ++++++++++++++++++++++-\n submodule.h                    |    3 +\n t/t4027-diff-submodule.sh      |   76 ++++++++++++++++++++++++++++++\n t/t7508-status.sh              |  100 ++++++++++++++++++++++++++++++++++++++--\n wt-status.c                    |    8 ++-\n 11 files changed, 297 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f81fb91..06faa02 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1747,6 +1747,16 @@ submodule.<name>.update::\n \tURL and other values found in the `.gitmodules` file.  See\n \tlinkgit:git-submodule[1] and linkgit:gitmodules[5] for details.\n\n+submodule.<name>.ignore::\n+\tDefines under what circumstances \"git status\" and the diff family show\n+\ta submodule as modified. When set to \"all\", it will never be considered\n+\tmodified, \"dirty\" will ignore all changes to the submodules work tree and\n+\ttakes only differences between the HEAD of the submodule and the commit\n+\trecorded in the superproject into account. \"untracked\" will additionally\n+\tlet submodules with modified tracked files in their work tree show up.\n+\tUsing \"none\" (the default when this option is not set) also shows\n+\tsubmodules that have untracked files in their work tree as changed.\n+\n tar.umask::\n \tThis variable can be used to restrict the permission bits of\n \ttar archive entries.  The default is 0002, which turns off the\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 2371262..9cf7506 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -330,7 +330,11 @@ endif::git-format-patch[]\n\n --ignore-submodules[=<when>]::\n \tIgnore changes to submodules in the diff generation. <when> can be\n-\teither \"untracked\", \"dirty\" or \"all\", which is the default. When\n+\teither \"none\", \"untracked\", \"dirty\" or \"all\", which is the default\n+\tUsing \"none\" will consider the submodule modified when it either contains\n+\tuntracked or modified files or its HEAD differs from the commit recorded\n+\tin the superproject and can be used to override any settings of the\n+\t'ignore' option in linkgit:git-config[1]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/Documentation/git-status.txt b/Documentation/git-status.txt\nindex 2fd054c..a7a5d79 100644\n--- a/Documentation/git-status.txt\n+++ b/Documentation/git-status.txt\n@@ -55,7 +55,11 @@ specified.\n\n --ignore-submodules[=<when>]::\n \tIgnore changes to submodules when looking for changes. <when> can be\n-\teither \"untracked\", \"dirty\" or \"all\", which is the default. When\n+\teither \"none\", \"untracked\", \"dirty\" or \"all\", which is the default.\n+\tUsing \"none\" will consider the submodule modified when it either contains\n+\tuntracked or modified files or its HEAD differs from the commit recorded\n+\tin the superproject and can be used to override any settings of the\n+\t'ignore' option in linkgit:git-config[1]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 8b8978a..392ce2b 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -68,11 +68,16 @@ static int match_stat_with_submodule(struct diff_options *diffopt,\n \t\t\t\t      unsigned ce_option, unsigned *dirty_submodule)\n {\n \tint changed = ce_match_stat(ce, st, ce_option);\n-\tif (S_ISGITLINK(ce->ce_mode)\n-\t    && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)\n-\t    && !DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)\n-\t    && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES))) {\n-\t\t*dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));\n+\tif (S_ISGITLINK(ce->ce_mode)) {\n+\t\tunsigned orig_flags = diffopt->flags;\n+\t\tif (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))\n+\t\t\tset_diffopt_flags_from_submodule_config(diffopt, ce->name);\n+\t\tif (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))\n+\t\t\tchanged = 0;\n+\t\telse if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)\n+\t\t    && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))\n+\t\t\t*dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));\n+\t\tdiffopt->flags = orig_flags;\n \t}\n \treturn changed;\n }\ndiff --git a/diff.c b/diff.c\nindex 782896d..bf6b9b1 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -141,6 +141,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n\n+\tif (!prefixcmp(var, \"submodule.\"))\n+\t\treturn parse_submodule_config_option(var, value);\n+\n \treturn git_color_default_config(var, value, cb);\n }\n\n@@ -3165,11 +3168,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n \t\tDIFF_OPT_SET(options, ALLOW_TEXTCONV);\n \telse if (!strcmp(arg, \"--no-textconv\"))\n \t\tDIFF_OPT_CLR(options, ALLOW_TEXTCONV);\n-\telse if (!strcmp(arg, \"--ignore-submodules\"))\n+\telse if (!strcmp(arg, \"--ignore-submodules\")) {\n+\t\tDIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(options, \"all\");\n-\telse if (!prefixcmp(arg, \"--ignore-submodules=\"))\n+\t} else if (!prefixcmp(arg, \"--ignore-submodules=\")) {\n+\t\tDIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(options, arg + 20);\n-\telse if (!strcmp(arg, \"--submodule\"))\n+\t} else if (!strcmp(arg, \"--submodule\"))\n \t\tDIFF_OPT_SET(options, SUBMODULE_LOG);\n \telse if (!prefixcmp(arg, \"--submodule=\")) {\n \t\tif (!strcmp(arg + 12, \"log\"))\n@@ -4102,6 +4107,24 @@ int diff_result_code(struct diff_options *opt, int status)\n \treturn result;\n }\n\n+/*\n+ * Shall changes to this submodule be ignored?\n+ *\n+ * Submodule changes can be configured to be ignored separately for each path,\n+ * but that configuration can be overridden from the command line.\n+ */\n+static int is_submodule_ignored(const char *path, struct diff_options *options)\n+{\n+\tint ignored = 0;\n+\tunsigned orig_flags = options->flags;\n+\tif (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))\n+\t\tset_diffopt_flags_from_submodule_config(options, path);\n+\tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES))\n+\t\tignored = 1;\n+\toptions->flags = orig_flags;\n+\treturn ignored;\n+}\n+\n void diff_addremove(struct diff_options *options,\n \t\t    int addremove, unsigned mode,\n \t\t    const unsigned char *sha1,\n@@ -4109,7 +4132,7 @@ void diff_addremove(struct diff_options *options,\n {\n \tstruct diff_filespec *one, *two;\n\n-\tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(mode))\n+\tif (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options))\n \t\treturn;\n\n \t/* This may look odd, but it is a preparation for\n@@ -4156,8 +4179,8 @@ void diff_change(struct diff_options *options,\n {\n \tstruct diff_filespec *one, *two;\n\n-\tif (DIFF_OPT_TST(options, IGNORE_SUBMODULES) && S_ISGITLINK(old_mode)\n-\t\t\t&& S_ISGITLINK(new_mode))\n+\tif (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&\n+\t    is_submodule_ignored(concatpath, options))\n \t\treturn;\n\n \tif (DIFF_OPT_TST(options, REVERSE_DIFF)) {\ndiff --git a/diff.h b/diff.h\nindex 063d10a..53ad345 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -77,6 +77,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)\n #define DIFF_OPT_DIRTY_SUBMODULES    (1 << 24)\n #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)\n #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)\n+#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)\n\n #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)\n #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)\ndiff --git a/submodule.c b/submodule.c\nindex 61cb6e2..ff28630 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -6,6 +6,10 @@\n #include \"revision.h\"\n #include \"run-command.h\"\n #include \"diffcore.h\"\n+#include \"string-list.h\"\n+\n+struct string_list config_name_for_path;\n+struct string_list config_ignore_for_name;\n\n static int add_submodule_odb(const char *path)\n {\n@@ -46,6 +50,57 @@ done:\n \treturn ret;\n }\n\n+void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n+\t\t\t\t\t     const char *path)\n+{\n+\tstruct string_list_item *path_option, *ignore_option;\n+\tpath_option = unsorted_string_list_lookup(&config_name_for_path, path);\n+\tif (path_option) {\n+\t\tignore_option = unsorted_string_list_lookup(&config_ignore_for_name, path_option->util);\n+\t\tif (ignore_option)\n+\t\t\thandle_ignore_submodules_arg(diffopt, ignore_option->util);\n+\t}\n+}\n+\n+int parse_submodule_config_option(const char *var, const char *value)\n+{\n+\tint len;\n+\tstruct string_list_item *config;\n+\tstruct strbuf submodname = STRBUF_INIT;\n+\n+\tvar += 10;\t\t/* Skip \"submodule.\" */\n+\n+\tlen = strlen(var);\n+\tif ((len > 5) && !strcmp(var + len - 5, \".path\")) {\n+\t\tstrbuf_add(&submodname, var, len - 5);\n+\t\tconfig = unsorted_string_list_lookup(&config_name_for_path, value);\n+\t\tif (config)\n+\t\t\tfree(config->util);\n+\t\telse\n+\t\t\tconfig = string_list_append(&config_name_for_path, xstrdup(value));\n+\t\tconfig->util = strbuf_detach(&submodname, NULL);\n+\t\tstrbuf_release(&submodname);\n+\t} else if ((len > 7) && !strcmp(var + len - 7, \".ignore\")) {\n+\t\tif (strcmp(value, \"untracked\") && strcmp(value, \"dirty\") &&\n+\t\t    strcmp(value, \"all\") && strcmp(value, \"none\")) {\n+\t\t\twarning(\"Invalid parameter \\\"%s\\\" for config option \\\"submodule.%s.ignore\\\"\", value, var);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\tstrbuf_add(&submodname, var, len - 7);\n+\t\tconfig = unsorted_string_list_lookup(&config_ignore_for_name, submodname.buf);\n+\t\tif (config)\n+\t\t\tfree(config->util);\n+\t\telse\n+\t\t\tconfig = string_list_append(&config_ignore_for_name,\n+\t\t\t\t\t\t    strbuf_detach(&submodname, NULL));\n+\t\tstrbuf_release(&submodname);\n+\t\tconfig->util = xstrdup(value);\n+\t\treturn 0;\n+\t}\n+\treturn 0;\n+}\n+\n void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\t\t\t  const char *arg)\n {\n@@ -55,7 +110,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt,\n \t\tDIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);\n \telse if (!strcmp(arg, \"dirty\"))\n \t\tDIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);\n-\telse\n+\telse if (strcmp(arg, \"none\"))\n \t\tdie(\"bad --ignore-submodules argument: %s\", arg);\n }\n\ndiff --git a/submodule.h b/submodule.h\nindex 6fd3bb4..185a5ce 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -3,6 +3,9 @@\n\n struct diff_options;\n\n+void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n+\t\tconst char *path);\n+int parse_submodule_config_option(const char *var, const char *value);\n void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n void show_submodule_summary(FILE *f, const char *path,\n \t\tunsigned char one[20], unsigned char two[20],\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 1bd8e5e..6836728 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -114,6 +114,31 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)'\n \t! test -s actual4\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' '\n+\tgit config submodule.subname.ignore none &&\n+\tgit config submodule.subname.path sub &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config submodule.subname.ignore all &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config submodule.subname.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual3.body &&\n+\tgit config submodule.subname.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit diff HEAD --ignore-submodules=none >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' '\n \t(\n \t\tcd sub &&\n@@ -146,6 +171,57 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n \t! test -s actual4\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.git/config]' '\n+\tgit config submodule.subname.ignore all &&\n+\tgit config submodule.subname.path sub &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config submodule.subname.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\t! test -s actual3 &&\n+\tgit config submodule.subname.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit diff --ignore-submodules=none HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n+test_expect_success 'git diff between submodule commits' '\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit diff --ignore-submodules=dirty HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit diff --ignore-submodules HEAD^..HEAD >actual &&\n+\t! test -s actual\n+'\n+\n+test_expect_success 'git diff between submodule commits [.git/config]' '\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config submodule.subname.ignore dirty &&\n+\tgit config submodule.subname.path sub &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config submodule.subname.ignore all &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\t! test -s actual &&\n+\tgit diff --ignore-submodules=dirty HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n test_expect_success 'git diff (empty submodule dir)' '\n \t: >empty &&\n \trm -rf sub/* sub/.git &&\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex a72fe3a..57bf2ee 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -808,24 +808,38 @@ test_expect_success POSIXPERM 'status succeeds in a read-only repository' '\n \t(exit $status)\n '\n\n+(cd sm && echo > bar && git add bar && git commit -q -m 'Add bar' && cd .. && git add sm)\n+new_head=$(cd sm && git rev-parse --short=7 --verify HEAD)\n+touch .gitmodules\n+\n cat > expect << EOF\n # On branch master\n+# Changes to be committed:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#\n+#\tmodified:   sm\n+#\n # Changed but not updated:\n #   (use \"git add <file>...\" to update what will be committed)\n #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n #\n #\tmodified:   dir1/modified\n #\n+# Submodule changes to be committed:\n+#\n+# * sm $head...$new_head (1):\n+#   > Add bar\n+#\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n #\texpect\n #\toutput\n #\tuntracked\n-no changes added to commit (use \"git add\" and/or \"git commit -a\")\n EOF\n\n test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' '\n@@ -834,19 +848,48 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un\n \ttest_cmp expect output\n '\n\n+test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '\n+\tgit config --add submodule.subname.ignore untracked &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' '\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n\n+test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '\n+\tgit config --add submodule.subname.ignore dirty &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' '\n \techo modified > sm/foo &&\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n\n+test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' '\n+\tgit config --add submodule.subname.ignore dirty &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n cat > expect << EOF\n # On branch master\n+# Changes to be committed:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#\n+#\tmodified:   sm\n+#\n # Changed but not updated:\n #   (use \"git add <file>...\" to update what will be committed)\n #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n@@ -855,16 +898,21 @@ cat > expect << EOF\n #\tmodified:   dir1/modified\n #\tmodified:   sm (modified content)\n #\n+# Submodule changes to be committed:\n+#\n+# * sm $head...$new_head (1):\n+#   > Add bar\n+#\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n #\texpect\n #\toutput\n #\tuntracked\n-no changes added to commit (use \"git add\" and/or \"git commit -a\")\n EOF\n\n test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules with modified content\" '\n@@ -872,10 +920,23 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules w\n \ttest_cmp expect output\n '\n\n+test_expect_success \".git/config ignore=untracked doesn't suppress submodules with modified content\" '\n+\tgit config --add submodule.subname.ignore untracked &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n head2=$(cd sm && git commit -q -m \"2nd commit\" foo && git rev-parse --short=7 --verify HEAD)\n\n cat > expect << EOF\n # On branch master\n+# Changes to be committed:\n+#   (use \"git reset HEAD <file>...\" to unstage)\n+#\n+#\tmodified:   sm\n+#\n # Changed but not updated:\n #   (use \"git add <file>...\" to update what will be committed)\n #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n@@ -883,21 +944,26 @@ cat > expect << EOF\n #\tmodified:   dir1/modified\n #\tmodified:   sm (new commits)\n #\n+# Submodule changes to be committed:\n+#\n+# * sm $head...$new_head (1):\n+#   > Add bar\n+#\n # Submodules changed but not updated:\n #\n-# * sm $head...$head2 (1):\n+# * sm $new_head...$head2 (1):\n #   > 2nd commit\n #\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n #\texpect\n #\toutput\n #\tuntracked\n-no changes added to commit (use \"git add\" and/or \"git commit -a\")\n EOF\n\n test_expect_success \"--ignore-submodules=untracked doesn't suppress submodule summary\" '\n@@ -905,11 +971,28 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodule su\n \ttest_cmp expect output\n '\n\n+test_expect_success \".git/config ignore=untracked doesn't suppress submodule summary\" '\n+\tgit config --add submodule.subname.ignore untracked &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n test_expect_success \"--ignore-submodules=dirty doesn't suppress submodule summary\" '\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n\n+test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\" '\n+\tgit config --add submodule.subname.ignore dirty &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n+\n cat > expect << EOF\n # On branch master\n # Changed but not updated:\n@@ -921,6 +1004,7 @@ cat > expect << EOF\n # Untracked files:\n #   (use \"git add <file>...\" to include in what will be committed)\n #\n+#\t.gitmodules\n #\tdir1/untracked\n #\tdir2/modified\n #\tdir2/untracked\n@@ -935,4 +1019,12 @@ test_expect_success \"--ignore-submodules=all suppresses submodule summary\" '\n \ttest_cmp expect output\n '\n\n+test_expect_failure '.git/config ignore=all suppresses submodule summary' '\n+\tgit config --add submodule.subname.ignore all &&\n+\tgit config --add submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config --remove-section submodule.subname\n+'\n+\n test_done\ndiff --git a/wt-status.c b/wt-status.c\nindex 2f9e33c..54b6b03 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -313,8 +313,10 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)\n \tDIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);\n \tif (!s->show_untracked_files)\n \t\tDIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);\n-\tif (s->ignore_submodule_arg)\n+\tif (s->ignore_submodule_arg) {\n+\t\tDIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);\n+    }\n \trev.diffopt.format_callback = wt_status_collect_changed_cb;\n \trev.diffopt.format_callback_data = s;\n \trev.prune_data = s->pathspec;\n@@ -331,8 +333,10 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \topt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;\n \tsetup_revisions(0, NULL, &rev, &opt);\n\n-\tif (s->ignore_submodule_arg)\n+\tif (s->ignore_submodule_arg) {\n+\t\tDIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);\n \t\thandle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);\n+\t}\n\n \trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = wt_status_collect_updated_cb;\n-- \n1.7.2.1.54.g6bed1\n"},{"id":"147265","messageId":"4C5B3DF0.2050505@web.de","threadId":"24531","inReplyTo":"4C5B3D36.1060902@web.de","subject":"[PATCH v2 2/2] Submodules: Use \"ignore\" settings from .gitmodules too for diff and status","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-08-05T22:40:48Z","receivedAt":"2010-08-05T22:40:48Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"The .gitmodules file is parsed for \"submodule.<name>.ignore\" entries\nbefore looking for them in .git/config. Thus settings found in .git/config\nwill override those from .gitmodules, thereby allowing the local developer\nto ignore settings given by the remote side while also letting upstream\nset defaults for those users who don't have special needs.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/config.txt       |    3 +\n Documentation/diff-options.txt |    2 +-\n Documentation/git-status.txt   |    2 +-\n Documentation/gitmodules.txt   |   15 +++++++\n builtin/commit.c               |    2 +\n builtin/diff-files.c           |    2 +\n builtin/diff-index.c           |    2 +\n builtin/diff-tree.c            |    2 +\n builtin/diff.c                 |    2 +\n submodule.c                    |   19 ++++++++\n submodule.h                    |    1 +\n t/t4027-diff-submodule.sh      |   76 +++++++++++++++++++++++++++++++++\n t/t7508-status.sh              |   91 ++++++++++++++++++++++++++++++++++++----\n 13 files changed, 209 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 06faa02..d97b986 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1756,6 +1756,9 @@ submodule.<name>.ignore::\n \tlet submodules with modified tracked files in their work tree show up.\n \tUsing \"none\" (the default when this option is not set) also shows\n \tsubmodules that have untracked files in their work tree as changed.\n+\tThis setting overrides any setting made in .gitmodules for this submodule,\n+\tboth settings can be overriden on the command line by using the\n+\t\"--ignore-submodule\" option.\n\n tar.umask::\n \tThis variable can be used to restrict the permission bits of\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 9cf7506..faa467b 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -334,7 +334,7 @@ endif::git-format-patch[]\n \tUsing \"none\" will consider the submodule modified when it either contains\n \tuntracked or modified files or its HEAD differs from the commit recorded\n \tin the superproject and can be used to override any settings of the\n-\t'ignore' option in linkgit:git-config[1]. When\n+\t'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/Documentation/git-status.txt b/Documentation/git-status.txt\nindex a7a5d79..dae190a 100644\n--- a/Documentation/git-status.txt\n+++ b/Documentation/git-status.txt\n@@ -59,7 +59,7 @@ specified.\n \tUsing \"none\" will consider the submodule modified when it either contains\n \tuntracked or modified files or its HEAD differs from the commit recorded\n \tin the superproject and can be used to override any settings of the\n-\t'ignore' option in linkgit:git-config[1]. When\n+\t'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When\n \t\"untracked\" is used submodules are not considered dirty when they only\n \tcontain untracked content (but they are still scanned for modified\n \tcontent). Using \"dirty\" ignores all changes to the work tree of submodules,\ndiff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt\nindex 72a13d1..8ae107d 100644\n--- a/Documentation/gitmodules.txt\n+++ b/Documentation/gitmodules.txt\n@@ -44,6 +44,21 @@ submodule.<name>.update::\n \tThis config option is overridden if 'git submodule update' is given\n \tthe '--merge' or '--rebase' options.\n\n+submodule.<name>.ignore::\n+\tDefines under what circumstances \"git status\" and the diff family show\n+\ta submodule as modified. When set to \"all\", it will never be considered\n+\tmodified, \"dirty\" will ignore all changes to the submodules work tree and\n+\ttakes only differences between the HEAD of the submodule and the commit\n+\trecorded in the superproject into account. \"untracked\" will additionally\n+\tlet submodules with modified tracked files in their work tree show up.\n+\tUsing \"none\" (the default when this option is not set) also shows\n+\tsubmodules that have untracked files in their work tree as changed.\n+\tIf this option is also present in the submodules entry in .git/config of\n+\tthe superproject, the setting there will override the one found in\n+\t.gitmodules.\n+\tBoth settings can be overriden on the command line by using the\n+\t\"--ignore-submodule\" option.\n+\n\n EXAMPLES\n --------\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 2bb30c0..269fa38 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -25,6 +25,7 @@\n #include \"rerere.h\"\n #include \"unpack-trees.h\"\n #include \"quote.h\"\n+#include \"submodule.h\"\n\n static const char * const builtin_commit_usage[] = {\n \t\"git commit [options] [--] <filepattern>...\",\n@@ -1073,6 +1074,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\tstatus_format = STATUS_FORMAT_PORCELAIN;\n\n \twt_status_prepare(&s);\n+\tgitmodules_config();\n \tgit_config(git_status_config, &s);\n \tin_merge = file_exists(git_path(\"MERGE_HEAD\"));\n \targc = parse_options(argc, argv, prefix,\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 5b64011..951c7c8 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -8,6 +8,7 @@\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n static const char diff_files_usage[] =\n \"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]\"\n@@ -20,6 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \tunsigned options = 0;\n\n \tinit_revisions(&rev, prefix);\n+\tgitmodules_config();\n \tgit_config(git_diff_basic_config, NULL); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n\ndiff --git a/builtin/diff-index.c b/builtin/diff-index.c\nindex 0483749..2eb32bd 100644\n--- a/builtin/diff-index.c\n+++ b/builtin/diff-index.c\n@@ -3,6 +3,7 @@\n #include \"commit.h\"\n #include \"revision.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n static const char diff_cache_usage[] =\n \"git diff-index [-m] [--cached] \"\n@@ -17,6 +18,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)\n \tint result;\n\n \tinit_revisions(&rev, prefix);\n+\tgitmodules_config();\n \tgit_config(git_diff_basic_config, NULL); /* no \"diff\" UI options */\n \trev.abbrev = 0;\n\ndiff --git a/builtin/diff-tree.c b/builtin/diff-tree.c\nindex 3c78bda..0d2a3e9 100644\n--- a/builtin/diff-tree.c\n+++ b/builtin/diff-tree.c\n@@ -3,6 +3,7 @@\n #include \"commit.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n static struct rev_info log_tree_opt;\n\n@@ -112,6 +113,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)\n \tint read_stdin = 0;\n\n \tinit_revisions(opt, prefix);\n+\tgitmodules_config();\n \tgit_config(git_diff_basic_config, NULL); /* no \"diff\" UI options */\n \topt->abbrev = 0;\n \topt->diff = 1;\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 89ae89c..a43d326 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -13,6 +13,7 @@\n #include \"revision.h\"\n #include \"log-tree.h\"\n #include \"builtin.h\"\n+#include \"submodule.h\"\n\n struct blobinfo {\n \tunsigned char sha1[20];\n@@ -279,6 +280,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t */\n\n \tprefix = setup_git_directory_gently(&nongit);\n+\tgitmodules_config();\n \tgit_config(git_diff_ui_config, NULL);\n\n \tif (diff_use_color_default == -1)\ndiff --git a/submodule.c b/submodule.c\nindex ff28630..9ebafc1 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -62,6 +62,25 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \t}\n }\n\n+static int submodule_config(const char *var, const char *value, void *cb)\n+{\n+\tif (!prefixcmp(var, \"submodule.\"))\n+\t\treturn parse_submodule_config_option(var, value);\n+\treturn 0;\n+}\n+\n+void gitmodules_config()\n+{\n+\tconst char *work_tree = get_git_work_tree();\n+\tif (work_tree) {\n+\t\tstruct strbuf gitmodules_path = STRBUF_INIT;\n+\t\tstrbuf_addstr(&gitmodules_path, work_tree);\n+\t\tstrbuf_addstr(&gitmodules_path, \"/.gitmodules\");\n+\t\tgit_config_from_file(submodule_config, gitmodules_path.buf, NULL);\n+\t\tstrbuf_release(&gitmodules_path);\n+\t}\n+}\n+\n int parse_submodule_config_option(const char *var, const char *value)\n {\n \tint len;\ndiff --git a/submodule.h b/submodule.h\nindex 185a5ce..8ac4037 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -5,6 +5,7 @@ struct diff_options;\n\n void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,\n \t\tconst char *path);\n+void gitmodules_config();\n int parse_submodule_config_option(const char *var, const char *value);\n void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);\n void show_submodule_summary(FILE *f, const char *path,\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 6836728..1bc6e77 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -139,6 +139,36 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \tgit config --remove-section submodule.subname\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config -f .gitmodules submodule.subname.ignore all &&\n+\tgit config -f .gitmodules submodule.subname.path sub &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual3.body &&\n+\tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit config submodule.subname.ignore none &&\n+\tgit config submodule.subname.path sub &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.subname &&\n+\tgit config --remove-section -f .gitmodules submodule.subname &&\n+\trm .gitmodules\n+'\n+\n test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' '\n \t(\n \t\tcd sub &&\n@@ -189,6 +219,28 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)\n \tgit config --remove-section submodule.subname\n '\n\n+test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore all &&\n+\tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit diff HEAD >actual2 &&\n+\t! test -s actual2 &&\n+\tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit diff HEAD >actual3 &&\n+\t! test -s actual3 &&\n+\tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit diff HEAD >actual4 &&\n+\t! test -s actual4 &&\n+\tgit config submodule.subname.ignore none &&\n+\tgit config submodule.subname.path sub &&\n+\tgit diff HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subprev $subprev-dirty &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --remove-section submodule.subname &&\n+\tgit config --remove-section -f .gitmodules submodule.subname &&\n+\trm .gitmodules\n+'\n+\n test_expect_success 'git diff between submodule commits' '\n \tgit diff HEAD^..HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n@@ -222,6 +274,30 @@ test_expect_success 'git diff between submodule commits [.git/config]' '\n \tgit config --remove-section submodule.subname\n '\n\n+test_expect_success 'git diff between submodule commits [.gitmodules]' '\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\ttest_cmp expect.body actual.body &&\n+\tgit config -f .gitmodules submodule.subname.ignore all &&\n+\tgit diff HEAD^..HEAD >actual &&\n+\t! test -s actual &&\n+\tgit config submodule.subname.ignore dirty &&\n+\tgit config submodule.subname.path sub &&\n+\tgit diff  HEAD^..HEAD >actual &&\n+\tsed -e \"1,/^@@/d\" actual >actual.body &&\n+\texpect_from_to >expect.body $subtip $subprev &&\n+\tgit config --remove-section submodule.subname &&\n+\tgit config --remove-section -f .gitmodules submodule.subname &&\n+\trm .gitmodules\n+'\n+\n test_expect_success 'git diff (empty submodule dir)' '\n \t: >empty &&\n \trm -rf sub/* sub/.git &&\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 57bf2ee..1aae762 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -848,12 +848,23 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un\n \ttest_cmp expect output\n '\n\n+test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n+\n test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config --remove-section -f .gitmodules submodule.subname\n '\n\n test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' '\n@@ -861,12 +872,23 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac\n \ttest_cmp expect output\n '\n\n+test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n+\n test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n '\n\n test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' '\n@@ -875,12 +897,23 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi\n \ttest_cmp expect output\n '\n\n+test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n+\n test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n '\n\n cat > expect << EOF\n@@ -920,12 +953,23 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules w\n \ttest_cmp expect output\n '\n\n+test_expect_success \".gitmodules ignore=untracked doesn't suppress submodules with modified content\" '\n+\tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n+\n test_expect_success \".git/config ignore=untracked doesn't suppress submodules with modified content\" '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n '\n\n head2=$(cd sm && git commit -q -m \"2nd commit\" foo && git rev-parse --short=7 --verify HEAD)\n@@ -971,28 +1015,48 @@ test_expect_success \"--ignore-submodules=untracked doesn't suppress submodule su\n \ttest_cmp expect output\n '\n\n+test_expect_success \".gitmodules ignore=untracked doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n+\n test_expect_success \".git/config ignore=untracked doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n '\n\n test_expect_success \"--ignore-submodules=dirty doesn't suppress submodule summary\" '\n \tgit status --ignore-submodules=dirty > output &&\n \ttest_cmp expect output\n '\n+test_expect_success \".gitmodules ignore=dirty doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n\n test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\" '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n '\n\n-\n cat > expect << EOF\n # On branch master\n # Changed but not updated:\n@@ -1019,12 +1083,23 @@ test_expect_success \"--ignore-submodules=all suppresses submodule summary\" '\n \ttest_cmp expect output\n '\n\n+test_expect_failure '.gitmodules ignore=all suppresses submodule summary' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore all &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit status > output &&\n+\ttest_cmp expect output &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n+'\n+\n test_expect_failure '.git/config ignore=all suppresses submodule summary' '\n+\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n+\tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit config --add submodule.subname.ignore all &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config -f .gitmodules  --remove-section submodule.subname\n '\n\n test_done\n-- \n1.7.2.1.54.g6bed1\n"},{"id":"147271","messageId":"4C5B48D3.6020402@web.de","threadId":"24531","inReplyTo":"4C5B0C13.6020809@web.de","subject":"[PATCH] Add tests for the diff.ignoreSubmodules config option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-08-05T23:27:15Z","receivedAt":"2010-08-05T23:27:15Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\nAm 05.08.2010 21:08, schrieb Jens Lehmann:\n> Am 05.08.2010 18:49, schrieb Junio C Hamano:\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>>> This commit introduces a global config setting to set a default\n>>> (porcelain) value for the --ignore-submodules option, keeping the\n>>> default at 'none'. It can be overridden by the submodule.*.ignore\n>>> setting and by the --ignore-submodules option.\n>>> ...\n>>> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>>> ---\n>>\n>> Nice, at least from a cursory look.  \n> \n> Yup, makes sense to me too.\n> \n> Acked-by: Jens Lehmann <Jens.Lehmann@web.de>\n\nAnd here are some test cases for this new option.\n\n t/t4027-diff-submodule.sh |   10 +++++++++-\n t/t7508-status.sh         |   12 ++++++++++--\n 2 files changed, 19 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 1bc6e77..d99814a 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -115,6 +115,9 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)'\n '\n\n test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.git/config]' '\n+\tgit config diff.ignoreSubmodules all &&\n+\tgit diff HEAD >actual &&\n+\t! test -s actual &&\n \tgit config submodule.subname.ignore none &&\n \tgit config submodule.subname.path sub &&\n \tgit diff HEAD >actual &&\n@@ -136,10 +139,14 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual.body &&\n-\tgit config --remove-section submodule.subname\n+\tgit config --remove-section submodule.subname &&\n+\tgit config --unset diff.ignoreSubmodules\n '\n\n test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' '\n+\tgit config diff.ignoreSubmodules dirty &&\n+\tgit diff HEAD >actual &&\n+\t! test -s actual &&\n \tgit config --add -f .gitmodules submodule.subname.ignore none &&\n \tgit config --add -f .gitmodules submodule.subname.path sub &&\n \tgit diff HEAD >actual &&\n@@ -166,6 +173,7 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \ttest_cmp expect.body actual.body &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n+\tgit config --unset diff.ignoreSubmodules &&\n \trm .gitmodules\n '\n\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 1aae762..9c14b85 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -849,11 +849,15 @@ test_expect_success '--ignore-submodules=untracked suppresses submodules with un\n '\n\n test_expect_success '.gitmodules ignore=untracked suppresses submodules with untracked content' '\n+\tgit config diff.ignoreSubmodules dirty &&\n+\tgit status >output &&\n+\ttest_cmp expect output &&\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules  --remove-section submodule.subname &&\n+\tgit config --unset diff.ignoreSubmodules\n '\n\n test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '\n@@ -873,11 +877,15 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with untrac\n '\n\n test_expect_success '.gitmodules ignore=dirty suppresses submodules with untracked content' '\n+\tgit config diff.ignoreSubmodules dirty &&\n+\tgit status >output &&\n+\t! test -s actual &&\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules  --remove-section submodule.subname &&\n+\tgit config --unset diff.ignoreSubmodules\n '\n\n test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '\n-- \n1.7.2.1.54.g6bed1\n"},{"id":"147272","messageId":"7vvd7obpy5.fsf@alter.siamese.dyndns.org","threadId":"24531","inReplyTo":"4C5B3D36.1060902@web.de","subject":"Re: [PATCH v2 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-08-05T23:27:30Z","receivedAt":"2010-08-05T23:27:30Z","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> Am 28.07.2010 23:35, schrieb Junio C Hamano:\n>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>> \n>>> The .gitmodules file is parsed for \"submodule.<name>.ignore\" entries\n>>> before looking for them in .git/config. Thus settings found in .git/config\n>>> will override those from .gitmodules,...\n>> \n>> Hmph.\n>> \n>> The value of \"submodule.<name>.path\" does not have to be \"<name>\".  There\n>> seems to be a bit of confusion here.\n>\n> Thanks for clearing up my confusion, this is v2 of this patch using the\n> path configured for the submodule instead of its name.\n\nHmph, I thought that it would make more sense to use <name> so that once\nthe user configures ignore in .git/config, it will persist across moving\nof the submodule in the superproject tree.  I wonder what others would\nthink.\n\nWill queue, anyway.\n\nThanks.\n"},{"id":"147273","messageId":"4C5B4E80.1070102@web.de","threadId":"24531","inReplyTo":"7vvd7obpy5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2010-08-05T23:51:28Z","receivedAt":"2010-08-05T23:51:28Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 06.08.2010 01:27, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> Am 28.07.2010 23:35, schrieb Junio C Hamano:\n>>> The value of \"submodule.<name>.path\" does not have to be \"<name>\".  There\n>>> seems to be a bit of confusion here.\n>>\n>> Thanks for clearing up my confusion, this is v2 of this patch using the\n>> path configured for the submodule instead of its name.\n> \n> Hmph, I thought that it would make more sense to use <name> so that once\n> the user configures ignore in .git/config, it will persist across moving\n> of the submodule in the superproject tree.  I wonder what others would\n> think.\n\nI think that is just what this patch does, it uses the\n\"config_name_for_path\" string_list to get the submodules <name> for the\npath to then look up what is configured for the \"ignore\" option under\nthat <name>. So the \"ignore\" option should survive renames, no? Or did\nI manage to confuse myself again?\n"},{"id":"147518","messageId":"7v7hjz7mhv.fsf@alter.siamese.dyndns.org","threadId":"24531","inReplyTo":"4C5B4E80.1070102@web.de","subject":"Re: [PATCH v2 0/2] Submodules: Add the new config option \"ignore\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-08-09T16:57:00Z","receivedAt":"2010-08-09T16:57:00Z","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> Am 06.08.2010 01:27, schrieb Junio C Hamano:\n>> Jens Lehmann <Jens.Lehmann@web.de> writes:\n>> \n>>> Am 28.07.2010 23:35, schrieb Junio C Hamano:\n>>>> The value of \"submodule.<name>.path\" does not have to be \"<name>\".  There\n>>>> seems to be a bit of confusion here.\n>>>\n>>> Thanks for clearing up my confusion, this is v2 of this patch using the\n>>> path configured for the submodule instead of its name.\n>> \n>> Hmph, I thought that it would make more sense to use <name> so that once\n>> the user configures ignore in .git/config, it will persist across moving\n>> of the submodule in the superproject tree.  I wonder what others would\n>> think.\n>\n> I think that is just what this patch does, it uses the ...\n\nYeah, what you said is all correct.  I just misread \"... this patch using\nthe path ... instead of its name\" to mean that the user-level interface is\nnow keying off of a path, but that is not what you meant.  You instead\nmeant that the name is used as the key and it used as if it is a path in\nthe previous round, but now it goes through name-to-path mapping.\n\nThanks.\n"},{"id":"147519","messageId":"7v1va77mhn.fsf@alter.siamese.dyndns.org","threadId":"24531","inReplyTo":"4C5B48D3.6020402@web.de","subject":"Re: [PATCH] Add tests for the diff.ignoreSubmodules config option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-08-09T16:57:08Z","receivedAt":"2010-08-09T16:57:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks, both.  Will queue.\n"}]}