ADR-0097: Discarding a rename restores the old name
- Status: Accepted
- Date: 2026-09-11
- Deciders: jka
- Decision: D97
Context
A rename is the one change git records as one entry with two names. Discard (ADR-0080)
treated it as a change to the new name only: git restore --staged --worktree -- new.txt
dropped the index entry and left the file untracked, and the old name stayed deleted.
The rename was unstaged, not undone. The cause was the query: git's rename detection
needs both paths in the same diff, and a status narrowed to the new path reports a plain
addition.
Decision
rio::git::discardreads the full repository status and finds the entry, instead of querying the single path.- For a rename (
R): unstage both paths, restore the old name from the index into the working tree, then remove the new file withgit clean. - A copy (
C) is handled as an addition: the new file is removed and the source is untouched. - The function returns
{action, paths}, so the operation emitsfs.changedfor both names (ADR-0094). - In the git pane, the confirmation for a rename says the file will go back to its old name and last committed contents. The file tree's entry keeps the generic wording, because its rows do not carry the original path.
git.diffuses the same full-status lookup for staged renames and passes git both names, so a rename shows as a rename rather than as a new file. Unstaged diffs are unaffected.
Consequences
- Discard undoes a rename completely.
- The core is the authority on what a change is. A second frontend gets a correct diff and discard without knowing about renames.
- Clicking a staged row costs one full
statuscall. The unstaged path does not.