diff --git a/diff-lib.c b/diff-lib.c
index 1c7e652..6918920 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -159,7 +159,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
continue;
}
- if (ce_uptodate(ce) || ce_skip_worktree(ce))
+ if ((ce_uptodate(ce) && !S_ISGITLINK(ce->ce_mode)) || ce_skip_worktree(ce))
continue;
/* If CE_VALID is set, don't look at workdir for file removal */
@@ -176,6 +176,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
continue;
}
changed = ce_match_stat(ce, &st, ce_option);
+ if (S_ISGITLINK(ce->ce_mode) && !changed)
+ changed = is_submodule_modified(ce->name);
if (!changed) {
ce_mark_uptodate(ce);
if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))diff --git a/submodule.c b/submodule.c
index 86aad65..3f851de 100644
--- a/submodule.c
+++ b/submodule.c
@@ -4,6 +4,7 @@
#include "diff.h"
#include "commit.h"
#include "revision.h"
+#include "run-command.h"
int add_submodule_odb(const char *path)
{@@ -112,3 +113,51 @@ void show_submodule_summary(FILE *f, const char *path,
}
strbuf_release(&sb);
}
+
+int is_submodule_modified(const char *path)
+{
+ int len;
+ struct child_process cp;
+ const char *argv[] = {
+ "status",
+ "--porcelain",
+ NULL,
+ };
+ char *env[3];
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addf(&buf, "%s/.git/", path);
+ if (!is_directory(buf.buf)) {
+ strbuf_release(&buf);
+ /* The submodule is not checked out, so it is not modified */
+ return 0;
+
+ }
+ strbuf_reset(&buf);
+
+ strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
+ env[0] = strbuf_detach(&buf, NULL);
+ strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
+ env[1] = strbuf_detach(&buf, NULL);
+ env[2] = NULL;
+
+ memset(&cp, 0, sizeof(cp));
+ cp.argv = argv;
+ cp.env = (const char *const *)env;
+ cp.git_cmd = 1;
+ cp.no_stdin = 1;
+ cp.out = -1;
+ if (start_command(&cp))
+ die("Could not run git status --porcelain");
+
+ len = strbuf_read(&buf, cp.out, 1024);
+ close(cp.out);
+
+ if (finish_command(&cp))
+ die("git status --porcelain failed");
+
+ free(env[0]);
+ free(env[1]);
+ strbuf_release(&buf);
+ return len != 0;
+}diff --git a/submodule.h b/submodule.h
index 4c0269d..0773121 100644
--- a/submodule.h
+++ b/submodule.h
@@ -4,5 +4,6 @@
void show_submodule_summary(FILE *f, const char *path,
unsigned char one[20], unsigned char two[20],
const char *del, const char *add, const char *reset);
+int is_submodule_modified(const char *path);
#endif
diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index 3ca17ab..47e205b 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -10,8 +10,12 @@ test_expect_success 'setup' '
: >bar &&
git add bar &&
git commit -m " Add bar" &&
+ : >foo &&
+ git add foo &&
+ git commit -m " Add foo" &&
cd .. &&
- git add sub &&
+ echo output > .gitignore
+ git add sub .gitignore &&
git commit -m "Add submodule sub"
'
@@ -23,6 +27,31 @@ test_expect_success 'commit --dry-run -a clean' '
git commit --dry-run -a |
grep "nothing to commit"
'
+
+echo "changed" > sub/foo
+test_expect_success 'status with modified file in submodule' '
+ git status | grep "modified: sub"
+'
+test_expect_success 'status with modified file in submodule (porcelain)' '
+ git status --porcelain >output &&
+ diff output - <<-EOF
+ M sub
+EOF
+'
+(cd sub && git checkout foo)
+
+echo "content" > sub/new-file
+test_expect_success 'status with untracked file in submodule' '
+ git status | grep "modified: sub"
+'
+test_expect_success 'status with untracked file in submodule (porcelain)' '
+ git status --porcelain >output &&
+ diff output - <<-EOF
+ M sub
+EOF
+'
+rm sub/new-file
+
test_expect_success 'rm submodule contents' '
rm -rf sub/* sub/.git
'
--
1.6.6.203.g28a8ba.dirty