mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* fix(worktree): remove a clean checkout that contains submodules Git refuses to remove any worktree with an initialized submodule unless --force is set, even when nothing is uncommitted. After that specific refusal, re-check the checkout including files inside the submodule and pass --force once. A dirty submodule still blocks the delete. A second --force is not added, because that would also clear a Git lock. * fix(worktree): offer Force Delete for a checkout Git refuses over submodules Drop the automatic --force retry. A forced removal deletes the submodule's repository under .git/worktrees/<id>/modules, including commits, local branches and stashes that were never pushed, and the parent's dirty check cannot see them (the retry #24602 removed for the same reason). Instead classify Git's "working trees containing submodules cannot be moved or removed" refusal as a new Force Delete reason, 'submodules', after the lock check and the force guard. The renderer classifies the error string, so older SSH and paired hosts get it too with no wire change. The toast, the delete dialog and the Space manager row show one plain warning naming what Force Delete would lose instead of Git's text. Keep --ignore-submodules=none in the pre-teardown dirty check so a user's ignore setting cannot hide submodule edits from it. Replace the retry test with one real-Git test: a clean checkout whose submodule holds a local-only commit is refused without --force, stays registered, keeps the commit, and its refusal classifies as 'submodules'. * fix(worktree): clarify the submodule Force Delete warning and hide View for it The warning now says Git deletes the workspace only with Force Delete, the submodule refusal no longer offers View (there are no changes to show), the real-Git test pins that Force Delete then succeeds, and a comment no longer describes the removed retry. * fix(worktree): name submodules when a changed submodule blocks the delete, and clear a stale delete toast With a commit inside a submodule that the parent has not recorded, the parent sees `M vendor`, so Orca's dirty check refused first with the generic "It has changed files". Force Delete then destroyed the never-pushed submodule commit without warning. On a dirty refusal the check now asks `git status --porcelain=v2` whether a changed entry is a submodule, and if so reports a refusal the app shows with the submodule Force Delete warning. The detail keeps the dirty sentence, so older apps still offer Force Delete. After the Space manager deleted a workspace (its row Force, or a later delete), the failure toast for that workspace stayed up and still offered Force Delete. A Space delete now dismisses it. * fix(worktree): warn about submodules on any refused delete of a checkout that has them Review found the warning still vanished when a submodule commit was already recorded and some other file was dirty: the parent's status shows no submodule change, yet Force Delete destroys the commit. The changed-files check now asks whether the checkout has a populated submodule (a .gitmodules path holding a .git, as Git's own refusal checks) instead of whether one changed. The refusal keeps the changed paths after the detail, and View stays available since there are changes to view. * test(worktree): mock the .gitmodules probe as missing in the preflight unit tests * refactor(worktree): attach the dirty-check status without a type assertion * fix(worktree): key the delete failure toast by host and worktree id A Space delete on one host must not dismiss another host's failure toast for a worktree with the same id. * fix(worktree): dismiss the failure toast by the store row's host after a Space row Force
40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
/**
|
|
* The text a failed Git invocation left behind, for the predicates that classify a
|
|
* failure by what Git said.
|
|
*
|
|
* Why all three streams and not just `message` + `stderr`: the errors Orca classifies
|
|
* do not all come straight out of `execFile`. Node puts Git's stderr in both `message`
|
|
* and `stderr`, but Orca also throws its own failures with the Git output on `stdout`
|
|
* (the removal dirty check attaches `git status --porcelain` output that way). Reading
|
|
* all three is what keeps the classifiers from disagreeing about the same error object.
|
|
*
|
|
* Against a real binary this reads no differently: Git emits every refusal this module
|
|
* classifies through `error()`/`die()`, i.e. stderr only, on 2.25 through 2.55.
|
|
*/
|
|
export function readGitCommandFailureText(error: unknown): string {
|
|
if (typeof error !== 'object' || error === null) {
|
|
return String(error)
|
|
}
|
|
const parts: string[] = []
|
|
for (const field of ['message', 'stderr', 'stdout'] as const) {
|
|
const value = (error as Record<string, unknown>)[field]
|
|
if (typeof value === 'string' && value) {
|
|
parts.push(value)
|
|
}
|
|
}
|
|
return parts.join('\n')
|
|
}
|
|
|
|
export function readGitCommandFailureStderr(error: unknown): string | null {
|
|
if (typeof error !== 'object' || error === null || !('stderr' in error)) {
|
|
return null
|
|
}
|
|
if (typeof error.stderr === 'string') {
|
|
return error.stderr
|
|
}
|
|
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(error.stderr)) {
|
|
return error.stderr.toString('utf8')
|
|
}
|
|
return null
|
|
}
|