feat(git): view submodule working-tree changes in the Git panel

Recurse into dirty submodules when building the Git status so their
modified and untracked files appear as full-path entries, and add a
commit-pointer entry (with short SHAs) only when the recorded commit
actually moved. Route diffs whose path falls inside a submodule to run
in that submodule's working tree so real per-file diffs are shown.

The changed-file list groups these under the submodule: tree view keeps
the nested structure and marks the submodule root with a badge, list
view flattens them into one expandable group pinned above the ordinary
files. Depth 1 only; ignored files are excluded; the panel stays
read-only.

Covered by client tree/list-grouping tests, parser tests, and a
server test that drives a real temporary repository and submodule.
This commit is contained in:
lzr
2026-07-22 21:35:06 +08:00
parent 8a5aaf93a1
commit dd435cb1b0
12 changed files with 610 additions and 56 deletions
+9
View File
@@ -681,6 +681,10 @@ export interface GitStatusFile {
oldPath?: string;
index: GitFileState;
workingTree: GitFileState;
// Set only on a submodule commit-pointer entry (path equals the submodule's
// superproject-relative path). Short SHAs of the recorded and current commit.
submoduleFromCommit?: string;
submoduleToCommit?: string;
}
export interface GitStatusResponse {
@@ -691,6 +695,11 @@ export interface GitStatusResponse {
ahead?: number;
behind?: number;
files: GitStatusFile[];
// Superproject-relative paths of submodules that carry a change. Files inside
// a submodule appear in `files` under `<submodule>/<inner path>`; the client
// uses this list to group and label them and to distinguish a submodule root
// from an ordinary directory with the same name.
submodules: string[];
}
export interface GitDiffResponse {