Skip to content

sugarcraft/sugar-stash

Repository files navigation

sugar-stash

SugarStash

CI codecov Packagist Version License PHP

demo

Three-pane git TUI on the SugarCraft stack — port of jesseduffield/lazygit. Status / branches / log laid out side-by-side, single-key stage / unstage, refresh, and ahead/behind branch summary.

composer require sugarcraft/sugar-stash
sugar-stash    # run inside any git working tree

Keys

Key Action
Tab Cycle pane focus
↑/↓ or k/j Move cursor in active pane
s (status pane) Stage / unstage the highlighted entry
a (status pane) Stage all files
d (status pane) Discard changes to the highlighted file
P (status pane) Open diff viewer for the highlighted file
Space (branches pane) Checkout branch
c Commit (type message, Enter to confirm, Esc to cancel)
A Amend last commit
n Create and switch to a new branch
u Undo last operation
Ctrl+r Redo last undone operation
D (branches pane) Delete the selected branch
M Merge selected branch into current
r Open rebase menu (continue / abort / skip / cancel)
S Open stash manager (list / apply / drop)
V Cherry-pick — type a commit ref and press Enter
w (branches pane) Open worktrees manager (list / add / remove)
i Interactive rebase — select N commits, set actions
R Refresh from disk
? Context-sensitive help
q / Esc Quit

Diff viewer keys

Key Action
Space Stage current hunk
↑/↓ or k/j Navigate between hunks
Esc Close diff viewer

Architecture

File Role
Git Concrete git shell-out — status --porcelain=v1 -b, for-each-ref, log --pretty=format:…, add, restore --staged. Throws RuntimeException on non-zero exit.
GitDriver Interface for all git operations. Tests inject a fixture-backed driver so transition correctness is asserted without staging a real repo.
Pane Enum — Status, Branches, Log — with next() for Tab cycling.
App (Model) Owns the three lists + cursors + focus + overlays (stash/cherry-pick/worktrees/interactive-rebase). Pure-state — every key returns a fresh App.
Renderer Pure view function — three Style::border(rounded) panes joined horizontally / vertically; the focused pane gets a brighter accent.
StashEntry Immutable stash entry — index, sha, branch, message + stashRef() / displayLine().
StashManager Immutable stash list state — stashes, cursor, withCursor(), withStashes(), current(), count().
CherryPick Immutable cherry-pick state — collecting flag + commitRef accumulator + withChar()/cancel().
WorktreeEntry Immutable worktree entry — path, branch, isBare, HEAD.
Worktrees Immutable worktree manager state — worktrees, cursor, adding/removing modes + path/branch collection.
RebaseAction Enum — Pick, Reword, Edit, Squash, Drop.
RebaseCommit Immutable rebase todo entry — sha, subject, action + withAction() / displayLine().
InteractiveRebase Immutable interactive-rebase state — commits todo list, cursor, selectingN/countInput, cycleAction(), dropCurrent().

SugarStash shells out to git directly via the system, so users keep their existing aliases, hooks, and signing config.

Note: All git operations are synchronous and block the event loop. This is by design for v1 — a TTY application naturally runs synchronously at the terminal. Async git operations are planned for v2 (see GitDriver interface for deprecation notes).

Internationalization

User-facing strings are internationalized via SugarCraft\Stash\Lang::t(). All translatable strings live in lang/en.php under the 'stash' namespace.

Available keys (lang/en.php):

Key Default string Parameters
git.spawn_failed git: failed to spawn
git.error git: {stderr} {stderr}
cli.not_a_repo sugar-stash: not a git repository (no .git in {cwd}) {cwd}
ui.error_prefix error:
status.clean clean working tree
branches.empty (no branches)
log.empty (empty log)
help.keyhints tab switch pane · j/k move · s stage/unstage · R refresh · q quit

To add a locale, copy lang/en.php to lang/<code>.php and translate the values. The lookup chain follows SugarCraft\Core\I18n\T: exact locale → base language → en → raw key.

Using the facade:

use SugarCraft\Stash\Lang;

$msg = Lang::t('status.clean');                 // 'clean working tree'
$hint = Lang::t('help.keyhints');               // 'tab  switch pane  ·  ...'
$err = Lang::t('ui.error_prefix') . $error;     // 'error: <msg>'

Adding new translatable strings:

// In any source file:
use SugarCraft\Stash\Lang;

// Simple key:
$msg = Lang::t('status.clean');

// With placeholder:
$msg = Lang::t('git.error', ['stderr' => $stderr]);

Demos

Staging workflow

stage

Shared foundations

sugar-stash uses candy-fuzzy for Smith-Waterman scored matching infrastructure, laying the groundwork for future fuzzy stash search.

Test

composer install
vendor/bin/phpunit

About

Terminal Git client — port of jesseduffield/lazygit on the SugarCraft stack.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages