From 39180a372badcc8926d25726d673052fc644949f Mon Sep 17 00:00:00 2001 From: sean <91675054+undont@users.noreply.github.com> Date: Fri, 9 Oct 2026 20:24:13 +0100 Subject: [PATCH 1/4] fix: keep a file recreated at a renamed file's old path on discard --- lua/differ/git/init.lua | 14 ++++++++++---- test/nvim/git_spec.lua | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lua/differ/git/init.lua b/lua/differ/git/init.lua index eff7f08..d3cbb6a 100644 --- a/lua/differ/git/init.lua +++ b/lua/differ/git/init.lua @@ -989,10 +989,16 @@ function M.discard(root, entry, preview) -- untouched, so its new path is an add ok = git_ok({ "reset", "-q", "HEAD", "--", entry.path }, root, "discard") and remove_ok(abs) elseif kind == "R" and entry.previous_path then - -- undoing a move: the old path comes back from HEAD, the new one goes like an add - ok = git_ok({ "checkout", "HEAD", "--", entry.previous_path }, root, "discard") - and git_ok({ "reset", "-q", "HEAD", "--", entry.path }, root, "discard") - and remove_ok(abs) + -- undoing a move: the old path comes back from HEAD, the new one goes like an add. + -- a file since recreated at the old path stays as it is, against HEAD in the index + if (vim.uv or vim.loop).fs_lstat(root .. "/" .. entry.previous_path) then + local unstage = { "reset", "-q", "HEAD", "--", entry.previous_path, entry.path } + ok = git_ok(unstage, root, "discard") and remove_ok(abs) + else + ok = git_ok({ "checkout", "HEAD", "--", entry.previous_path }, root, "discard") + and git_ok({ "reset", "-q", "HEAD", "--", entry.path }, root, "discard") + and remove_ok(abs) + end else ok = git_ok({ "checkout", "HEAD", "--", entry.path }, root, "discard") -- index + worktree end diff --git a/test/nvim/git_spec.lua b/test/nvim/git_spec.lua index 93d83c2..7e4bfa6 100644 --- a/test/nvim/git_spec.lua +++ b/test/nvim/git_spec.lua @@ -7572,6 +7572,26 @@ describe(":Differ diff rename staging", function() p:close() end) + it("undoes a rename with X in the index only when a file is back at the old path", function() + local root = renamed_repo({ 5 }) + write(root .. "/old/big.lua", "new file\n") + vim.cmd.edit(root .. "/new/big.lua") + + git_src.panel({ rev = {} }) + local p = Panel.current() + assert.is_true(p:focus_file("new/big.lua")) + + confirming(1, function() + p:discard() + end) + + local status = git(root, "status", "--porcelain=v1") + p:close() + assert.are.equal(" M old/big.lua\n", status) + assert.are.same({ "new file" }, vim.fn.readfile(root .. "/old/big.lua")) + assert.are.equal(0, vim.fn.filereadable(root .. "/new/big.lua")) + end) + it("names the path X will restore in its confirm", function() local root = renamed_repo() vim.cmd.edit(root .. "/new/big.lua") From 9825efcc52b7039a0e3291f9f4e9ff21bf1b1509 Mon Sep 17 00:00:00 2001 From: sean <91675054+undont@users.noreply.github.com> Date: Fri, 9 Oct 2026 20:45:46 +0100 Subject: [PATCH 2/4] test: keep a file at a staged rename's old path untracked on stage --- test/nvim/git_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/nvim/git_spec.lua b/test/nvim/git_spec.lua index 7e4bfa6..3da542d 100644 --- a/test/nvim/git_spec.lua +++ b/test/nvim/git_spec.lua @@ -7537,6 +7537,22 @@ describe(":Differ diff rename staging", function() assert.are.equal("R old/big.lua -> new/big.lua\n", status) end) + it("leaves a file back at a staged rename's old path untracked on s", function() + local root = renamed_repo({ 5 }) + write(root .. "/old/big.lua", "new file\n") + vim.cmd.edit(root .. "/new/big.lua") + + git_src.panel({ rev = {} }) + local p = Panel.current() + assert.is_true(p:focus_file("new/big.lua")) + p:stage_op("stage") + + local status = git(root, "status", "--porcelain=v1", "-uall") + p:close() + assert.are.equal("R old/big.lua -> new/big.lua\n?? old/big.lua\n", status) + assert.are.same({ "new file" }, vim.fn.readfile(root .. "/old/big.lua")) + end) + it("unstages both of a rename's paths from the panel row, as the diff keys do", function() local root = renamed_repo({ 5 }) vim.cmd.edit(root .. "/new/big.lua") From f92f7a2587447cc752e1867e213caa7e3bfe8569 Mon Sep 17 00:00:00 2001 From: sean <91675054+undont@users.noreply.github.com> Date: Fri, 9 Oct 2026 20:48:24 +0100 Subject: [PATCH 3/4] chore: bump golangci-lint to 2.14.0 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1a7c0eb..24c9dcb 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ PANDOC_VERSION := 3.10.1 PANDOC_DIR := .tools/pandoc-$(PANDOC_VERSION) PANDOC_BIN := $(PANDOC_DIR)/bin/pandoc -GOLANGCI_VERSION := 2.13.1 +GOLANGCI_VERSION := 2.14.0 GOLANGCI_DIR := .tools/golangci-lint-$(GOLANGCI_VERSION) GOLANGCI_BIN := $(GOLANGCI_DIR)/golangci-lint From 1da7c31a04d00d5f68e558752cd7f4365488d07d Mon Sep 17 00:00:00 2001 From: sean <91675054+undont@users.noreply.github.com> Date: Fri, 9 Oct 2026 22:09:37 +0100 Subject: [PATCH 4/4] docs: changelog entry for the rename discard fix --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 951cdca..3c950aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Fixed + +- `X` on a staged rename overwrote a file recreated at the old path with its `HEAD` content. It now undoes the rename and leaves that file as it is + +## [0.2.1] — 2026-10-09 + ### Added - The diff view highlights code embedded in another language with that language's parser, not only the file's own grammar