zed/crates/git
Priyadharshan 4bdf188c99
Added Tracked , Staged options to stash (#62254)
# Objective

Closes #62252 

The Git Panel could only stash *everything* — `Stash All` runs
`git stash push --include-untracked`, sweeping tracked edits and
untracked files
into a single entry. There was no way to stash a subset, so the common
workflows
of "park my tracked edits but keep my new scratch files" and "park what
I've
staged and keep working on the rest" required dropping to the terminal.

## Images

<img width="389" height="358" alt="Screenshot 2026-08-10 at 3 10 50 PM"
src="https://github.com/user-attachments/assets/18e4c943-e320-4802-ada8-59e54bf4cefd"
/>

<img width="504" height="462" alt="Screenshot 2026-08-10 at 3 10 37 PM"
src="https://github.com/user-attachments/assets/783237eb-980d-47bc-a0f5-17b03a23a60c"
/>






## Solution

Add two stash variants alongside `Stash All`, surfaced in the Git
Panel's
overflow menu based on how the list is currently grouped, so the menu
mirrors the
sections the user can actually see:

| Group By | Stash entries offered |
| --- | --- |
| None | Stash All |
| Tracked & Untracked | Stash All, **Stash Tracked** |
| Staged & Unstaged | Stash All, **Stash Staged** |

- **`git::StashTracked`** stashes tracked changes and leaves untracked
files in
place. It reuses the existing pathspec plumbing
(`Repository::stash_entries`),
  filtering the status list down to the paths to stash.
- **`git::StashStaged`** stashes the index only, leaving unstaged
changes in
place. This *cannot* be expressed as a pathspec — a partially staged
file would
have its unstaged hunks stashed too — so it needs git's own `--staged`
flag.
  That meant a new `GitRepository::stash_staged` backend method and an
`optional bool staged` field on `proto::Stash` so remote projects work
too.

Both actions are unbound by default and are dispatchable from the
command palette
when the panel is focused.

One subtlety worth calling out for review: `Stash Tracked` filters on
`FileStatus::is_created()`, not `is_untracked()`. Staging a new file
flips it from
`Untracked` to `Tracked { Added }`, but the panel still lists it under
**Untracked** — using `is_untracked()` meant staged-new files were
silently
stashed. `is_created()` is the same predicate the panel uses to build
that section
(`git_panel.rs`), so the menu item and the list can no longer disagree.

This branch also includes a separate commit adding **per-section
staging**
(`git::StageSection` / `git::UnstageSection`) — right-click a file to
stage or
unstage every entry in its section. Happy to split that into its own PR
if
preferred.

## Testing

Manually tested on macOS against a scratch repo with a mix of states:
modified
tracked files, untracked files, and untracked files that had been
staged.

- `Stash Tracked` with tracked edits + untracked files → only tracked
edits
  stashed; untracked files remain.
- `Stash Tracked` with untracked files **staged** → they remain, staged.
This was
  broken in an earlier revision and drove the `is_created()` fix above.
- `Stash Staged` with one file staged and another modified-but-unstaged
→ only the
  staged file is stashed; the unstaged edit and untracked files survive.
- `Stash Pop` round-trips both cases back to the original state, with no
conflicts.
- Menu contents and disabled states verified in all three Group By
modes.
- Per-section staging covered by a new unit test,
  `test_stage_section_scopes_to_selected_section`.

Not covered by automated tests: the stash actions themselves.
`FakeGitRepository`
leaves every stash method `unimplemented!()`, so stash behavior isn't
reachable
from GPUI tests today — consistent with the existing untested
`StashAll`. Adding
fake-repo stash support looks like a worthwhile follow-up but felt out
of scope here.

Reviewers on non-macOS platforms: nothing here is platform-specific.
Note that
`Stash Staged` requires **git 2.35+** (Jan 2022) for `git stash push
--staged`;
older git surfaces a clear error toast rather than failing opaquely. The
remote
path (`proto::Stash.staged`) has not been exercised against a live
collab session.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Added `Stash Tracked` and `Stash Staged` options to the Git Panel,
letting you stash only tracked changes or only staged changes.

---------

Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
2026-08-18 05:36:16 +00:00
..
src Added Tracked , Staged options to stash (#62254) 2026-08-18 05:36:16 +00:00
test_data Add an undo button to the git panel (#24593) 2025-02-12 15:57:08 -07:00
Cargo.toml Remove git2 (libgit2) dependency (#53453) 2026-06-02 05:35:36 +00:00
clippy.toml git: Add trusted worktree support to git integrations (#50649) 2026-03-04 12:19:13 +00:00
LICENSE-GPL