Skip to content

Commit 7f79ce5

Browse files
DeusDatahalindrome
andcommitted
Fix watcher: detect dirty state inside git submodules
The watcher's git_is_dirty() only ran git status on the parent repo, missing uncommitted changes inside submodules. Add a second check via git submodule foreach --recursive (portable, works on Apple Git which lacks --recurse-submodules). Fixes #71 Co-Authored-By: halindrome <halindrome@users.noreply.github.com>
1 parent dbab4d3 commit 7f79ce5

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

src/watcher/watcher.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ static int git_head(const char *root_path, char *out, size_t out_size) {
122122
return CBM_NOT_FOUND;
123123
}
124124

125-
/* Returns true if working tree has changes (modified, untracked, etc.) */
125+
/* Returns true if working tree has changes (modified, untracked, etc.).
126+
* Also checks submodules via `git submodule foreach` to detect uncommitted
127+
* changes inside submodules that `git status` alone would not report. */
126128
static bool git_is_dirty(const char *root_path) {
127129
char cmd[CBM_SZ_1K];
128130
snprintf(cmd, sizeof(cmd),
@@ -137,7 +139,33 @@ static bool git_is_dirty(const char *root_path) {
137139
char line[CBM_SZ_256];
138140
bool dirty = false;
139141
if (fgets(line, sizeof(line), fp)) {
140-
/* Any output means changes */
142+
size_t len = strlen(line);
143+
while (len > 0 && (line[len - SKIP_ONE] == '\n' || line[len - SKIP_ONE] == '\r')) {
144+
line[--len] = '\0';
145+
}
146+
if (len > 0) {
147+
dirty = true;
148+
}
149+
}
150+
cbm_pclose(fp);
151+
152+
if (dirty) {
153+
return true;
154+
}
155+
156+
/* Check submodules: uncommitted changes inside a submodule are invisible
157+
* to the parent's git status. Use `git submodule foreach` as a portable
158+
* fallback (Apple Git lacks --recurse-submodules). */
159+
snprintf(cmd, sizeof(cmd),
160+
"git --no-optional-locks -C '%s' submodule foreach --quiet --recursive "
161+
"'git status --porcelain --untracked-files=normal 2>/dev/null' "
162+
"2>/dev/null",
163+
root_path);
164+
fp = cbm_popen(cmd, "r");
165+
if (!fp) {
166+
return false;
167+
}
168+
if (fgets(line, sizeof(line), fp)) {
141169
size_t len = strlen(line);
142170
while (len > 0 && (line[len - SKIP_ONE] == '\n' || line[len - SKIP_ONE] == '\r')) {
143171
line[--len] = '\0';

0 commit comments

Comments
 (0)