Stefan Beller wrote: > When a nested submodule has untracked files, it would be reported as > "modified submodule" in the superproject, because submodules are not > parsed correctly in is_submodule_modified as they are bucketed into > the modified pile as "they are not an untracked file". > > Signed-off-by: Stefan Beller <sbeller@xxxxxxxxxx> > --- > submodule.c | 16 ++++++++++++++-- > t/t3600-rm.sh | 2 +- > t/t7506-status-submodule.sh | 2 +- > 3 files changed, 16 insertions(+), 4 deletions(-) > > diff --git a/submodule.c b/submodule.c > index 467f1de763..ec7e9b1b06 100644 > --- a/submodule.c > +++ b/submodule.c > @@ -1078,8 +1078,20 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) > /* regular untracked files */ > if (buf.buf[0] == '?') > dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; > - else > - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; > + > + /* regular unmerged and renamed files */ > + if (buf.buf[0] == 'u' || > + buf.buf[0] == '1' || > + buf.buf[0] == '2') { > + if (buf.buf[5] == 'S') { Can this overflow the buffer? Submodule state is supposed to be 4 characters, so could do /* * T XY SSSS: * T = line type, XY = status, SSSS = submodule state */ if (buf.len < 1 + 1 + 2 + 1 + 4) die("BUG: invalid status --porcelain=2 line %s", buf.buf); if (buf.buf[5] == 'S' && buf.buf[8] == 'U') /* untracked file */ dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; if (memcmp(buf.buf + 5, "S..U", 4)) /* other change */ dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; } > + /* nested submodule handling */ > + if (buf.buf[6] == 'C' || buf.buf[7] == 'M') > + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; > + if (buf.buf[8] == 'U') > + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; > + } else > + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; > + } I get lost in these cases. What does it mean if we see S..., for example? As an example, if I am understanding correctly, before this patch, if I have a submodule-in-submodule: $ find . -name .git .git sub/.git sub/subsub/.git and I put a stray file in the sub-sub module: $ echo stray-file >sub/subsub/x.o then status --porcelain=2 tells me that sub is modified: $ git status --porcelain=2 1 .M S.M. [...] sub What should it say after the patch? Is the XY field ".." or ".M"? Some tests covering these cases with --porcelain=2 and a brief mention in documentation may help. Thanks, Jonathan diff --git i/submodule.c w/submodule.c index ec7e9b1b06..aec1b2cdca 100644 --- i/submodule.c +++ w/submodule.c @@ -1083,13 +1083,18 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) if (buf.buf[0] == 'u' || buf.buf[0] == '1' || buf.buf[0] == '2') { - if (buf.buf[5] == 'S') { - /* nested submodule handling */ - if (buf.buf[6] == 'C' || buf.buf[7] == 'M') - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; - if (buf.buf[8] == 'U') - dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; - } else + /* + * T XY SSSS: + * T = line type, XY = status, SSSS = submodule state + */ + if (buf.len < 1 + 1 + 2 + 1 + 4) + die("BUG: invalid status --porcelain=2 line %s", + buf.buf); + if (buf.buf[5] == 'S' && buf.buf[8] == 'U') + /* untracked file */ + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED; + if (memcmp(buf.buf + 5, "S..U", 4)) + /* other change */ dirty_submodule |= DIRTY_SUBMODULE_MODIFIED; }