Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a new interactive forgit_discard command (aliased as gdc) that combines unstaging and reverting uncommitted changes into a single operation. This fills a gap in forgit's workflow by providing a safe, interactive way to discard staged changes with preview and optional confirmation, consistent with forgit's design philosophy of making destructive operations more deliberate.
Changes:
- Added
_forgit_discard()function with preview and interactive file selection for discarding staged changes - Integrated the new command across all shell plugins (bash, zsh, fish) and completion systems
- Added comprehensive test coverage for the new functionality
- Updated documentation with usage examples and configuration options
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| bin/git-forgit | Implements the core discard functionality with _forgit_discard(), _forgit_git_discard(), and _forgit_discard_preview() functions |
| tests/discard.test.sh | Adds test suite covering empty state, tracked file restoration, new file handling, and unstaging behavior |
| forgit.plugin.zsh | Registers forgit::discard() function and gdc alias for zsh |
| conf.d/forgit.plugin.fish | Registers abbreviation for fish shell |
| completions/git-forgit.fish | Adds completion support for fish shell |
| completions/git-forgit.bash | Adds completion support for bash |
| completions/_git-forgit | Adds completion support for zsh |
| README.md | Documents the new command in features list and configuration tables |
| LICENSE | Updates copyright year to 2026 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ea508d8 to
7f90257
Compare
6d49fd7 to
6cfc362
Compare
Currently there is no interactive way to selectively discard modifications to working tree files. Users must either manually type file paths with git restore or use git checkout, which is the older discouraged syntax. This makes it cumbersome to selectively discard changes when reviewing multiple modified files. Add _forgit_restore function that provides an fzf-based selector for modified files with diff preview. This follows the same pattern as existing forgit commands like reset_head and checkout_file, allowing users to interactively review diffs before discarding changes. The command is exposed as 'grs' alias and integrated with shell completion systems across bash/zsh/fish. Signed-off-by: Javier Tia <floss@jetm.me>
Currently the restore functionality lacks automated tests, making it difficult to verify correctness during refactoring and increasing the risk of regressions. Without tests, developers cannot confidently modify the restore behavior or ensure edge cases are handled properly. Add a complete test suite covering core restore scenarios including modified files, untracked files, mixed staged/unstaged changes, and renamed files. These tests validate that restore correctly reverts working tree changes while preserving staged content and ignoring untracked files, ensuring the command behaves consistently with Git's restore semantics. Signed-off-by: Javier Tia <floss@jetm.me>
sandr01d
left a comment
There was a problem hiding this comment.
Thanks for the update @jetm! Looks mostly good, but needs a few changes here and there. The pipeline is failing because we require the usage of conventional commits. I'll do a full functional review, once the code is finalized.
completions/git-forgit.fish
Outdated
| cherry_pick cherry_pick_from_branch clean diff fixup ignore log reflog rebase reset_head \ | ||
| revert_commit reword squash stash_show stash_push switch_branch |
There was a problem hiding this comment.
There have been some commands removed here, probably by mistake.
| # for antidote (in .zsh_plugins.txt) | ||
| wfxr/forgit kind:defer | ||
|
|
There was a problem hiding this comment.
This change does not belong in this PR. Feel free to open a separate one.
|
|
||
|
|
||
|
|
There was a problem hiding this comment.
The empty lines should not be here.
| echo "staged change" >mixed.txt | ||
| git add mixed.txt | ||
| echo "unstaged change" >mixed.txt |
There was a problem hiding this comment.
You need double >> here to not overwrite the file.
| echo "staged change" >mixed.txt | |
| git add mixed.txt | |
| echo "unstaged change" >mixed.txt | |
| echo "staged change" >> mixed.txt | |
| git add mixed.txt | |
| echo "unstaged change" >> mixed.txt |
| function test_restore_with_renamed_file() { | ||
| echo "rename content" >before-rename.txt | ||
| git add before-rename.txt | ||
| git commit -q -m "Add file for rename test" | ||
| git mv before-rename.txt after-rename.txt | ||
| git commit -q -m "Rename file" | ||
| echo "modified after rename" >after-rename.txt | ||
| _forgit_git_restore after-rename.txt | ||
| assert_same "rename content" "$(cat after-rename.txt)" | ||
| } |
There was a problem hiding this comment.
Because you commit the file after renaming, the renaming does not have any effect anymore in this case.
| function test_restore_passes_through_arguments_when_non_flags_provided() { | ||
| echo "original" >passthrough.txt | ||
| git add passthrough.txt | ||
| git commit -q -m "Add passthrough file" | ||
| echo "modified" >passthrough.txt | ||
| _forgit_restore passthrough.txt | ||
| assert_same "original" "$(cat passthrough.txt)" | ||
| } |
There was a problem hiding this comment.
This test has nothing to do with what it's name implies.
| reflog) _git-forgit-reflog ;; | ||
| rebase) _git-rebase ;; | ||
| reset_head) _git-staged ;; | ||
| restore) _git-checkout-file ;; |
There was a problem hiding this comment.
Git has completions for git restore (_git-restore for zsh and _git_restore for bash). Any reason not to use those?
| } | ||
|
|
||
| # git restore selector | ||
| _forgit_restore() { |
There was a problem hiding this comment.
One very neat thing about git restore IMO is that it allows to not only discard modified files, but also allows unstaging files with --staged and discarding from the working tree and the index (staged files) with --staged --worktree. I think it would be worth adding support for this, which would require us to do a bit of argument parsing to determine which files to show in the selection:
- no
--staged-> modified --staged-> staged files--staged --worktree-> modified and staged files
Would you be willing to implement this with this PR @jetm?
| echo "initial" >README.md | ||
| git add README.md | ||
| git commit -q -m "Initial commit" |
There was a problem hiding this comment.
This file is added and committed here, but not actually used in any of the tests, so this section should be removed.
| } | ||
|
|
||
| function test_restore_reverts_modified_file_to_committed_state() { | ||
| echo "original content" >tracked.txt |
There was a problem hiding this comment.
Very minor nitpick, but could you please add an extra space after the redirects? This applies to all redirects in this file.
| echo "original content" >tracked.txt | |
| echo "original content" > tracked.txt |
Summary
Add an interactive
git restorecommand (grs) that provides an fzf-basedselector for discarding unstaged changes to working tree files. Closes #447.
Problem
There is no interactive way to selectively discard modifications to working
tree files. Users must either manually type file paths with
git restoreoruse
git checkout, which is the older discouraged syntax.Changes
_forgit_restorefunction with fzf-based file selector and diff previewgrsalias, consistent with existing forgit commandsCheck list
Type of change
Test environment