Skip to content

Commit 7bd0a41

Browse files
committed
fix(git_diff): logic to match git diff command
fix #2615
1 parent 30ba09a commit 7bd0a41

4 files changed

Lines changed: 91 additions & 33 deletions

File tree

lua/fzf-lua/core.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,22 @@ M.set_header = function(opts)
836836
return opts.search and #opts.search > 0 and opts.search
837837
end,
838838
},
839+
ref = {
840+
hdr_txt_opt = "ref_header_txt",
841+
hdr_txt_str = "ref: ",
842+
hdr_txt_col = opts.hls.header_text,
843+
val = function()
844+
return opts.ref and #opts.ref > 0 and opts.ref
845+
end,
846+
},
847+
ref1 = {
848+
hdr_txt_opt = "ref1_header_txt",
849+
hdr_txt_str = "ref1: ",
850+
hdr_txt_col = opts.hls.header_text,
851+
val = function()
852+
return opts.ref1 and #opts.ref1 > 0 and opts.ref1
853+
end,
854+
},
839855
lsp_query = {
840856
hdr_txt_opt = "lsp_query_header_txt",
841857
hdr_txt_str = "Query: ",

lua/fzf-lua/defaults.lua

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -666,15 +666,16 @@ M.defaults.git = {
666666
},
667667
---Git diff (changed files vs a git ref).
668668
---@class fzf-lua.config.GitDiff: fzf-lua.config.GitBase
669-
---Git reference to compare against.
670-
---@field ref? string
669+
---Git reference(s) to compare against.
670+
---@field ref? string|string[]
671671
---Git reference used as the base for the comparison.
672-
---@field compare_against? string
672+
-- `compare_against` was renamed to `ref1`
673+
---@field ref1? string
673674
diff = {
674-
cmd = "git --no-pager diff --name-only {compare_against} {ref}",
675-
ref = "HEAD",
676-
compare_against = "",
677-
preview = "git diff {compare_against} {ref} {file}",
675+
cmd = "git --no-pager diff --name-only {ref1} {ref}",
676+
ref = nil,
677+
ref1 = nil,
678+
preview = "git diff {ref1} {ref} {file}",
678679
preview_pager = M._preview_pager_fn,
679680
multiprocess = 1, ---@type integer|boolean
680681
_type = "file",
@@ -683,7 +684,14 @@ M.defaults.git = {
683684
fzf_opts = { ["--multi"] = true },
684685
_fzf_nth_devicons = true,
685686
_actions = function() return M.globals.actions.files end,
686-
_headers = { "cwd" },
687+
_headers = { "cwd", "actions" },
688+
actions = {
689+
["ctrl-q"] = {
690+
fn = function() FzfLua.git_commits() end,
691+
reuse = true,
692+
header = "git commits"
693+
},
694+
},
687695
},
688696
---Git diff hunks (changed lines).
689697
---@class fzf-lua.config.GitHunks: fzf-lua.config.GitBase
@@ -717,6 +725,17 @@ M.defaults.git = {
717725
actions = {
718726
["enter"] = actions.git_checkout,
719727
["ctrl-y"] = { fn = actions.git_yank_commit, exec_silent = true },
728+
["ctrl-d"] = {
729+
fn = function(s, _o)
730+
if not s[1] then return FzfLua.utils.fzf_exit() end
731+
local o = vim.deepcopy(_o.__call_opts)
732+
o.ref = s[1]:match("[^ ]+")
733+
o.ref1 = o.ref .. "~"
734+
FzfLua.git_diff(o)
735+
end,
736+
reuse = true,
737+
header = "git diff"
738+
},
720739
},
721740
fzf_opts = { ["--no-multi"] = true },
722741
_headers = { "actions", "cwd" },
@@ -816,6 +835,7 @@ M.defaults.git = {
816835
},
817836
---Git stashes.
818837
---@class fzf-lua.config.GitStash: fzf-lua.config.GitBase
838+
---@field search? string
819839
stash = {
820840
cmd = "git --no-pager stash list",
821841
preview = "git --no-pager stash show --patch --color {1}",

lua/fzf-lua/path.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,9 @@ end
563563

564564
---@overload fun(cmd: string, opts: table): string
565565
---@overload fun(cmd: string[], opts: table): string[]
566+
---@param cmd string|string[]
567+
---@param opts table
568+
---@return string|string[]
566569
function M.git_cwd(cmd, opts)
567570
local git_args = {
568571
{ "cwd", "-C" },

lua/fzf-lua/providers/git.lua

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,39 +91,61 @@ local function git_preview(opts, file)
9191
return opts.preview
9292
end
9393

94+
---@param opts fzf-lua.config.GitBase|{}?
95+
---@param ref string
96+
---@return boolean
97+
local git_validate_ref = function(opts, ref)
98+
local cmd = path.git_cwd({ "git", "rev-parse", "--verify", ref }, opts --[[@as table]])
99+
local _, exit_code = utils.io_systemlist(cmd --[[@as string[] ]])
100+
if exit_code ~= 0 then
101+
utils.warn("Invalid git ref %s", ref)
102+
return false
103+
end
104+
return true
105+
end
106+
94107
---@param opts fzf-lua.config.GitDiff|{}?
95108
---@return thread?, string?, table?
96109
M.diff = function(opts)
97110
---@type fzf-lua.config.GitDiff
98111
opts = config.normalize_opts(opts, "git.diff")
99112
if not opts then return end
100-
-- Ensure that ref is a commit hash in this git repository.
101-
local validation_ref = path.git_cwd({ "git", "rev-parse", "--verify", opts.ref }, opts)
102-
local _, exit_status_code_ref = utils.io_systemlist(validation_ref)
103-
if exit_status_code_ref ~= 0 then
104-
utils.warn("Invalid git ref %s", opts.ref)
105-
return
113+
-- Backward compat `compare_against` -> `ref1`
114+
---@diagnostic disable-next-line: undefined-field
115+
opts.ref1 = opts.compare_against or opts.ref1
116+
-- Convinience: ref as string array
117+
if type(opts.ref) == "table" then
118+
opts.ref, opts.ref1 = opts.ref[1], (opts.ref[2] or opts.ref1)
106119
end
107-
-- If compare_against is given, ensure that it is a commit hash in this git repository.
108-
if type(opts.compare_against) == "string" and #opts.compare_against > 0 then
109-
local validation_comp = path.git_cwd({ "git", "rev-parse", "--verify", opts.compare_against },
110-
opts)
111-
local _, exit_code_status_comp = utils.io_systemlist(validation_comp)
112-
if exit_code_status_comp ~= 0 then
113-
utils.warn("Invalid git ref %s", opts.compare_against)
120+
-- Ensure supplied refs are valid in this git repository.
121+
for _, r in ipairs({ "ref", "ref1" }) do
122+
if type(opts[r]) == "string" and #opts[r] > 0 and not git_validate_ref(opts, opts[r]) then
114123
return
115124
end
116-
else
117-
-- Default to diffing against ref and its direct parent commit.
118-
opts.compare_against = opts.ref .. "^"
119125
end
120-
opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref)
121-
opts.cmd = opts.cmd:gsub("[<{]compare_against[}>]", opts.compare_against)
122-
opts.preview = opts.preview:gsub("[<{]ref[}>]", opts.ref)
123-
opts.preview = opts.preview:gsub("[<{]compare_against[}>]", opts.compare_against)
126+
-- If no ref was supplied default to last commit, otherwise compare against the index
127+
if not opts.ref and not opts.ref1 then
128+
local cmd = path.git_cwd(
129+
{ "git", "-c", "color.status=false", "--no-optional-locks", "status", "--porcelain=v1" },
130+
opts --[[@as table]])
131+
local out, exit_code = utils.io_systemlist(cmd --[[@as string[] ]])
132+
if exit_code == 0 and #out == 0 then
133+
opts.ref = "HEAD^"
134+
else
135+
opts.ref = "HEAD"
136+
end
137+
end
138+
opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref or "")
139+
opts.cmd = opts.cmd:gsub("[<{]ref1[}>]", opts.ref1 or "")
140+
opts.preview = opts.preview:gsub("[<{]ref[}>]", opts.ref or "")
141+
opts.preview = opts.preview:gsub("[<{]ref1[}>]", opts.ref1 or "")
124142
opts = set_git_cwd_args(opts)
125143
if not opts.cwd then return end
126144
opts.preview = git_preview(opts, "{-1}")
145+
if type(opts._headers) == "table" then
146+
table.insert(opts._headers, "ref")
147+
table.insert(opts._headers, "ref1")
148+
end
127149
return core.fzf_exec(opts.cmd, opts)
128150
end
129151

@@ -301,13 +323,10 @@ M.hunks = function(opts)
301323
---@type fzf-lua.config.GitHunks
302324
opts = config.normalize_opts(opts, "git.hunks")
303325
if not opts then return end
304-
local cmd = path.git_cwd({ "git", "rev-parse", "--verify", opts.ref }, opts)
305-
local _, err = utils.io_systemlist(cmd)
306-
if err ~= 0 then
307-
utils.warn("Invalid git ref %s", opts.ref)
326+
if type(opts.ref) == "string" and #opts.ref > 0 and not git_validate_ref(opts, opts.ref) then
308327
return
309328
end
310-
opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref)
329+
opts.cmd = opts.cmd:gsub("[<{]ref[}>]", opts.ref or "")
311330
opts = set_git_cwd_args(opts)
312331
if not opts.cwd then return end
313332

0 commit comments

Comments
 (0)