Skip to content

Commit 7e5a85c

Browse files
authored
feat(file-history): Added --walk-reflogs (#413)
1 parent db97e66 commit 7e5a85c

File tree

7 files changed

+111
-48
lines changed

7 files changed

+111
-48
lines changed

USAGE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ from the PR branch.
8181
8282
![file history cherry pick demo](https://user-images.githubusercontent.com/2786478/229853402-f45280ee-f6e2-4325-8a39-ce25b9c5221e.png)
8383
84+
## Inspecting Diffs for Stashes
85+
86+
The latest Git stash is always stored in the reference `refs/stash`. We can
87+
find all the stashes by traversing the reflog for this reference. This can be
88+
achieved with the flag option `--walk-reflogs` (or it's short form `-g`). The
89+
following command will list all stashes in the file history panel:
90+
91+
```vim
92+
:DiffviewFileHistory -g --range=stash
93+
```
94+
8495
## Committing
8596
8697
Creating commits from within nvim is a solved problem, and as such diffview.nvim

doc/diffview.txt

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,32 @@ COMMANDS *diffview-commands*
5656
{paths...} may be provided to narrow down what files are shown. If the
5757
`-C` flag is not defined, the git top-level is determined from the
5858
current buffer when possible. Otherwise it's determined from the cwd.
59-
Examples:
60-
>vim
59+
60+
Examples: >vim
61+
62+
" Diff the working tree against the index:
6163
:DiffviewOpen
64+
65+
" Diff the working tree against a specific commit:
6266
:DiffviewOpen HEAD~2
63-
:DiffviewOpen HEAD~4..HEAD~2
6467
:DiffviewOpen d4a7b0d
65-
:DiffviewOpen d4a7b0d^!
68+
69+
" Diff a commit range:
70+
:DiffviewOpen HEAD~4..HEAD~2
6671
:DiffviewOpen d4a7b0d..519b30e
72+
73+
" Diff the changes introduced by a specific commit (kind of like
74+
" `git show d4a7b0d`):
75+
:DiffviewOpen d4a7b0d^!
76+
77+
" Diff HEAD against it's merge base in origin/main:
6778
:DiffviewOpen origin/main...HEAD
79+
80+
" Limit the scope to the given paths:
6881
:DiffviewOpen HEAD~2 -- lua/diffview plugin
69-
:DiffviewOpen d4a7b0d -uno
82+
83+
" Hide untracked files:
84+
:DiffviewOpen -uno
7085
<
7186

7287
*diffview-staging*
@@ -170,25 +185,44 @@ COMMANDS *diffview-commands*
170185
<Tab>, or by using the mappings that are shown directly in the panel,
171186
preceding the flags' descriptions.
172187

173-
NOTE: Commits are only listed if git-log is able to show its file
174-
stats given your currently configured log options. As such pay
175-
attention to the value of `--diff-merges`, as this controls how
176-
git-log treats merge commits and subsequently it's willingness to show
177-
stats for these commits. Setting `--diff-merges=off` will tell git-log
178-
to never compare merge commits, and as such they won't show up in the
179-
file history view.
188+
*diffview-inspect-stash*
189+
The latest Git stash is always stored in the reference `refs/stash`.
190+
We can find all the stashes by traversing the reflog for this
191+
reference. This can be achieved with the flag option `--walk-reflogs`
192+
(or it's short form `-g`). The following command will list all stashes
193+
in the file history panel: >
194+
:DiffviewFileHistory -g --range=stash
195+
<
196+
197+
Examples: >vim
180198

181-
Examples:
182-
>vim
199+
" History for the current branch:
183200
:DiffviewFileHistory
201+
202+
" History for the current file:
184203
:DiffviewFileHistory %
204+
205+
" History for a specific file:
185206
:DiffviewFileHistory path/to/some/file.txt
207+
208+
" History for a specific directory:
186209
:DiffviewFileHistory path/to/some/directory
210+
211+
" History for multiple paths:
187212
:DiffviewFileHistory multiple/paths foo/bar baz/qux
213+
214+
" Compare history against a fixed base:
188215
:DiffviewFileHistory --base=HEAD~4
189216
:DiffviewFileHistory --base=LOCAL
217+
218+
" History for a specific rev range:
190219
:DiffviewFileHistory --range=origin..HEAD
191220
:DiffviewFileHistory --range=feat/some-branch
221+
222+
" Inspect diffs for Git stashes:
223+
:DiffviewFileHistory -g --range=stash
224+
225+
" Trace the line evolution for the current visual selection:
192226
:'<,'>DiffviewFileHistory
193227
<
194228

@@ -226,6 +260,9 @@ COMMANDS *diffview-commands*
226260
--reflog
227261
Include all reachable objects mentioned by reflogs.
228262

263+
-g, --walk-reflogs
264+
Walk reflogs instead of the commit ancestry chain.
265+
229266
--all Include all refs.
230267

231268
--merges
@@ -344,7 +381,7 @@ COMMANDS *diffview-commands*
344381
current Diffview.
345382

346383
*:DiffviewLog*
347-
:DiffviewLog Open the log.
384+
:DiffviewLog Open the debug log.
348385

349386
==============================================================================
350387

@@ -1539,6 +1576,9 @@ LogOptions *diffview.git.LogOptions*
15391576
{reflog} (boolean)
15401577
Include all reachable objects mentioned by reflogs.
15411578

1579+
{walk_reflogs} (boolean)
1580+
Walk reflogs instead of the commit ancestry chain.
1581+
15421582
{all} (boolean)
15431583
Include all refs.
15441584

lua/diffview/config.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ M._config = M.defaults
257257
---@field first_parent boolean
258258
---@field show_pulls boolean
259259
---@field reflog boolean
260+
---@field walk_reflogs boolean
260261
---@field all boolean
261262
---@field merges boolean
262263
---@field no_merges boolean
@@ -299,6 +300,7 @@ M.log_option_defaults = {
299300
first_parent = false,
300301
show_pulls = false,
301302
reflog = false,
303+
walk_reflogs = false,
302304
all = false,
303305
merges = false,
304306
no_merges = false,

lua/diffview/hl.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,9 @@ M.hl_links = {
448448
FilePanelConflicts = "DiagnosticSignWarn",
449449
FolderName = "Directory",
450450
FolderSign = "PreProc",
451+
Hash = "Identifier",
451452
Reference = "Function",
453+
ReflogSelector = "Special",
452454
StatusAdded = "diffAdded",
453455
StatusUntracked = "diffAdded",
454456
StatusModified = "diffChanged",

lua/diffview/scene/views/file_history/render.lua

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ local function render_entries(panel, parent, entries, updating)
131131
end
132132

133133
if entry.commit.hash then
134-
comp:add_text(" " .. entry.commit.hash:sub(1, 8), "DiffviewSecondary")
134+
comp:add_text(" " .. entry.commit.hash:sub(1, 8), "DiffviewHash")
135+
end
136+
137+
if (entry.commit --[[@as GitCommit ]]).reflog_selector then
138+
comp:add_text((" %s"):format((entry.commit --[[@as GitCommit ]]).reflog_selector), "DiffviewReflogSelector")
135139
end
136140

137141
if entry.commit.ref_names then

lua/diffview/vcs/adapters/git/commit.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ local M = {}
99

1010

1111
---@class GitCommit : Commit
12+
---@field reflog_selector? string
1213
local GitCommit = oop.create_class("GitCommit", Commit.__get())
1314

1415
function GitCommit:init(opt)
1516
self:super(opt)
1617

18+
self.reflog_selector = opt.reflog_selector ~= "" and opt.reflog_selector or nil
19+
1720
if opt.time_offset then
1821
self.time_offset = Commit.parse_time_offset(opt.time_offset)
1922
self.time = self.time - self.time_offset

lua/diffview/vcs/adapters/git/init.lua

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ GitAdapter.bootstrap = {
4747
GitAdapter.COMMIT_PRETTY_FMT = (
4848
"%H %P" -- Commit hash followed by parent hashes
4949
.. "%n%an" -- Author name
50-
.. "%n%ad" -- Author date
51-
.. "%n%ar" -- Author date relative
50+
.. "%n%at" -- Author date: UNIX timestamp
51+
.. "%n%ai" -- Author date: ISO (gives us timezone)
52+
.. "%n%ar" -- Author date: relative
5253
.. "%n..%D" -- Ref names
54+
.. "%n..%gd" -- Reflog selectors
5355
.. "%n..%s" -- Subject
5456
-- The leading dots here are only used for padding to ensure those lines
5557
-- won't ever be completetely empty. This way the lines will be
@@ -388,6 +390,7 @@ function GitAdapter:prepare_fh_options(log_options, single_file)
388390
o.first_parent and { "--first-parent" } or nil,
389391
o.show_pulls and { "--show-pulls" } or nil,
390392
o.reflog and { "--reflog" } or nil,
393+
o.walk_reflogs and { "--walk-reflogs" } or nil,
391394
o.all and { "--all" } or nil,
392395
o.merges and { "--merges" } or nil,
393396
o.no_merges and { "--no-merges" } or nil,
@@ -451,6 +454,7 @@ end
451454
---@field time_offset string
452455
---@field rel_date string
453456
---@field ref_names string
457+
---@field reflog_selector string
454458
---@field subject string
455459
---@field namestat string[]
456460
---@field numstat string[]
@@ -462,22 +466,23 @@ end
462466
---@return GitAdapter.LogData data
463467
local function structure_fh_data(stat_data, keep_diff)
464468
local right_hash, left_hash, merge_hash = unpack(utils.str_split(stat_data[1]))
465-
local time, time_offset = unpack(utils.str_split(stat_data[3]))
469+
local time_offset = utils.str_split(stat_data[4])[3]
466470

467471
---@type GitAdapter.LogData
468472
local ret = {
469473
left_hash = left_hash ~= "" and left_hash or nil,
470474
right_hash = right_hash,
471475
merge_hash = merge_hash,
472476
author = stat_data[2],
473-
time = tonumber(time),
477+
time = tonumber(stat_data[3]),
474478
time_offset = time_offset,
475-
rel_date = stat_data[4],
476-
ref_names = stat_data[5] and stat_data[5]:sub(3) or "",
477-
subject = stat_data[6] and stat_data[6]:sub(3) or "",
479+
rel_date = stat_data[5],
480+
ref_names = stat_data[6] and stat_data[6]:sub(3) or "",
481+
reflog_selector = stat_data[7] and stat_data[7]:sub(3) or "",
482+
subject = stat_data[8] and stat_data[8]:sub(3) or "",
478483
}
479484

480-
local namestat, numstat = structure_stat_data(stat_data, 7)
485+
local namestat, numstat = structure_stat_data(stat_data, 9)
481486
ret.namestat = namestat
482487
ret.numstat = numstat
483488

@@ -486,26 +491,21 @@ local function structure_fh_data(stat_data, keep_diff)
486491
end
487492

488493
-- Soft validate the data
489-
if (ret.merge_hash and (#namestat == 0 or #numstat == 0)) or #namestat ~= #numstat then
490-
-- Merge commits are likely to be missing stat data depending on the value
491-
-- of `--diff-merges`.
492-
ret.valid = false
493-
else
494-
ret.valid = #stat_data >= 6 and pcall(
495-
vim.validate,
496-
{
497-
left_hash = { ret.left_hash, "string", true },
498-
right_hash = { ret.right_hash, "string" },
499-
merge_hash = { ret.merge_hash, "string", true },
500-
author = { ret.author, "string" },
501-
time = { ret.time, "number" },
502-
time_offset = { ret.time_offset, "string" },
503-
rel_date = { ret.rel_date, "string" },
504-
ref_names = { ret.ref_names, "string" },
505-
subject = { ret.subject, "string" },
506-
}
507-
)
508-
end
494+
ret.valid = #namestat == #numstat and pcall(
495+
vim.validate,
496+
{
497+
left_hash = { ret.left_hash, "string", true },
498+
right_hash = { ret.right_hash, "string" },
499+
merge_hash = { ret.merge_hash, "string", true },
500+
author = { ret.author, "string" },
501+
time = { ret.time, "number" },
502+
time_offset = { ret.time_offset, "string" },
503+
rel_date = { ret.rel_date, "string" },
504+
ref_names = { ret.ref_names, "string" },
505+
reflog_selector = { ret.reflog_selector, "string" },
506+
subject = { ret.subject, "string" },
507+
}
508+
)
509509

510510
return ret
511511
end
@@ -569,7 +569,6 @@ function GitAdapter:stream_fh_data(state)
569569
"gc.auto=0",
570570
"log",
571571
"--pretty=format:%x00%n" .. GitAdapter.COMMIT_PRETTY_FMT,
572-
"--date=raw",
573572
"--numstat",
574573
"--raw",
575574
state.prepared_log_opts.flags,
@@ -649,7 +648,6 @@ function GitAdapter:stream_line_trace_data(state)
649648
"--color=never",
650649
"--no-ext-diff",
651650
"--pretty=format:%x00%n" .. GitAdapter.COMMIT_PRETTY_FMT,
652-
"--date=raw",
653651
state.prepared_log_opts.flags,
654652
state.prepared_log_opts.rev_range,
655653
"--"
@@ -772,6 +770,7 @@ function GitAdapter:file_history_options(range, paths, argo)
772770
{ "first-parent" },
773771
{ "show-pulls" },
774772
{ "reflog" },
773+
{ "walk-reflogs", "g" },
775774
{ "all" },
776775
{ "merges" },
777776
{ "no-merges" },
@@ -985,6 +984,7 @@ GitAdapter.file_history_worker = async.void(function(self, out_stream, opt)
985984
time_offset = new_data.time_offset,
986985
rel_date = new_data.rel_date,
987986
ref_names = new_data.ref_names,
987+
reflog_selector = new_data.reflog_selector,
988988
subject = new_data.subject,
989989
diff = new_data.diff,
990990
})
@@ -1028,10 +1028,9 @@ GitAdapter.fh_retry_commit = async.wrap(function(self, rev_arg, state, opt, call
10281028
"gc.auto=0",
10291029
"show",
10301030
"--pretty=format:" .. GitAdapter.COMMIT_PRETTY_FMT,
1031-
"--date=raw",
10321031
"--numstat",
10331032
"--raw",
1034-
"--diff-merges=" .. (opt.is_merge and "first-parent" or state.log_options.diff_merges),
1033+
"--diff-merges=" .. state.log_options.diff_merges,
10351034
(state.single_file and state.log_options.follow) and "--follow" or nil,
10361035
rev_arg,
10371036
"--",
@@ -1849,6 +1848,7 @@ GitAdapter.flags = {
18491848
FlagOption("-p", "--first-parent", "Follow only the first parent upon seeing a merge commit"),
18501849
FlagOption("-s", "--show-pulls", "Show merge commits the first introduced a change to a branch"),
18511850
FlagOption("-R", "--reflog", "Include all reachable objects mentioned by reflogs"),
1851+
FlagOption("-g", "--walk-reflogs", "Walk reflogs instead of the commit ancestry chain"),
18521852
FlagOption("-a", "--all", "Include all refs"),
18531853
FlagOption("-m", "--merges", "List only merge commits"),
18541854
FlagOption("-n", "--no-merges", "List no merge commits"),
@@ -2055,6 +2055,7 @@ function GitAdapter:init_completion()
20552055
self.comp.file_history:put({ "--first-parent" })
20562056
self.comp.file_history:put({ "--show-pulls" })
20572057
self.comp.file_history:put({ "--reflog" })
2058+
self.comp.file_history:put({ "--walk-reflogs", "-g" })
20582059
self.comp.file_history:put({ "--all" })
20592060
self.comp.file_history:put({ "--merges" })
20602061
self.comp.file_history:put({ "--no-merges" })

0 commit comments

Comments
 (0)