Skip to content

Commit

Permalink
Show submodules as modified when they contain a dirty work tree
Browse files Browse the repository at this point in the history
Until now a submodule only then showed up as modified in the supermodule
when the last commit in the submodule differed from the one in the index
or the diffed against commit of the superproject. A dirty work tree
containing new untracked or modified files in a submodule was
undetectable when looking at it from the superproject.

Now git status and git diff (against the work tree) in the superproject
will also display submodules as modified when they contain untracked or
modified files, even if the compared ref matches the HEAD of the
submodule.

Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de>
Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jens Lehmann authored and Junio C Hamano committed Jan 17, 2010
1 parent 1f73566 commit ee6fc51
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 17 deletions.
8 changes: 6 additions & 2 deletions diff-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "cache-tree.h"
#include "unpack-trees.h"
#include "refs.h"
#include "submodule.h"

/*
* diff-files
Expand Down Expand Up @@ -159,7 +160,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 */
Expand All @@ -176,6 +177,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))
Expand Down Expand Up @@ -230,7 +233,8 @@ static int get_stat_data(struct cache_entry *ce,
return -1;
}
changed = ce_match_stat(ce, &st, 0);
if (changed) {
if (changed
|| (S_ISGITLINK(ce->ce_mode) && is_submodule_modified(ce->name))) {
mode = ce_mode_from_stat(ce, st.st_mode);
sha1 = null_sha1;
}
Expand Down
49 changes: 49 additions & 0 deletions submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "diff.h"
#include "commit.h"
#include "revision.h"
#include "run-command.h"

int add_submodule_odb(const char *path)
{
Expand Down Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions submodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
83 changes: 68 additions & 15 deletions t/t7506-status-submodule.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,87 @@ test_description='git status for submodule'
. ./test-lib.sh

test_expect_success 'setup' '
test_create_repo sub
cd sub &&
: >bar &&
git add bar &&
git commit -m " Add bar" &&
cd .. &&
git add sub &&
test_create_repo sub &&
(
cd sub &&
: >bar &&
git add bar &&
git commit -m " Add bar" &&
: >foo &&
git add foo &&
git commit -m " Add foo"
) &&
echo output > .gitignore &&
git add sub .gitignore &&
git commit -m "Add submodule sub"
'

test_expect_success 'status clean' '
git status |
grep "nothing to commit"
git status >output &&
grep "nothing to commit" output
'

test_expect_success 'commit --dry-run -a clean' '
git commit --dry-run -a |
grep "nothing to commit"
test_must_fail git commit --dry-run -a >output &&
grep "nothing to commit" output
'

test_expect_success 'status with modified file in submodule' '
(cd sub && git reset --hard) &&
echo "changed" >sub/foo &&
git status >output &&
grep "modified: sub" output
'

test_expect_success 'status with modified file in submodule (porcelain)' '
(cd sub && git reset --hard) &&
echo "changed" >sub/foo &&
git status --porcelain >output &&
diff output - <<-\EOF
M sub
EOF
'

test_expect_success 'status with added file in submodule' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status >output &&
grep "modified: sub" output
'

test_expect_success 'status with added file in submodule (porcelain)' '
(cd sub && git reset --hard && echo >foo && git add foo) &&
git status --porcelain >output &&
diff output - <<-\EOF
M sub
EOF
'

test_expect_success 'status with untracked file in submodule' '
(cd sub && git reset --hard) &&
echo "content" >sub/new-file &&
git status >output &&
grep "modified: sub" output
'

test_expect_success 'status with untracked file in submodule (porcelain)' '
git status --porcelain >output &&
diff output - <<-\EOF
M sub
EOF
'

test_expect_success 'rm submodule contents' '
rm -rf sub/* sub/.git
'

test_expect_success 'status clean (empty submodule dir)' '
git status |
grep "nothing to commit"
git status >output &&
grep "nothing to commit" output
'

test_expect_success 'status -a clean (empty submodule dir)' '
git commit --dry-run -a |
grep "nothing to commit"
test_must_fail git commit --dry-run -a >output &&
grep "nothing to commit" output
'

test_done

0 comments on commit ee6fc51

Please sign in to comment.