diff --git a/PRODUCT_ROADMAP.md b/PRODUCT_ROADMAP.md index 9be21f1..d0fed33 100644 --- a/PRODUCT_ROADMAP.md +++ b/PRODUCT_ROADMAP.md @@ -1,409 +1,266 @@ -# wgit Product Roadmap +# wgit Product Roadmap (Baseline: current `work` branch) -## Vision +> Note: there is no local `master` branch in this checkout, so this roadmap is grounded in the current codebase baseline available in this repository. -`wgit` becomes a fast, keyboard-friendly, GPU-rendered desktop Git client for developers who want the clarity of terminal Git with the discoverability of a visual client. +## 1) Repository Audit Summary (Detailed Search) -The product should feel: +This roadmap is based on a code-and-test audit of: -- Native and responsive on large repositories -- Safe for high-impact Git actions -- Strong for daily workflows before edge-case power features -- Visually distinct from Electron-style Git clients +- `src/git_model.rs` for Git capability surface and command safety boundaries +- `src/app.rs` and `src/models.rs` for UX surface and interaction modes +- `src/main.rs` + `src/repo_store.rs` for startup and repository lifecycle +- `tests/git_model_backend.rs` + in-file `git_model` tests for backend behavior coverage +- `Cargo.toml` for dependency and platform constraints -## Current State +### Implemented capabilities (today) -Today the app already has a strong prototype foundation: +#### Core desktop UX shell +- Native `winit` + `wgpu` app shell and custom renderer +- Split view: files/status pane and diff pane +- Keyboard/mouse navigation, pane focus, divider/zoom state +- Toolbar + status feedback patterns -- Custom `wgpu` + `winit` desktop shell -- Repository discovery -- Working tree status list -- Selected-file diff view -- Stage / unstage selected file -- Basic syntax coloring for Rust and TOML diff content +#### Repository lifecycle +- Open current repo (`GitModel::open()`) +- Open explicit repo path (`--repo` or positional path) +- Recover from non-repo cwd by trying recent repos +- Persist up to 12 recent repositories in `~/.wgit/recent_repos.txt` -That means `wgit` is not starting from zero. The right next step is to evolve it from a "status + diff viewer" into a safe, complete Git workstation. - -## Product Pillars - -### 1. Everyday Git First - -Make the common path excellent: - -- Review changes -- Stage selectively -- Commit confidently -- Pull / push safely -- Manage branches without context switching to terminal - -### 2. Speed and Clarity - -Lean into the custom renderer: - -- Very fast list rendering -- Large diff performance -- Dense information layout -- Strong keyboard navigation - -### 3. Safe Power - -Git clients fail when dangerous actions are too easy or too opaque. `wgit` should emphasize: - -- Clear previews -- Undo / recovery where possible -- Confirmation for destructive actions -- Explicit state transitions - -### 4. Progressive Depth - -The app should work well for both: - -- Users doing `status`, `commit`, `pull`, `push`, `branch` -- Users handling rebase, cherry-pick, stash, history inspection, conflict resolution - -## Target Personas - -### Primary - -- Developers who know Git, but want a faster visual workflow -- Rust / native-tooling enthusiasts who care about responsiveness - -### Secondary - -- Developers learning Git who need guardrails -- Users managing medium-to-large repositories where terminal diffing is noisy - -## Product Strategy - -Sequence the roadmap in this order: - -1. Complete the daily workflow -2. Add history and branch fluency -3. Add collaboration and remote workflows -4. Add recovery and advanced Git operations -5. Polish performance, trust, and platform quality - -This avoids over-investing in advanced Git before the app can replace day-to-day terminal usage. - -## Milestones - -## Milestone 0: Stabilize The Core Prototype - -Goal: turn the current prototype into a reliable base for shipping features. - -### Outcomes - -- Clean separation between Git state, view state, and render state -- Predictable refresh model -- Better error handling and user feedback -- Testable command layer around Git operations - -### Work - -- Introduce an application state model for repo, selection, panels, modal state, and async tasks -- Wrap Git actions in typed operations instead of scattered shell calls -- Add structured error surfaces in the UI -- Add fixture-based tests for status parsing and diff parsing -- Define command safety tiers: - - Safe: refresh, open history, inspect diff - - Guarded: stage, unstage, commit, checkout branch - - Dangerous: reset, discard, force push, rebase continue/abort - -### Exit Criteria - -- App no longer feels prototype-fragile -- Core Git actions can be tested without rendering -- UI can display loading, success, and failure states consistently - -## Milestone 1: Daily Workflow MVP - -Goal: make `wgit` viable for normal solo development. - -### Must-have features - -- Open any repo, not just current working directory -- Repo switcher / recent repositories -- Working tree sections: - - Staged - - Unstaged - - Untracked -- Multi-select file staging +#### Working tree and staging flows +- Porcelain status parsing with grouped sections: + - `STAGED` + - `UNSTAGED` + - `UNTRACKED` +- Single-file stage/unstage - Stage all / unstage all -- Discard changes for selected file or hunk with confirmation -- Commit panel: - - Summary + description - - Commit validation - - Amend last commit -- Pull, fetch, push -- Ahead / behind status -- Diff view improvements: - - Side-by-side and unified modes - - Intra-line highlighting - - Image / binary-file fallback messaging -- Search / filter changed files - -### UX requirements - -- Keyboard shortcuts for all primary actions -- Clear action affordances even without mouse precision -- Empty states and no-repo states -- Progress indicators for Git operations - -### Exit Criteria - -- A developer can finish a normal change-review, commit, and push cycle entirely in `wgit` - -## Milestone 2: History And Branching - -Goal: let users understand repository history and move across branches comfortably. - -### Features - -- Commit log view -- Commit details panel -- File history -- Blame view -- Branch list: - - local branches - - remote branches - - current branch -- Create branch -- Rename branch -- Delete branch with guardrails -- Checkout branch -- Checkout detached commit with strong warning -- Branch comparison view -- Graph visualization for commit ancestry - -### UX requirements - -- Smooth transitions between status, history, and branch views -- Strong indicators for HEAD state -- Clear remote tracking information - -### Exit Criteria - -- User can inspect history, create / switch branches, and understand divergence without terminal help - -## Milestone 3: Collaboration And Review - -Goal: make the client useful in team workflows, not just local repo management. - -### Features - -- Fetch all remotes -- Remote management UI -- Pull with rebase option -- Push with upstream setup -- Conflict-aware pull / merge messaging -- Compare local branch to upstream -- Review mode for incoming changes -- Commit range diffing -- Tag list and tag creation - -### Stretch features - -- Optional hosting integration later for GitHub / GitLab review metadata - -Do not start hosting-service integration until core Git flows are solid. - -### Exit Criteria - -- User can safely sync, inspect incoming/outgoing work, and prepare branch changes for collaboration - -## Milestone 4: Power Git - -Goal: support advanced workflows that make the app a serious long-term client. - -### Features - -- Hunk staging -- Line staging -- Stash create / apply / pop / drop -- Cherry-pick -- Revert commit -- Interactive rebase helper -- Merge UI -- Conflict resolution workflow -- Reset modes: - - soft - - mixed - - hard -- Reflog browser -- Recoverability helpers after risky operations - -### Guardrails - -- Preview before destructive actions -- Dedicated confirmation dialogs with affected refs/files -- Plain-language explanation of consequences - -### Exit Criteria - -- Advanced users can stay in `wgit` for most non-forensic Git operations - -## Milestone 5: Product Polish And Release Quality - -Goal: make the client feel production-grade. - -### Features - -- Command palette -- Settings panel -- Theme system -- Better typography and information density controls -- Large repo performance tuning -- Background refresh / file watching -- Accessibility improvements -- Cross-platform packaging -- Crash reporting strategy -- Logging / diagnostics export - -### Non-functional priorities - -- Cold start time -- Frame pacing during scrolling -- Zero-jank diff rendering -- Robustness on monorepos and repos with many changed files - -### Exit Criteria - -- App is credible as a daily driver and ready for broader user testing - -## Cross-Cutting Tracks - -These should run alongside the milestones instead of being left to the end. - -### Safety - -- Confirmation UX for destructive actions -- Better messaging around HEAD, index, working tree, and remotes -- Recovery affordances wherever Git permits them - -### Information Architecture - -The likely long-term layout should evolve toward: - -- Left sidebar: repos, branches, stashes, tags, filters -- Center pane: status list / history list / graph -- Right pane: diff, commit details, action panels -- Modal surfaces: commit, branch create, stash, confirmations - -### Performance - -- Virtualized lists for large status / history views -- Incremental diff loading -- Background command execution -- Smarter invalidation than full-document rebuilds - -### Observability - -- Command log for recent Git operations -- Error diagnostics with actionable messages -- Metrics for operation duration and failure rate during development - -### Test Strategy - -- Parser tests for status / diff / branch output -- Integration tests against temporary fixture repositories -- Snapshot-like view-model tests for document generation -- Manual test matrix for destructive operations - -## Suggested Release Plan - -### v0.1 - -Prototype quality: - -- Current status view -- Better stability -- Open repo -- Commit -- Push / pull / fetch - -### v0.2 - -Daily-driver candidate: - -- Grouped file states -- Better diff modes -- Multi-select staging -- Branch checkout and create -- Recent repos - -### v0.3 - -History release: - -- Commit log -- Commit details -- Branch graph -- File history - -### v0.4 - -Power-user release: - -- Hunk staging -- Stash -- Cherry-pick -- Revert -- Early conflict tooling - -### v1.0 - -Proper Git client: - -- Strong daily workflow -- History and branch fluency -- Safe remote workflows -- Recovery tooling -- Stable packaging and performance - -## What To Build Next - -If we want the highest-leverage immediate sequence from the current codebase, the next 10 items should be: - -1. Add repo picker and recent repos -2. Split changed files into staged / unstaged / untracked sections -3. Add commit UI -4. Add fetch / pull / push actions with visible progress and errors -5. Add multi-select files -6. Add stage all / unstage all / discard file -7. Refactor Git operations into a typed command layer -8. Add branch list and branch checkout -9. Add commit log view -10. Add hunk-level diff interaction - -## Product Risks - -### 1. Building too much custom UI too early - -The renderer is a strength, but the product can stall if too much time goes into chrome before core Git workflows are complete. - -### 2. Unsafe Git actions - -If resets, discards, rebases, or force pushes are exposed without trust-building UX, the client will feel risky even if technically correct. - -### 3. Synchronous command execution - -As features expand, blocking Git commands will make the UI feel brittle and dated. - -### 4. Weak state modeling - -A richer client needs explicit models for selection, modal flows, async operations, and transient errors. - -## Success Metrics - -Track these as the product matures: - -- Time to review and commit a change -- Percentage of daily Git actions completed without terminal fallback -- Failure rate of Git operations -- App startup time -- Scroll smoothness in large diffs -- User confidence in destructive actions - -## Bottom Line - -`wgit` already has an interesting foundation: a native-rendered Git UI with real performance potential. The smartest path is not to chase every Git feature immediately, but to become excellent at the daily loop first, then grow into history, collaboration, and power workflows with strong safety rails. +- Discard selected file changes (tracked/untracked handling) + +#### Diff and readability +- Selected-file diff rendering +- Cached/unstaged diff behavior via backend +- Syntax highlighting (Rust + TOML) using Tree-sitter +- Diff line style classification (add/remove/hunk/meta/file headers) +- Hunk header parsing for line numbers + +#### Commit + remote basics +- Commit from UI message fields +- Fetch / pull / push operations +- Branch tracking status (ahead/behind/upstream) +- Branch list + checkout branch + +#### Existing test coverage +- Status classification and section summarization coverage in: + - unit tests inside `git_model.rs` + - integration-style tests in `tests/git_model_backend.rs` +- Recent repo parsing/writing tests in `repo_store.rs` + +## 2) Product Positioning + +`wgit` should become the **fastest native desktop Git workstation for keyboard-centric developers** by doubling down on: + +1. **Performance and clarity** (large repos, large diffs) +2. **Safe operations** (guardrails for destructive Git actions) +3. **Flow completeness** (terminal-free daily work) +4. **Progressive power** (advanced flows without UI overload) + +## 3) Gap Analysis (Current vs Desired) + +### A. Daily workflow gaps (highest user value) +- No hunk-level stage/unstage/discard +- No explicit commit validation UX (e.g., empty summary behavior guidance) +- No robust operation progress/cancellation model +- Limited filtering/search in changed files +- Pull/push UX is basic (limited remote/branch intent controls) + +### B. History/inspection gaps +- No commit graph/log view +- No commit details drill-down +- No file history and no blame view +- No comparison mode for branch-to-branch ranges + +### C. Collaboration gaps +- Remote management is not modeled in UI +- No upstream configuration workflow UX +- No conflict-resolution guided flow in-app + +### D. Recovery/power gaps +- No stash UX +- No rebase/cherry-pick UX +- No reflog/recovery visibility +- No safety tiers communicated directly in UI + +### E. Platform quality gaps +- Minimal QA matrix and release process artifacts +- No benchmark harness for large repo/diff rendering +- Limited telemetry/diagnostics for operation failures + +## 4) Roadmap Principles + +- **Principle 1: finish daily loop first** (`review -> stage -> commit -> sync`) +- **Principle 2: safety before power** (guardrails precede destructive features) +- **Principle 3: architecture before breadth** (stabilize command/state model) +- **Principle 4: keyboard-first parity** (every primary flow keyboard reachable) +- **Principle 5: measurable milestones** (acceptance criteria + success metrics) + +## 5) 4-Phase Product Roadmap + +## Phase 0 (2–3 weeks): Foundation Hardening + +### Objective +Turn prototype-quality behavior into a reliable product core. + +### Scope +- Define explicit command lifecycle states: + - idle / running / success / error +- Standardize backend action wrappers for all Git operations with consistent error payloads +- Add operation-result surfaces in UI status area +- Add fixture tests for: + - status parsing edge cases + - diff formatting edge cases (binary/renames/empty hunks) + - branch tracking parsing +- Introduce command safety tiers in UX copy for destructive actions + +### Acceptance criteria +- Every Git action reports consistent status semantics +- Error messages include command intent + actionable next step +- No silent failures in stage/unstage/commit/sync paths + +### Success metrics +- 0 known crashers in normal repo interactions +- >= 80% backend parser path coverage for status/diff/branch parsing modules + +## Phase 1 (4–6 weeks): Daily Workflow MVP + +### Objective +Make `wgit` viable for day-to-day solo development. + +### Scope +- File list productivity: + - text filter/search + - section collapse/expand + - better selection persistence on refresh +- Staging improvements: + - multi-select stage/unstage + - hunk-level stage/unstage (first iteration) +- Commit workflow: + - enforce non-empty summary + - optional amend toggle + - clearer post-commit refresh and state reset +- Sync workflow: + - explicit fetch/pull/push target controls (remote + branch) + - ahead/behind indicator prominence +- Repo workflow: + - recent repos quick switch UX improvements + +### Acceptance criteria +- User can complete `edit -> review -> hunk/file stage -> commit -> push` without terminal +- Keyboard-only path exists for core actions + +### Success metrics +- >= 90% successful completion in scripted QA tasks for daily loop +- Median action latency for stage/unstage/commit refresh < 200ms on medium repo + +## Phase 2 (5–7 weeks): History, Branching, and Insight + +### Objective +Enable users to understand change context and branch topology. + +### Scope +- Commit log view with paging/virtualization +- Commit detail panel (message, files changed, diff) +- Branch panel improvements: + - local/remote grouping + - create/delete/rename branch with guardrails +- Branch compare mode (HEAD vs selected branch) +- File history view (per-path commit list) + +### Acceptance criteria +- User can answer “what changed, where, and on which branch” fully in-app +- Branch switch operations are safe and legible + +### Success metrics +- 100% of branch-management happy paths covered by integration tests +- <= 1% branch-operation failure rate in internal dogfooding + +## Phase 3 (6–8 weeks): Collaboration + Power Safety + +### Objective +Add team-oriented and advanced Git workflows safely. + +### Scope +- Conflict-aware pull/merge UX with clear next actions +- Upstream setup and remote management workflows +- Stash flows: + - create/apply/pop/drop with previews +- Rebase/cherry-pick assistant (guided, explicit state machine) +- Recovery tools: + - reflog viewer + - “undo-oriented” action prompts where feasible + +### Acceptance criteria +- Advanced workflows remain understandable under failure states +- Destructive operations require explicit confirmations with previews + +### Success metrics +- Reduced terminal fallback for conflict and stash flows in dogfooding +- High user confidence score on destructive action clarity + +## 6) Cross-Cutting Engineering Tracks + +### Performance track (runs across all phases) +- Diff rendering virtualization for large patches +- Incremental text shaping/cache invalidation strategy +- Benchmarks: + - large monorepo status list + - large binary-heavy repo fallback behavior + +### Quality track +- Expand backend test fixtures for real-world porcelain outputs +- Add regression fixtures for branch-tracking edge cases +- Add deterministic golden outputs for grouped document rendering + +### UX consistency track +- Unified command palette + shortcut discovery +- Consistent modal language for confirmations/errors +- Color/accessibility audit for line styles and section indicators + +## 7) Release Plan + +- **v0.2.0** = Phase 0 + initial Phase 1 (stable daily basics) +- **v0.3.0** = complete Phase 1 (daily workflow MVP) +- **v0.4.0** = Phase 2 (history + branch fluency) +- **v0.5.0** = Phase 3 baseline (collab/power workflows) + +Each release should include: +- migration notes for UX shortcuts +- known limitations section +- benchmark delta report vs prior release + +## 8) Risks and Mitigations + +### Risk: Git edge cases create brittle UX +Mitigation: +- use fixture-driven parser tests +- define structured error taxonomy +- ship guarded workflows incrementally + +### Risk: Performance regressions from feature breadth +Mitigation: +- introduce benchmark gates before each release +- prioritize virtualization before heavy history views + +### Risk: Unsafe destructive operations +Mitigation: +- command safety tiers +- preview + confirm flows +- explicit recovery guidance in errors + +## 9) Immediate Next Sprint Backlog (Recommended) + +1. Standardize command result model (`ok/error/loading`) across all toolbar actions +2. Add file filter/search in status pane +3. Add commit validation + amend toggle +4. Add multi-select file stage/unstage +5. Add integration fixtures for branch tracking and diff edge cases + +These five items provide the highest ROI toward terminal-free daily usage while improving trust and product stability. diff --git a/src/app.rs b/src/app.rs index 4095337..c6311f3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -111,6 +111,7 @@ struct State { input_mode: InputMode, commit_summary: String, commit_body: String, + commit_amend: bool, repo_tracking: BranchTrackingStatus, recent_repos: Vec, repo_picker_index: usize, @@ -453,6 +454,7 @@ impl State { input_mode: InputMode::Normal, commit_summary: String::new(), commit_body: String::new(), + commit_amend: false, repo_tracking: BranchTrackingStatus::default(), recent_repos: Vec::new(), repo_picker_index: 0, @@ -625,9 +627,10 @@ impl State { self.input_mode = InputMode::CommitSummary; self.commit_summary.clear(); self.commit_body.clear(); + self.commit_amend = false; self.set_status( StatusKind::Prompt, - "Commit summary: type a subject, Enter for body, Esc to cancel", + "Commit summary: type a subject, Enter for body, Ctrl+A toggle amend, Esc to cancel", ); } @@ -655,6 +658,7 @@ impl State { self.input_mode = InputMode::Normal; self.commit_summary.clear(); self.commit_body.clear(); + self.commit_amend = false; self.pending_discard_path = None; self.branch_list.clear(); self.set_selection_status(); @@ -664,23 +668,28 @@ impl State { let message = match self.input_mode { InputMode::CommitSummary => { if self.commit_summary.is_empty() { - String::from("Commit summary: type a subject, Enter for body, Esc to cancel") + format!( + "Commit summary: type a subject, Enter for body, Ctrl+A amend({}), Esc cancel", + if self.commit_amend { "on" } else { "off" } + ) } else { format!( - "Commit summary: {} [Enter] next [Esc] cancel", - self.commit_summary + "Commit summary: {} [Enter] next [Ctrl+A] amend({}) [Esc] cancel", + self.commit_summary, + if self.commit_amend { "on" } else { "off" } ) } } InputMode::CommitBody => { if self.commit_body.is_empty() { String::from( - "Commit body: optional details, Enter to submit, Tab back, Esc cancel", + "Commit body: optional details, Enter submit, Tab back, Ctrl+A amend, Esc cancel", ) } else { format!( - "Commit body: {} [Enter] submit [Tab] back [Esc] cancel", - self.commit_body + "Commit body: {} [Enter] submit [Tab] back [Ctrl+A] amend({}) [Esc] cancel", + self.commit_body, + if self.commit_amend { "on" } else { "off" } ) } } @@ -715,14 +724,19 @@ impl State { format!("{summary}\n\n{body}") }; - self.git.commit(&message)?; + let amend = self.commit_amend; + self.git.commit_with_options(&message, false, amend)?; self.refresh_document_from_git()?; self.input_mode = InputMode::Normal; self.commit_summary.clear(); self.commit_body.clear(); + self.commit_amend = false; self.set_status( StatusKind::Success, - format!("Committed changes: {summary_for_status}"), + format!( + "Committed{}: {summary_for_status}", + if amend { " (amend)" } else { "" } + ), ); Ok(()) } @@ -799,7 +813,7 @@ impl State { text.get(5..).map(|path| PathBuf::from(path.trim())) } - fn handle_commit_input(&mut self, key: &Key) -> anyhow::Result { + fn handle_commit_input(&mut self, key: &Key, ctrl: bool) -> anyhow::Result { match key { Key::Named(NamedKey::Escape) => { self.cancel_input_mode(); @@ -829,6 +843,11 @@ impl State { Ok(true) } Key::Character(ch) => { + if ctrl && ch.eq_ignore_ascii_case("a") { + self.commit_amend = !self.commit_amend; + self.update_commit_prompt(); + return Ok(true); + } let mut changed = false; for c in ch.chars() { if !c.is_control() { @@ -1273,6 +1292,18 @@ impl State { "Commit message", [0.92, 0.96, 1.0, 1.0], )?; + let mut amend_x = panel[0] + panel[2] - self.ui(180.0); + self.append_text_run( + text_vertices, + &mut amend_x, + y + self.ascent, + &format!("Amend: {}", if self.commit_amend { "ON" } else { "OFF" }), + if self.commit_amend { + [0.66, 0.95, 0.73, 1.0] + } else { + [0.73, 0.79, 0.90, 1.0] + }, + )?; y += self.line_height * 1.2; let summary_active = matches!(self.input_mode, InputMode::CommitSummary); @@ -1363,7 +1394,7 @@ impl State { text_vertices, &mut hint_x, hint_y + self.ascent, - "Enter next / submit Tab switch Esc cancel", + "Enter next / submit Tab switch Ctrl+A amend Esc cancel", [0.76, 0.82, 0.92, 1.0], )?; @@ -3304,9 +3335,10 @@ impl ApplicationHandler for App { WindowEvent::KeyboardInput { event, .. } => { if event.state == ElementState::Pressed { let handled = if st.input_mode != InputMode::Normal { + let ctrl = self.modifiers.state().control_key(); match st.input_mode { InputMode::CommitSummary | InputMode::CommitBody => { - st.handle_commit_input(&event.logical_key) + st.handle_commit_input(&event.logical_key, ctrl) } InputMode::RepoPicker => { st.handle_repo_picker_input(&event.logical_key) diff --git a/src/git_model.rs b/src/git_model.rs index d89e5e9..74f6944 100644 --- a/src/git_model.rs +++ b/src/git_model.rs @@ -103,6 +103,7 @@ enum GitCommand<'a> { Commit { message: &'a str, allow_empty: bool, + amend: bool, }, Fetch { remote: Option<&'a str>, @@ -166,11 +167,15 @@ impl<'a> GitCommand<'a> { Self::Commit { message, allow_empty, + amend, } => { let mut desc = format!("git commit --message {}", compact_preview(message, 48)); if allow_empty { desc.push_str(" --allow-empty"); } + if amend { + desc.push_str(" --amend"); + } desc } Self::Fetch { remote } => match remote { @@ -277,11 +282,15 @@ impl<'a> GitCommand<'a> { Self::Commit { message, allow_empty, + amend, } => { command.arg("commit"); if allow_empty { command.arg("--allow-empty"); } + if amend { + command.arg("--amend"); + } command.args(["--message", message]); } Self::Fetch { remote } => { @@ -390,6 +399,15 @@ impl GitModel { } pub fn commit(&mut self, message: &str) -> anyhow::Result<()> { + self.commit_with_options(message, false, false) + } + + pub fn commit_with_options( + &mut self, + message: &str, + allow_empty: bool, + amend: bool, + ) -> anyhow::Result<()> { let message = message.trim(); if message.is_empty() { anyhow::bail!("commit message cannot be empty"); @@ -397,7 +415,8 @@ impl GitModel { self.run_git(GitCommand::Commit { message, - allow_empty: false, + allow_empty, + amend, })?; self.refresh() } @@ -1463,4 +1482,16 @@ not a status line ] ); } + + #[test] + fn commit_command_description_includes_amend_when_requested() { + let desc = GitCommand::Commit { + message: "chore: update", + allow_empty: false, + amend: true, + } + .description(); + assert!(desc.contains("git commit --message")); + assert!(desc.contains("--amend")); + } }