Skip to content

Filter file views rather than search#5273

Merged
stefanhaller merged 4 commits into
masterfrom
filter-files
Mar 7, 2026
Merged

Filter file views rather than search#5273
stefanhaller merged 4 commits into
masterfrom
filter-files

Conversation

@jesseduffield

@jesseduffield jesseduffield commented Feb 7, 2026

Copy link
Copy Markdown
Owner

PR Description

Way back when I implemented filter functionality I could not muster the motivation to apply it to the file views (files and commit files), but it really should be used on them.

The text filter matches against the full file path (not just the filename), which is more useful for navigating large directory trees.

When a text filter is active, all operations respect it consistently:

  • Diffs: selecting a filtered directory shows only the diff of visible files, not all files in the directory
  • Staging/unstaging: pressing space on a filtered directory only stages/unstages visible files
  • Toggle all (a): only toggles staging for visible files
  • Custom patch: toggling a filtered directory only adds visible files to the patch

Full disclosure, opus 4.6 wrote this entire PR but reviewing its changes they seem reasonable, and I have done some local testing and everything works as expected.

Please check if the PR fulfills these requirements

  • Cheatsheets are up-to-date (run go generate ./...)
  • Code has been formatted (see here)
  • Tests have been added/updated (see here for the integration test guide)
  • Text is internationalised (see here)
  • If a new UserConfig entry was added, make sure it can be hot-reloaded (see here)
  • Docs have been updated if necessary
  • You've read through your own file changes for silly mistakes etc

Copilot AI review requested due to automatic review settings February 7, 2026 07:10
@codacy-production

codacy-production Bot commented Feb 7, 2026

Copy link
Copy Markdown

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
Report missing for 825784f1 91.63%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (825784f) Report Missing Report Missing Report Missing
Head commit (615c566) 60140 52615 87.49%

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#5273) 478 438 91.63%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Footnotes

  1. Codacy didn't receive coverage data for the commit, or there was an error processing the received data. Check your integration for errors and validate that your coverage setup is correct.

Comment thread pkg/gui/controllers/helpers/refresh_helper.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Lazygit’s file-based panels (working tree files and commit files) to use the existing filter mechanism (i.e., actually reducing the list contents) instead of the search mechanism (highlighting matches without changing the list).

Changes:

  • Add text-filter support to working-tree and commit-file trees, including fuzzy/non-fuzzy matching.
  • Convert Working Tree Files and Commit Files contexts from “searchable” to “filterable”.
  • Enable and adjust integration tests that validate file/commit-file filtering behavior.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/integration/tests/filter_and_search/nested_filter_transient.go Updates expectations to reflect filtering behavior in transient panels.
pkg/integration/tests/filter_and_search/nested_filter.go Updates expectations/comments for filtering behavior across nested panels.
pkg/integration/tests/filter_and_search/filter_files.go Unskips and runs file filtering integration test now that filtering is implemented.
pkg/integration/tests/filter_and_search/filter_commit_files.go Unskips and runs commit-file filtering integration test now that filtering is implemented.
pkg/gui/filetree/file_tree_view_model.go Adds IFilterableContext methods + search history to working tree file view model.
pkg/gui/filetree/file_tree.go Implements text filtering for working-tree files and renames status filter getter.
pkg/gui/filetree/file_filter.go Adds shared text-filter helpers for files and commit files (substring or fuzzy).
pkg/gui/filetree/commit_file_tree_view_model.go Adds IFilterableContext methods + search history to commit-file view model.
pkg/gui/filetree/commit_file_tree.go Implements text filtering in commit-file tree building.
pkg/gui/controllers/switch_to_diff_files_controller.go Clears commit-files filtering when switching into diff-files view.
pkg/gui/controllers/helpers/search_helper.go Resets filter history index on open; adjusts when selection resets on re-apply.
pkg/gui/controllers/helpers/refresh_helper.go Updates call sites for renamed status filter getter.
pkg/gui/controllers/files_controller.go Updates status filter references to new getter name.
pkg/gui/context/working_tree_context.go Converts working tree context from searchable to filterable.
pkg/gui/context/commit_files_context.go Converts commit files context from searchable to filterable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/gui/filetree/file_tree_view_model.go
Comment thread pkg/gui/filetree/commit_file_tree_view_model.go
@jesseduffield jesseduffield added the enhancement New feature or request label Feb 7, 2026

@mdsiaofficial mdsiaofficial left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after staging?

@stefanhaller

Copy link
Copy Markdown
Collaborator

Nice!

