Merge branch 'sb/submodule-short-status'
The output from "git status --short" has been extended to show various kinds of dirtyness in submodules differently; instead of to "M" for modified, 'm' and '?' can be shown to signal changes only to the working tree of the submodule but not the commit that is checked out. * sb/submodule-short-status: submodule.c: correctly handle nested submodules in is_submodule_modified short status: improve reporting for submodule changes submodule.c: stricter checking for submodules in is_submodule_modified submodule.c: port is_submodule_modified to use porcelain 2 submodule.c: convert is_submodule_modified to use strbuf_getwholeline submodule.c: factor out early loop termination in is_submodule_modified submodule.c: use argv_array in is_submodule_modified
This commit is contained in:
81
submodule.c
81
submodule.c
@ -1112,67 +1112,78 @@ out:
|
||||
|
||||
unsigned is_submodule_modified(const char *path, int ignore_untracked)
|
||||
{
|
||||
ssize_t len;
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
const char *argv[] = {
|
||||
"status",
|
||||
"--porcelain",
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
FILE *fp;
|
||||
unsigned dirty_submodule = 0;
|
||||
const char *line, *next_line;
|
||||
const char *git_dir;
|
||||
int ignore_cp_exit_code = 0;
|
||||
|
||||
strbuf_addf(&buf, "%s/.git", path);
|
||||
git_dir = read_gitfile(buf.buf);
|
||||
if (!git_dir)
|
||||
git_dir = buf.buf;
|
||||
if (!is_directory(git_dir)) {
|
||||
if (!is_git_directory(git_dir)) {
|
||||
if (is_directory(git_dir))
|
||||
die(_("'%s' not recognized as a git repository"), git_dir);
|
||||
strbuf_release(&buf);
|
||||
/* The submodule is not checked out, so it is not modified */
|
||||
return 0;
|
||||
|
||||
}
|
||||
strbuf_reset(&buf);
|
||||
|
||||
argv_array_pushl(&cp.args, "status", "--porcelain=2", NULL);
|
||||
if (ignore_untracked)
|
||||
argv[2] = "-uno";
|
||||
argv_array_push(&cp.args, "-uno");
|
||||
|
||||
cp.argv = argv;
|
||||
prepare_submodule_repo_env(&cp.env_array);
|
||||
cp.git_cmd = 1;
|
||||
cp.no_stdin = 1;
|
||||
cp.out = -1;
|
||||
cp.dir = path;
|
||||
if (start_command(&cp))
|
||||
die("Could not run 'git status --porcelain' in submodule %s", path);
|
||||
die("Could not run 'git status --porcelain=2' in submodule %s", path);
|
||||
|
||||
len = strbuf_read(&buf, cp.out, 1024);
|
||||
line = buf.buf;
|
||||
while (len > 2) {
|
||||
if ((line[0] == '?') && (line[1] == '?')) {
|
||||
fp = xfdopen(cp.out, "r");
|
||||
while (strbuf_getwholeline(&buf, fp, '\n') != EOF) {
|
||||
/* regular untracked files */
|
||||
if (buf.buf[0] == '?')
|
||||
dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
|
||||
if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
|
||||
break;
|
||||
} else {
|
||||
dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
|
||||
if (ignore_untracked ||
|
||||
(dirty_submodule & DIRTY_SUBMODULE_UNTRACKED))
|
||||
break;
|
||||
}
|
||||
next_line = strchr(line, '\n');
|
||||
if (!next_line)
|
||||
break;
|
||||
next_line++;
|
||||
len -= (next_line - line);
|
||||
line = next_line;
|
||||
}
|
||||
close(cp.out);
|
||||
|
||||
if (finish_command(&cp))
|
||||
die("'git status --porcelain' failed in submodule %s", path);
|
||||
if (buf.buf[0] == 'u' ||
|
||||
buf.buf[0] == '1' ||
|
||||
buf.buf[0] == '2') {
|
||||
/* T = line type, XY = status, SSSS = submodule state */
|
||||
if (buf.len < strlen("T XY SSSS"))
|
||||
die("BUG: invalid status --porcelain=2 line %s",
|
||||
buf.buf);
|
||||
|
||||
if (buf.buf[5] == 'S' && buf.buf[8] == 'U')
|
||||
/* nested untracked file */
|
||||
dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
|
||||
|
||||
if (buf.buf[0] == 'u' ||
|
||||
buf.buf[0] == '2' ||
|
||||
memcmp(buf.buf + 5, "S..U", 4))
|
||||
/* other change */
|
||||
dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
|
||||
}
|
||||
|
||||
if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) &&
|
||||
((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ||
|
||||
ignore_untracked)) {
|
||||
/*
|
||||
* We're not interested in any further information from
|
||||
* the child any more, neither output nor its exit code.
|
||||
*/
|
||||
ignore_cp_exit_code = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (finish_command(&cp) && !ignore_cp_exit_code)
|
||||
die("'git status --porcelain=2' failed in submodule %s", path);
|
||||
|
||||
strbuf_release(&buf);
|
||||
return dirty_submodule;
|
||||
|
||||
Reference in New Issue
Block a user