Skip to content

Add interactive git discard command#489

Open
jetm wants to merge 3 commits intowfxr:mainfrom
jetm:forgit-discard
Open

Add interactive git discard command#489
jetm wants to merge 3 commits intowfxr:mainfrom
jetm:forgit-discard

Conversation

@jetm
Copy link

@jetm jetm commented Feb 2, 2026

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

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have added unit tests for my code
  • I have made corresponding changes to the documentation

Description

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Test
  • Documentation change

Test environment

  • Shell
    • bash
    • zsh
    • fish
  • OS
    • Linux
    • Mac OS X
    • Windows
    • Others:

jetm added 3 commits February 2, 2026 12:31
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>
Copy link

Copilot AI left a comment

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 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.

Comment on lines +67 to +89
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"
}
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +534 to +539
# 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
Copy link
Owner

Choose a reason for hiding this comment

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

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?

Copy link
Collaborator

@sandr01d sandr01d Feb 5, 2026

Choose a reason for hiding this comment

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

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.

Copy link
Owner

Choose a reason for hiding this comment

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

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants