feat(lanes): stage/undo one hunk at a time, sticky review file headers
Review and the single-file view gain per-hunk Stage and Undo (stage-hunk / discard-hunk: the hunk is named by its @@ line and re-matched against a fresh diff, then git apply --cached / -R; undo needs confirm: true and two clicks). Each review file header stays pinned while its diff scrolls and carries the file's own stage/unstage/discard.
This commit is contained in:
+13
-3
@@ -566,6 +566,8 @@ cannot collide on `index.lock`.
|
||||
| `stage` | `git add -- <paths>` | `{"paths": ["..."]}` |
|
||||
| `unstage` | `git restore --staged -- <paths>` (a staged rename also passes its original path, so both halves unstage) | `{"paths": ["..."]}` |
|
||||
| `discard` | `git restore --source=HEAD --staged --worktree` (tracked) / `git clean -fd` (untracked) | `{"paths": ["..."], "confirm": true}` |
|
||||
| `stage-hunk` | `git apply --cached` of ONE hunk of `git diff -U<context> HEAD -- <path>` | `{"path": "...", "hunk": "@@ -1,2 +1,3 @@", "context": 3}` |
|
||||
| `discard-hunk` | `git apply -R` of that one hunk, off the working tree | `{"path": "...", "hunk": "@@ ... @@", "context": 3, "confirm": true}` |
|
||||
| `commit` | `git add -A` then `git commit -m <message>`, or the index as it stands with `only: "staged"` | `{"message": "...", "only": "staged"}` |
|
||||
| `switch` | `git switch [-c] <branch>` | `{"branch": "...", "create": false}` |
|
||||
| `branch-create` | `git branch <branch> [<base>]` — never switches | `{"branch": "...", "base": "..."}` |
|
||||
@@ -587,15 +589,23 @@ cannot collide on `index.lock`.
|
||||
A `commit` without `only: "staged"` sweeps in (`git add -A -- .`) only the
|
||||
lane cwd's own changes, and is `400 ENOCHANGES` when the lane has none —
|
||||
even if the repo is dirty elsewhere.
|
||||
- `discard` is the one irreversible action here and it **requires**
|
||||
`confirm: true` (`400 ECONFIRM` without it). The UI additionally asks twice.
|
||||
- `discard` and `discard-hunk` are the irreversible actions here and both
|
||||
**require** `confirm: true` (`400 ECONFIRM` without it). The UI additionally
|
||||
asks twice.
|
||||
- A hunk is named by its `@@` line and matched against a FRESH diff at the
|
||||
`context` the caller read it with (send the `context` the changes read
|
||||
returned), so a hunk the file has moved past is `409 EHUNKGONE`, never a
|
||||
stale patch applied somewhere else. The path goes through the same
|
||||
`git status` check; an untracked file has no hunks (`400 EUNTRACKED`). A
|
||||
hunk that no longer applies (e.g. part of it is already staged) is
|
||||
`409 EGIT`.
|
||||
- `branch-create` never switches — the usual reason to create one from a lane
|
||||
is to spawn a sibling worktree lane, and moving this pane's HEAD under a
|
||||
working agent is not. `branch-delete` is `-d`, never `-D`, and refuses
|
||||
`main`/`master`/`development`/`develop` (`400 EPROTECTED`), the current
|
||||
branch and a branch another worktree holds (`400 EBRANCHBUSY`).
|
||||
- Bad input is **400** (`EBADACTION`, `EBADMESSAGE`, `EBADBRANCH`, `EBADPATH`,
|
||||
`ECONFIRM`, `EPROTECTED`, `ENOBRANCH`, `EBRANCHEXISTS`, `EBRANCHBUSY`,
|
||||
`ECONFIRM`, `EUNTRACKED`, `EPROTECTED`, `ENOBRANCH`, `EBRANCHEXISTS`, `EBRANCHBUSY`,
|
||||
`EDIRTY`, `ENOCHANGES`, `ESTAGEDOUTSIDE`, `ENOREMOTE`); git itself exiting
|
||||
non-zero (a rejected push, a credential failure, a diverged pull) is
|
||||
**409 `EGIT`** with git's own `stderr` appended to `error.message` — a
|
||||
|
||||
Reference in New Issue
Block a user