feat(submodules): add submodule management and recursive clone

Add a new backend module to manage Git submodules (list, initialize/update,
stage, sync, add) and expose Tauri commands (list_submodules,
submodule_action, add_submodule). The implementation enforces safe relative
paths, a maximum nesting depth, and guards (dirty/conflicted checks and
initialization/no-op semantics) to avoid unsafe operations.

Refactor clone logic to a testable run_git_clone_command and enable
automatic initialization of submodules during clone by passing
--recurse-submodules. Also disallow certain submodule-related custom clone
flags so callers cannot override this behaviour.

Update README with a Submodules section and add frontend components and types
to surface submodule UI (dialogs, toolbar badge). Unit tests were added for
submodule discovery, initialization/update semantics, and recursive clone
behavior.
This commit is contained in:
2026-09-16 22:31:14 +02:00
parent f0ff1914c9
commit 66c85321ea
11 changed files with 1084 additions and 3 deletions
+11
View File
@@ -32,6 +32,7 @@ import type {
GitStatus,
GitTag,
GitWorktree,
GitSubmodule,
PatchApplyAction,
RepositoryBundle,
StoredCredential,
@@ -732,3 +733,13 @@ export function createIntegrationIssue(provider: GitIntegrationProvider, baseUrl
export function pullRequestAiGenerate(path: string, remote: string, sourceBranch: string, targetBranch: string, options: { provider: string; model: string; apiKey?: string; baseUrl?: string; language: string }): Promise<{title: string; description: string}> {
return invoke("pull_request_ai_generate", { path, remote, sourceBranch, targetBranch, ...options });
}
export function listSubmodules(path: string, recursive = true): Promise<GitSubmodule[]> {
return invoke("list_submodules", { path, recursive });
}
export function addSubmodule(path: string, url: string, destination: string, branch?: string): Promise<void> {
return invoke("add_submodule", { path, url, destination, branch: branch || null });
}
export function submoduleAction(path: string, modulePath: string, action: "update" | "stage" | "sync" | "initialize", recursive: boolean): Promise<void> {
return invoke("submodule_action", { path, modulePath, action, recursive });
}