Skip to content

git status renders a fully staged deletion as DD (porcelain's unmerged both-deleted conflict code) instead of D  #56

Description

@rajpreetcodes

Describe the bug

workspace.git.cli(["status", "--short"]) (and --porcelain / --porcelain=v2, and the worker-shell git command) reports a fully staged deletion with worktree code D, producing DD <path>. In porcelain v1, DD specifically means an unmerged "both deleted" merge conflict; in porcelain v2, DD on a 1 line is not a producible state at all (unmerged entries use u lines).

Cause: packages/computer/src/git/status.ts:111, first branch of worktreeCode:

if (workdir === 0 && stage === 0 && head === 1) return "D";

For the status-matrix row [path, 1, 0, 0] (present in HEAD, absent from workdir, absent from index) the workdir matches the index (the deletion is fully staged), so Y (workdir vs index) must be a space. The rendered forms come out of formatShort / formatPorcelainV1 (status.ts:152-173) and formatPorcelainV2 (status.ts:127-144).

The existing suite covers D (worktree delete, unstaged) but never the staged-deletion row [path,1,0,0].

Expected behavior

Real git, for git rm f && git status --porcelain: D f (X=D, Y=space).

Steps to reproduce

Same harness as packages/computer/src/git/status.test.ts: commit gone.txt, unlink it from the worktree, stage the deletion via the package's own git add -A path (addWith({ all: true }) in staging.ts), then run statusWith. Actual output:

statusMatrix: [["gone.txt",1,0,0]]        <- in HEAD, absent workdir, absent index
entries:  [{"path":"gone.txt","index":"D","worktree":"D"}]
short:    "DD gone.txt\n"
v1:       "DD gone.txt\n"
v2:       "1 DD gone.txt\n"

Expected: "D gone.txt\n" and {index:"D", worktree:" "}.

Impact

Any staged deletion (git rm, git add -A after a delete, commit -a flows) is misreported to porcelain parsers and to agents reading git status as a merge conflict. An agent driving the workspace via the shell backend will try to "resolve" conflicts that don't exist.

Proposed fix

In worktreeCode, the head === 1 && workdir === 0 && stage === 0 row should return " ", leaving the second branch (workdir === 0 && stage > 0, deletion not yet staged) as the only producer of Y=D. One-line change; add a matrix-row test for [p,1,0,0] asserting {index:"D", worktree:" "}.

Environment

  • cloudflare/computer at 76d9e75 (current main), local checkout
  • npx vitest run baseline in packages/computer: 897/897 pass before adding the repro
  • Node v22.18.0, Windows 11 (platform-independent)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions