git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Confusing behavior with ignored submodules and `git commit -a`

From
Michael Forney <mforney@mforney.org>
Date
Nov 15, 2018, 21:33 UTC
Message-ID
<CAGw6cBvLGZKcf1em0d47hcCuKau2QVbX4wfb0yN+m4umbNLaRg@mail.gmail.com>
In-Reply-To
<CAGZ79kYiWnciitwTQCXR5bHOj7nhHWr40xBiS5sPCH5W4_yQ5w@mail.gmail.com>
On 2018-11-15, Stefan Beller <sbeller@google.com> wrote:
Show 22 quoted lines
> On Wed, Nov 14, 2018 at 10:05 PM Michael Forney <mforney@mforney.org>
> wrote:
>> Looking at ff6f1f564c, I don't really see anything that might be
>> related to git-add, git-reset, or git-diff, so I'm guessing that this
>> only worked before because the submodule config wasn't getting loaded
>> during `git add` or `git reset`. Now that the config is loaded
>> automatically, submodule.<name>.ignore started taking effect where it
>> shouldn't.
>>
>> Unfortunately, this doesn't really get me much closer to finding a fix.
>
> Maybe selectively unloading or overwriting the config?
>
> Or we can change is_submodule_ignored() in diff.c
> to be only applied selectively whether we are running the
> right command? For this approach we'd have to figure out the
> set of commands to which the ignore config should apply or
> not (and come up with a more concise documentation then)
>
> This approach sounds appealing to me as it would cover
> new commands as well and we'd only have a central point
> where the decision for ignoring is made.

Well, currently the submodule config can be disabled in diff_flags by setting override_submodule_config=1. However, I'm thinking it may be simpler to selectively *enable* the submodule config in diff_flags where it is needed instead of disabling it everywhere else (i.e. use_submodule_config instead of override_submodule_config).

I'm also starting to see why this is tricky. The only difference that diff.c:run_diff_files sees between `git add inner` and `git add --all` is whether the index entry matched the pathspec exactly or not.

Here is a work-in-progress diff that seems to have the correct behavior in all cases I tried. Can you think of any cases that it breaks? I'm not quite sure of the consequences of having diff_change and diff_addremove always ignore the submodule config; git-diff and git-status still seem to work correctly.

diff --git a/builtin/add.c b/builtin/add.c
index f65c17229..9902f7742 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -117,7 +117,6 @@ int add_files_to_cache(const char *prefix,
 	rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
 	rev.diffopt.format_callback = update_callback;
 	rev.diffopt.format_callback_data = &data;
-	rev.diffopt.flags.override_submodule_config = 1;
 	rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
 	run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 	clear_pathspec(&rev.prune_data);
diff --git a/diff-lib.c b/diff-lib.c
index 83fce5151..fbb048cca 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -68,12 +68,13 @@ static int check_removed(const struct cache_entry
*ce, struct stat *st)
 static int match_stat_with_submodule(struct diff_options *diffopt,
 				     const struct cache_entry *ce,
 				     struct stat *st, unsigned ce_option,
-				     unsigned *dirty_submodule)
+				     unsigned *dirty_submodule,
+				     int exact)
 {
 	int changed = ie_match_stat(diffopt->repo->index, ce, st, ce_option);
 	if (S_ISGITLINK(ce->ce_mode)) {
 		struct diff_flags orig_flags = diffopt->flags;
-		if (!diffopt->flags.override_submodule_config)
+		if (!diffopt->flags.override_submodule_config && !exact)
 			set_diffopt_flags_from_submodule_config(diffopt, ce->name);
 		if (diffopt->flags.ignore_submodules)
 			changed = 0;
@@ -88,7 +89,7 @@ static int match_stat_with_submodule(struct
diff_options *diffopt,

 int run_diff_files(struct rev_info *revs, unsigned int option)
 {
-	int entries, i;
+	int entries, i, matched;
 	int diff_unmerged_stage = revs->max_count;
 	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
 			      ? CE_MATCH_RACY_IS_DIRTY : 0);
@@ -110,7 +111,8 @@ int run_diff_files(struct rev_info *revs, unsigned
int option)
 		if (diff_can_quit_early(&revs->diffopt))
 			break;

-		if (!ce_path_match(istate, ce, &revs->prune_data, NULL))
+		matched = ce_path_match(istate, ce, &revs->prune_data, NULL);
+		if (!matched)
 			continue;

 		if (ce_stage(ce)) {
@@ -226,7 +228,8 @@ int run_diff_files(struct rev_info *revs, unsigned
int option)
 			}

 			changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
-							    ce_option, &dirty_submodule);
+							    ce_option, &dirty_submodule,
+							    matched == MATCHED_EXACTLY);
 			newmode = ce_mode_from_stat(ce, st.st_mode);
 		}

@@ -292,7 +295,7 @@ static int get_stat_data(const struct cache_entry *ce,
 			return -1;
 		}
 		changed = match_stat_with_submodule(diffopt, ce, &st,
-						    0, dirty_submodule);
+						    0, dirty_submodule, 0);
 		if (changed) {
 			mode = ce_mode_from_stat(ce, st.st_mode);
 			oid = &null_oid;
diff --git a/diff.c b/diff.c
index e38d1ecaf..73dc75286 100644
--- a/diff.c
+++ b/diff.c
@@ -6209,24 +6209,6 @@ int diff_can_quit_early(struct diff_options *opt)
 		opt->flags.has_changes);
 }

-/*
- * Shall changes to this submodule be ignored?
- *
- * Submodule changes can be configured to be ignored separately for each path,
- * but that configuration can be overridden from the command line.
- */
-static int is_submodule_ignored(const char *path, struct diff_options *options)
-{
-	int ignored = 0;
-	struct diff_flags orig_flags = options->flags;
-	if (!options->flags.override_submodule_config)
-		set_diffopt_flags_from_submodule_config(options, path);
-	if (options->flags.ignore_submodules)
-		ignored = 1;
-	options->flags = orig_flags;
-	return ignored;
-}
-
 void diff_addremove(struct diff_options *options,
 		    int addremove, unsigned mode,
 		    const struct object_id *oid,
@@ -6235,7 +6217,7 @@ void diff_addremove(struct diff_options *options,
 {
 	struct diff_filespec *one, *two;

-	if (S_ISGITLINK(mode) && is_submodule_ignored(concatpath, options))
+	if (S_ISGITLINK(mode) && options->flags.ignore_submodules)
 		return;

 	/* This may look odd, but it is a preparation for
@@ -6285,7 +6267,7 @@ void diff_change(struct diff_options *options,
 	struct diff_filepair *p;

 	if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
-	    is_submodule_ignored(concatpath, options))
+	    options->flags.ignore_submodules)
 		return;

 	if (options->flags.reverse_diff) {
Previous: Stefan BellerNext: Michael Forney
Message 7 of 12 in “Confusing behavior with ignored submodules and `git commit -a`”
  1. Michael ForneyMar 17, 2018
  2. Michael ForneyOct 25, 2018
  3. Stefan BellerOct 25, 2018
  4. Michael ForneyNov 15, 2018
  5. Michael ForneyNov 15, 2018
  6. Stefan BellerNov 15, 2018
  7. Michael ForneyNov 15, 2018
  8. Michael ForneyNov 15, 2018
  9. Stefan BellerNov 15, 2018
  10. Michael ForneyNov 16, 2018
  11. Stefan BellerNov 27, 2018
  12. Stefan BellerNov 15, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.