Conversation
Currently there is no way to interactively unstage and discard staged changes in one operation. Users must manually unstage files with git restore -S and then discard changes with git restore, or risk using git reset --hard which discards all changes indiscriminately. This makes it cumbersome to selectively abandon staged work while keeping other staged changes intact. Add a new discard command that combines unstaging and discarding in an interactive workflow. The command presents staged files in fzf with diff previews, then safely unstages and restores selected files in one operation. For newly added files, only unstaging occurs since they have no prior state to restore. This provides a safe, selective way to abandon staged work without affecting other changes or requiring multiple manual commands. Signed-off-by: Javier Tia <floss@jetm.me>
The discard feature currently lacks automated test coverage, making it difficult to verify correct behavior and prevent regressions when modifying the implementation. Without tests, changes to how discard handles staged files, untracked files, or restoration logic risk breaking existing workflows. Add comprehensive test suite covering all discard scenarios: rejecting operations when no files are staged, restoring tracked files to their committed state, converting newly-staged files back to untracked status, and properly unstaging modifications. These tests ensure the discard operation maintains expected Git semantics across different file states and provides confidence for future refactoring. Signed-off-by: Javier Tia <floss@jetm.me>
Currently, unstaging and reverting uncommitted changes requires running separate git reset and git checkout commands. This is error-prone and lacks the interactive file selection that other forgit commands provide, forcing users to manually specify files or risk discarding unintended changes. Add forgit_discard (gdc) command that combines unstaging and reverting into a single interactive operation. This provides a safer workflow by showing a preview of changes before discarding and allows selective file-by-file confirmation, consistent with forgit's design philosophy of making destructive operations more deliberate. Signed-off-by: Javier Tia <floss@jetm.me>
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.
| function test_discard_unstages_files() { | ||
| # Create and commit a file | ||
| echo "original" > unstage-test.txt | ||
| git add unstage-test.txt | ||
| git commit -q -m "Add file for unstage test" | ||
|
|
||
| # Modify and stage the file | ||
| echo "modified" > unstage-test.txt | ||
| git add unstage-test.txt | ||
|
|
||
| # Verify file is staged | ||
| local staged_before | ||
| staged_before=$(git diff --staged --name-only) | ||
| assert_contains "unstage-test.txt" "$staged_before" | ||
|
|
||
| # Call discard | ||
| _forgit_git_discard unstage-test.txt | ||
|
|
||
| # Verify file is no longer staged | ||
| local staged_after | ||
| staged_after=$(git diff --staged --name-only) | ||
| assert_not_contains "unstage-test.txt" "$staged_after" | ||
| } |
There was a problem hiding this comment.
This test only verifies that the file is unstaged but does not verify that the file content is restored to its original state. The discard operation should both unstage AND revert the file content to the last committed state. Consider adding an assertion to check that the file content is "original" after calling _forgit_git_discard.
| # Only restore tracked files (new files become untracked after unstaging) | ||
| for file in "$@"; do | ||
| if _forgit_is_file_tracked "$file"; then | ||
| git restore "${_forgit_discard_git_opts[@]}" -- "$file" | ||
| fi | ||
| done |
There was a problem hiding this comment.
I'm wondering if we should limit this command to just unstaging rather than combining unstage + discard?
Sometimes we accidentally stage a file and simply want to move it back to the unstaged state — without discarding the actual changes. If someone truly needs to discard modifications, the existing forgit_checkout_file (gcf) already handles that use case well.
What do you think about keeping the two operations separate?
There was a problem hiding this comment.
I agree that unstaging and discarding should be two separate options. One of the main concepts of git is the separation between file states (tracked, untracked, staged) and I don't think we should break with this concept.
However, we already have a command for unstaging too (_forgit_reset_head/grh) and there are plans to add a new command for git restore (#447). So is introducing yet another unstage command necessary? Maybe this PR could be refactored to solve #447 instead.
There was a problem hiding this comment.
Thanks for pointing this out, @sandr01d. I have to admit I had been overlooking the existing grh command, which already covers the unstaging use case quite well.
@sandr01d's suggestion sounds good to me: it would be more valuable to pivot this PR toward implementing #447 (interactive git restore) instead. @jetm What do you think? Would you be interested in refactoring this PR to tackle #447?
Currently, unstaging and reverting uncommitted changes requires
running separate git reset and git checkout commands. This is
error-prone and lacks the interactive file selection that other
forgit commands provide, forcing users to manually specify files or
risk discarding unintended changes.
Add forgit_discard (gdc) command that combines unstaging and
reverting into a single interactive operation. This provides a safer
workflow by showing a preview of changes before discarding and allows
selective file-by-file confirmation, consistent with forgit's design
philosophy of making destructive operations more deliberate.
Check list
Description
Type of change
Test environment