From what I remember, the main reason why we excluded the Files view from filtering back then was that we couldn't decide whether it should filter just the file name, or the full path. I can't find any discussion about that any more though. In this PR it seems you have decided to filter by full path, and it may well be the more desirable behavior (I'm still not really sure though). I would have expected some mention of this in the PR description or commit message.

One inconsistency that I found: if you filter in the Commit Files view so that only some files in a directory are visible, and then select the directory and press space, only the visible files are added to the custom patch. However, if you do the same in the Files panel, all files are staged, even the invisible ones. I'm not really sure which behavior is the more expected one, but I feel it would be good to be consistent.

And finally, after using it for a day I found a very confusing aspect of this, related to the previous parapraph: if you filter a directory so that only one file is visible, and then select the directory, it shows the diff of all files in it. This is of course the expected behavior if you think about it, but if you don't, it can confuse the hell out of you. (It did for me, anyway, and I suspect it could confuse other users.) I don't have any idea what we could do about it (probably nothing), just wanted to bring it up as something that confused me.

@jesseduffield

Copy link
Copy Markdown
Owner Author

From what I remember, the main reason why we excluded the Files view from filtering back then was that we couldn't decide whether it should filter just the file name, or the full path. I can't find any discussion about that any more though. In this PR it seems you have decided to filter by full path, and it may well be the more desirable behavior (I'm still not really sure though). I would have expected some mention of this in the PR description or commit message.

I had forgotten there was discussion about that: this time around doing the full path feels like a no-brainer: in rust you can often have a bunch of files with the same name mod.rs and so for those you'd want to be filtering based on their directory.

One inconsistency that I found: if you filter in the Commit Files view so that only some files in a directory are visible, and then select the directory and press space, only the visible files are added to the custom patch. However, if you do the same in the Files panel, all files are staged, even the invisible ones. I'm not really sure which behavior is the more expected one, but I feel it would be good to be consistent.

Good catch. I think it's less surprising if we only stage things which are visible. It also supports more use cases like only wanting to stage all .go files in a project (filter by .go, then stage all). I've pushed a commit which does this.

And finally, after using it for a day I found a very confusing aspect of this, related to the previous parapraph: if you filter a directory so that only one file is visible, and then select the directory, it shows the diff of all files in it. This is of course the expected behavior if you think about it, but if you don't, it can confuse the hell out of you. (It did for me, anyway, and I suspect it could confuse other users.) I don't have any idea what we could do about it (probably nothing), just wanted to bring it up as something that confused me.

I've resolved this in the last commit.

@stefanhaller stefanhaller left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming back to this at last, sorry for the long delay. Trying to work my way back into proper maintainership now, after some time off for private reasons.

This looks very good to me now, I only have a few git-history related questions below. And I think the third commit should probably be squashed into the second.

| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Search the current view by text | |
| `` / `` | Filter the current view by text | |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Since github doesn't allow commenting on commit messages, I'll add this here:)

The third paragraph of the commit message is backwards.

Comment on lines +36 to +37
state.PrevSearchIndex = -1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an unrelated fix. What does it fix? Can this be a separate commit?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a separate commit (already tested by filter_and_search/filter_search_history, which fails if we revert the change. This test isn't changed by this branch but was failing due to switching from search -> filter.)

if ok {
state := self.searchState()
if context == state.Context {
if context == state.Context && self.c.Context().Current().GetKey() == self.c.Contexts().Search.GetKey() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this change, and again, it looks unrelated. Can it be a separate commit? And why is it needed?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an explanation in the commit message and a matching test

func (self *CommitFilesController) pathsForDiff(node *filetree.CommitFileNode) []string {
if !node.IsFile() && self.context().IsFiltering() {
var paths []string
node.ForEachFile(func(file *models.CommitFile) error {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed 9e29941 to address the linter warnings

Comment on lines +31 to +34
Contains("dir1").IsSelected(),
Contains("apple-grape"),
Contains("apple-orange"),
Contains("grape-orange"),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer Equals over Contains for all file-tree related tests nowadays; I find it makes the tests much easier to read at a glance. I pushed 5024d75 to change this, but it is a fixup for both the 2nd and 3rd commits (which I think should be squashed).

jesseduffield and others added 4 commits March 7, 2026 20:04
This avoids a naming collision with GetFilter from the
IFilterableContext interface, which will be implemented by
FileTreeViewModel in the next commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When opening a filter prompt, reset PrevSearchIndex to -1 to avoid
stale search state from a previous search/filter session.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Without this check, the selection was being reset to 0 whenever
ReApplyFilter was called for the current filter context, even when
the user wasn't actively typing in the search prompt (e.g. when the
model updates in the background). This was causing unexpected cursor
jumps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change working tree files and commit files panels to use filtering
(reducing the list) instead of search (highlighting matches). This
matches the behavior of other filterable views.

The text filter matches against the full file path, not just the
filename, which is more useful for navigating large directory trees.

When toggling a directory for a custom patch while a text filter is
active, only the visible filtered files in the directory are affected,
consistent with how staging a directory in the files panel works.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@stefanhaller stefanhaller enabled auto-merge March 7, 2026 19:05
@stefanhaller stefanhaller merged commit 35911da into master Mar 7, 2026
13 checks passed
@stefanhaller stefanhaller deleted the filter-files branch March 7, 2026 19:06
phanen added a commit to phanen/mterm.nvim that referenced this pull request Mar 10, 2026
jesseduffield/lazygit#5273

We can abort with esc to keep old behavior.
maybe detect lazygit version if possible but I always use the latest.
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Mar 24, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [jesseduffield/lazygit](https://github.com/jesseduffield/lazygit) | minor | `v0.59.0` → `v0.60.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>jesseduffield/lazygit (jesseduffield/lazygit)</summary>

### [`v0.60.0`](https://github.com/jesseduffield/lazygit/releases/tag/v0.60.0)

[Compare Source](jesseduffield/lazygit@v0.59.0...v0.60.0)

<!-- Release notes generated using configuration in .github/release.yml at v0.60.0 -->

#### What's Changed

##### Enhancements 🔥

- Rename "Copy commit hash to clipboard" to mention it's an abbreviated hash by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5331](jesseduffield/lazygit#5331)
- Hide the "Fetching..." status of the auto-fetch when bottom line is hidden by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5321](jesseduffield/lazygit#5321)
- Allow removing lines from patch directly by [@&#8203;jesseduffield](https://github.com/jesseduffield) in [#&#8203;5277](jesseduffield/lazygit#5277)
- Filter file views rather than search by [@&#8203;jesseduffield](https://github.com/jesseduffield) in [#&#8203;5273](jesseduffield/lazygit#5273)
- Show branch name and detached HEAD in worktrees tab by [@&#8203;ruudk](https://github.com/ruudk) in [#&#8203;5339](jesseduffield/lazygit#5339)
- Add backward cycling support for log view (using `<shift>-a` on status page) by [@&#8203;zaakiy](https://github.com/zaakiy) in [#&#8203;5346](jesseduffield/lazygit#5346)
- Show worktree name next to branch in branches list by [@&#8203;ruudk](https://github.com/ruudk) in [#&#8203;5340](jesseduffield/lazygit#5340)

##### Fixes 🔧

- Fix matching of lazygit-edit URLs without line numbers by [@&#8203;danielwe](https://github.com/danielwe) in [#&#8203;5311](jesseduffield/lazygit#5311)
- Fix [#&#8203;5302](jesseduffield/lazygit#5302): Create .git/info directory before writing exclude file by [@&#8203;cobyfrombrooklyn-bot](https://github.com/cobyfrombrooklyn-bot) in [#&#8203;5325](jesseduffield/lazygit#5325)
- Fix off-by-one error when calculating popup panel dimensions by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5312](jesseduffield/lazygit#5312)
- Properly disable clicks in inactive views behind popups by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5313](jesseduffield/lazygit#5313)
- Enable `{` and `}` to change diff context size in branches and tags panels in diffing mode by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5258](jesseduffield/lazygit#5258)
- Fix diff display of custom pagers after screen mode change by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5349](jesseduffield/lazygit#5349)

##### Maintenance ⚙️

- Bump github.com/cloudflare/circl from 1.6.1 to 1.6.3 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;5323](jesseduffield/lazygit#5323)

##### Docs 📖

- Fix typo: MacOS to macOS by [@&#8203;04cb](https://github.com/04cb) in [#&#8203;5335](jesseduffield/lazygit#5335)

##### I18n 🌎

- Update translations from Crowdin by [@&#8203;stefanhaller](https://github.com/stefanhaller) in [#&#8203;5352](jesseduffield/lazygit#5352)

##### Other Changes

- Add Terra as an alternative Fedora install method by [@&#8203;Owen-sz](https://github.com/Owen-sz) in [#&#8203;5281](jesseduffield/lazygit#5281)

#### New Contributors

- [@&#8203;Owen-sz](https://github.com/Owen-sz) made their first contribution in [#&#8203;5281](jesseduffield/lazygit#5281)
- [@&#8203;danielwe](https://github.com/danielwe) made their first contribution in [#&#8203;5311](jesseduffield/lazygit#5311)
- [@&#8203;cobyfrombrooklyn-bot](https://github.com/cobyfrombrooklyn-bot) made their first contribution in [#&#8203;5325](jesseduffield/lazygit#5325)
- [@&#8203;04cb](https://github.com/04cb) made their first contribution in [#&#8203;5335](jesseduffield/lazygit#5335)
- [@&#8203;zaakiy](https://github.com/zaakiy) made their first contribution in [#&#8203;5346](jesseduffield/lazygit#5346)

**Full Changelog**: <jesseduffield/lazygit@v0.59.0...v0.60.0>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My42MS43IiwidXBkYXRlZEluVmVyIjoiNDMuNjEuNyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants