libra stash
Command reference for `libra stash`
Stash the changes in a dirty working directory away.
Synopsis
libra stash push [-m <message>] [-u | -a] [-k | --keep-index] [-- <pathspec>...]
libra stash pop [<stash>]
libra stash list
libra stash apply [<stash>]
libra stash drop [<stash>]
libra stash show [<stash>] [-p | --patch] [--name-only | --name-status]
libra stash branch <branch> [<stash>]
libra stash clear [--force]Description
libra stash saves your local modifications to a new stash entry and reverts the working directory to match HEAD. By default, stash push records tracked index/worktree changes and leaves untracked files alone. Use -u / --include-untracked to include visible untracked files, or -a / --all to include ignored files too. Pass -- <pathspec>... (file or directory paths; . selects the whole tree) to stash only the changes to those paths, leaving every other change in the working tree. A pathspec cannot be combined with -u/-a/-k. The modifications can be restored later with libra stash pop or libra stash apply, which replay the stash onto the CURRENT working tree (not HEAD) — so any unrelated uncommitted change you made in the meantime, including the paths a pathspec push left behind, is preserved. Default apply / pop leave the current index intact, so restored tracked changes appear as unstaged working-tree changes; Git's --index restore mode is not exposed yet. If stash push is run on a clean working tree and no requested untracked files exist, it exits successfully as a no-op and reports that there are no local changes to save.
Stash entries are stored as specially-structured commit objects under .libra/refs/stash, with a flat-file list tracking the stash stack. Each stash captures both the index state and worktree state at the time of creation.
Options
Subcommands
push
Save your local modifications to a new stash and clean the working directory.
| Option | Short | Long | Description |
|---|---|---|---|
| Message | -m | --message | Optional descriptive message for the stash entry. If omitted, a default "WIP on <branch>: <short-hash> ..." message is generated. |
| Include untracked | -u | --include-untracked | Include visible untracked files in the stash and remove them from the worktree. Ignored files remain in place. |
| No include untracked | --no-include-untracked | Do not include untracked files (the default), countermanding an earlier -u/--include-untracked (last one wins). Untracked files are excluded by default, so on its own this is a no-op. | |
| Include all | -a | --all | Include visible untracked and ignored files in the stash, then remove them from the worktree. |
| Keep index | -k | --keep-index | Keep staged changes in the index and restore the worktree to the staged content, removing only unstaged deltas. |
# Save with default message
libra stash push
# Save with a descriptive message
libra stash push -m "work in progress on feature X"
# Include visible untracked files
libra stash push -u
# Include ignored files too
libra stash push -a
# Stash only unstaged deltas while keeping staged content ready to commit
libra stash push --keep-index
# Stash only the changes to specific paths (here a file and a directory),
# leaving every other change in the working tree
libra stash push -- src/main.rs docs/pop
Apply the top stash entry and remove it from the stash list. Equivalent to apply followed by drop. By default, restored tracked changes are written to the working tree only and are not staged.
| Argument | Description |
|---|---|
<stash> | Stash reference, e.g. stash@{1}. Defaults to stash@{0} (the most recent stash). |
# Pop the latest stash
libra stash pop
# Pop a specific stash
libra stash pop stash@{2}list
List all stash entries with their index, message, and stash ID.
libra stash listapply
Apply a stash entry without removing it from the stash list. Useful when you want to apply the same stash to multiple branches. By default, restored tracked changes are written to the working tree only and are not staged.
| Argument | Description |
|---|---|
<stash> | Stash reference, e.g. stash@{1}. Defaults to stash@{0}. |
libra stash apply
libra stash apply stash@{1}drop
Remove a single stash entry from the stash list without applying it.
| Argument | Description |
|---|---|
<stash> | Stash reference, e.g. stash@{1}. Defaults to stash@{0}. |
libra stash drop
libra stash drop stash@{1}show
Show the file-level changes recorded in a stash entry.
| Argument / Flag | Description |
|---|---|
<stash> | Stash reference, e.g. stash@{1}. Defaults to stash@{0}. |
-p / --patch | Show the stashed changes as a unified diff (patch) instead of the file-level summary. |
--name-only | Show only the changed file names, one per line. |
--name-status | Show file names prefixed with the status code (A / M / D). |
--name-only and --name-status are mutually exclusive in human render mode; the JSON envelope always carries the full files list with status, regardless of which hint is set. With -p/--patch, the human output is the unified diff (no summary footer) and the JSON envelope adds a patch field (absent otherwise).
# File-level summary of stash@{0}
libra stash show
# Inspect a specific stash entry
libra stash show stash@{1}
# Show the stashed changes as a unified diff
libra stash show -p
# File names only
libra stash show --name-onlybranch
Create a new branch from a stash entry, apply the stash on it, then drop the entry. Useful when a stash applies cleanly only on a branch that no longer exists, or when you want to resume the stashed work as a normal branch.
| Argument | Description |
|---|---|
<branch> | Name of the new branch to create. Required. |
<stash> | Stash reference, e.g. stash@{1}. Defaults to stash@{0}. |
# Branch off the latest stash and drop it
libra stash branch hotfix
# Branch off a specific stash
libra stash branch hotfix stash@{2}clear
Remove every stash entry. Outside --json / --machine mode, --force is required to prevent accidental data loss.
| Flag | Description |
|---|---|
--force | Skip the confirmation requirement. Mandatory in human mode; bypassed automatically in JSON / machine mode. |
# Human mode (refuses without --force)
libra stash clear --force
# JSON mode (--force not required)
libra stash clear --jsonGlobal Flags
| Flag | Description |
|---|---|
--json | Emit structured JSON output |
--quiet | Suppress human-readable output |
Common Commands
# Save current changes
libra stash push
# Save with a message
libra stash push -m "work in progress on feature X"
# Save tracked changes plus visible untracked files
libra stash push -u
# Save unstaged deltas without disturbing staged content
libra stash push --keep-index
# List stashes
libra stash list
# Apply and remove the latest stash
libra stash pop
# Apply without removing
libra stash apply
# Drop a specific stash
libra stash drop stash@{1}
# JSON output for scripting
libra stash list --jsonHuman Output
stash push (with changes):
Saved working directory and index state WIP on main: abc1234 ...stash push (clean working tree):
No local changes to savestash list:
stash@{0}: WIP on main: abc1234 initial commit
stash@{1}: On main: work in progress on feature Xstash pop / stash apply:
On branch main
Changes restored from stash@{0}stash drop:
Dropped stash@{0} (abc1234...)Structured Output (JSON)
When --json is passed, all subcommands produce a JSON envelope:
{
"command": "stash",
"data": {
"action": "push",
"message": "WIP on main: abc1234 ...",
"stash_id": "..."
}
}When -u, -a, or --keep-index is used, the push envelope adds only the relevant fields:
{
"command": "stash",
"data": {
"action": "push",
"message": "WIP on main: abc1234 ...",
"stash_id": "...",
"included_untracked": 2,
"kept_index": true
}
}On a clean working tree, stash push --json returns:
{
"command": "stash",
"data": { "action": "noop", "message": "No local changes to save" }
}The data.action field is one of: noop, push, pop, apply, drop, list, show, branch, clear.
list JSON schema
{
"command": "stash",
"data": {
"action": "list",
"entries": [
{ "index": 0, "message": "WIP on main: ...", "stash_id": "abc1234..." }
]
}
}pop / apply JSON schema
{
"command": "stash",
"data": {
"action": "pop",
"index": 0,
"stash_id": "abc1234...",
"branch": "main"
}
}drop JSON schema
{
"command": "stash",
"data": {
"action": "drop",
"index": 0,
"stash_id": "abc1234..."
}
}show JSON schema
{
"command": "stash",
"data": {
"action": "show",
"stash": "stash@{0}",
"stash_id": "abc1234...",
"files": [
{ "path": "src/foo.rs", "status": "M" }
],
"files_changed": {
"total": 1,
"added": 0,
"modified": 1,
"deleted": 0
}
}
}The structured envelope always emits the full files list. The --name-only / --name-status flags only affect human render output.
branch JSON schema
{
"command": "stash",
"data": {
"action": "branch",
"branch": "hotfix",
"stash": "stash@{0}",
"stash_id": "abc1234...",
"applied": true,
"dropped": true
}
}clear JSON schema
{
"command": "stash",
"data": {
"action": "clear",
"cleared_count": 3
}
}Design Rationale
How untracked and ignored files are stored
stash push -u and stash push -a use a third stash parent for the untracked/all snapshot, matching Git's object topology. stash apply and stash pop restore those files as untracked worktree files. If a local file would be overwritten during restore, the apply/pop operation fails and keeps the stash entry intact.
How pop / apply treat the index
Default stash pop and stash apply restore tracked content to the working tree while leaving the current index unchanged. A change that was staged when stashed comes back as an unstaged working-tree edit unless a future --index mode is added. This matches Git's default stash pop / stash apply behavior and prevents a later libra commit from committing restored stash content before the user runs libra add.
How --keep-index works
stash push --keep-index stores the same stash metadata as a normal push, then writes the saved index back and restores the worktree to the index state. For a mixed file with both staged and unstaged edits, the staged content remains in the index and worktree, while the unstaged delta is saved in the stash.
Why a curated subcommand model?
Git's stash has grown organically and supports git stash as a shorthand for git stash push, plus git stash save (deprecated) and the plumbing pair git stash create / git stash store. Libra exposes the eight subcommands users actually reach for in practice: push, pop, list, apply, drop, show, branch, and clear. The plumbing pair (create / store) and the save shorthand are deferred — see docs/development/commands/_compatibility.md sections D8 and D9. This keeps the surface aligned with stock Git for everyday workflows while leaving rarely-used plumbing out of the maintained surface.
Why stash@{N} syntax instead of plain indices?
Libra preserves Git's stash@{N} reference syntax for familiarity. Users migrating from Git can use the same muscle memory. The parser also accepts bare integers in some contexts, but the canonical form remains stash@{N}.
Parameter Comparison: Libra vs Git vs jj
| Parameter | Libra | Git | jj |
|---|---|---|---|
| Push (save changes) | stash push | stash push / stash save (deprecated) | N/A (no stash; use jj new to shelve) |
| Message | -m <message> | -m <message> | N/A |
| Keep index | --keep-index | --keep-index / --no-keep-index | N/A |
| Include untracked | -u / --include-untracked | -u / --include-untracked | N/A |
| No include untracked | --no-include-untracked (countermands -u) | --no-include-untracked | N/A |
| Include all (ignored too) | -a / --all | -a / --all | N/A |
| Pathspec (partial stash) | stash push -- <pathspec>... (file/dir paths, . = whole tree; not combinable with -u/-a/-k → LBR-CLI-002; no match → LBR-CLI-003) | stash push [--] <pathspec>... | N/A |
| Pop | stash pop [ref] | stash pop [--index] [<stash>] | N/A |
| Apply | stash apply [ref] | stash apply [--index] [<stash>] | N/A |
| Drop | stash drop [ref] | stash drop [<stash>] | N/A |
| List | stash list | stash list [<log-options>] | N/A |
| Show file-level summary | stash show [<stash>] [--name-only | --name-status] | stash show [<stash>] | N/A |
| Show stash as a patch | stash show -p | --patch [<stash>] | stash show -p [<stash>] | N/A |
| Create branch from stash | stash branch <branch> [<stash>] | stash branch <branch> [<stash>] | N/A |
| Clear all stashes | stash clear [--force] | stash clear | N/A |
| Plumbing create/store | Not supported (deferred — see compatibility/declined.md D8/D9) | stash create / stash store | N/A |
| JSON output | --json | Not supported | N/A |
| Quiet mode | --quiet | -q / --quiet | N/A |
Note: jj does not have a stash command. Its change-based model allows creating anonymous changes with jj new that serve a similar purpose to stashing.
Error Handling
| Code | Condition |
|---|---|
LBR-REPO-001 | Not a libra repository |
LBR-REPO-003 | No initial commit |
LBR-CLI-002 | Invalid stash reference syntax |
LBR-CLI-003 | Stash does not exist |
LBR-CONFLICT-001 | Merge conflict during stash apply |