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>
This commit is contained in:
1 parent
52f9567fb4
commit
f652da59e8
8 files changed
+520
-14
No files matched your search
+12
-2
@@ -155,6 +155,8 @@ From the panel, you can simply type a commit message and hit the commit button,
|
||||
|
||||
Entries can be staged using each individual entry's checkbox. All changes can be staged using the button at the top of the panel, or {#action git::StageAll}.
|
||||
|
||||
Entries are grouped into sections (**Tracked** and **Untracked** by default), and each section can be staged on its own without touching the others. Click the checkbox on a section header, or use {#action git::StageSection} / {#action git::UnstageSection}, which act on the section containing the selected entry. These are also available by right-clicking an entry. Neither is bound by default; bind them in your keymap under the `GitPanel` context if you use them often.
|
||||
|
||||
To open a changed file in the editor without a diff view, right-click on the file in the Git Panel and select **View File**. Use **Open Diff** ({#kb menu::Confirm}) or **Open Diff (File)** to review changes in a diff view instead.
|
||||
|
||||
<!-- Add media -->
|
||||
@@ -255,9 +257,13 @@ Git stash allows you to temporarily save your uncommitted changes and revert you
|
||||
|
||||
### Creating Stashes
|
||||
|
||||
To stash all your current changes, use the {#action git::StashAll} action. This will save both staged and unstaged changes to a new stash entry and clean your working directory.
|
||||
To stash all your current changes, use the {#action git::StashAll} action. This will save both staged and unstaged changes, including untracked files, to a new stash entry and clean your working directory.
|
||||
|
||||
The action first prompts for an optional stash name. Confirming with an empty prompt lets git generate its usual `WIP on ...` description.
|
||||
To stash only tracked changes and leave untracked files in place, use the {#action git::StashTracked} action. To stash only staged changes and leave unstaged changes in place, use the {#action git::StashStaged} action; this requires git 2.35 or newer.
|
||||
|
||||
The Git Panel's overflow menu offers whichever of these matches the current **Group By** mode: **Stash Tracked** when grouping by Tracked & Untracked, and **Stash Staged** when grouping by Staged & Unstaged. **Stash All** is always available.
|
||||
|
||||
Each of these actions first prompts for an optional stash name. Confirming with an empty prompt lets git generate its usual `WIP on ...` description.
|
||||
|
||||
### Managing Stashes
|
||||
|
||||
@@ -385,6 +391,8 @@ When viewing files with changes, Zed displays diff hunks that can be expanded or
|
||||
| {#action git::Add} | {#kb git::Add} |
|
||||
| {#action git::StageAll} | {#kb git::StageAll} |
|
||||
| {#action git::UnstageAll} | {#kb git::UnstageAll} |
|
||||
| {#action git::StageSection} | {#kb git::StageSection} |
|
||||
| {#action git::UnstageSection} | {#kb git::UnstageSection} |
|
||||
| {#action git::ToggleStaged} | {#kb git::ToggleStaged} |
|
||||
| {#action git::StageAndNext} | {#kb git::StageAndNext} |
|
||||
| {#action git::UnstageAndNext} | {#kb git::UnstageAndNext} |
|
||||
@@ -404,6 +412,8 @@ When viewing files with changes, Zed displays diff hunks that can be expanded or
|
||||
| {#action git::Worktree} | {#kb git::Worktree} |
|
||||
| {#action git::Blame} | {#kb git::Blame} |
|
||||
| {#action git::StashAll} | {#kb git::StashAll} |
|
||||
| {#action git::StashTracked} | {#kb git::StashTracked} |
|
||||
| {#action git::StashStaged} | {#kb git::StashStaged} |
|
||||
| {#action git::StashPop} | {#kb git::StashPop} |
|
||||
| {#action git::StashApply} | {#kb git::StashApply} |
|
||||
| {#action git::ViewStash} | {#kb git::ViewStash} |
|
||||
|
||||
Reference in new issue
Block a user