Skip to content

[06/08] wire gitoxide graph/query/action changes through App state and input#100

Open
mjc wants to merge 54 commits into
asinglebit:mainfrom
mjc:mjc/gitoxide-spike-06-app-integration
Open

[06/08] wire gitoxide graph/query/action changes through App state and input#100
mjc wants to merge 54 commits into
asinglebit:mainfrom
mjc:mjc/gitoxide-spike-06-app-integration

Conversation

@mjc

@mjc mjc commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Stacked on mjc/gitoxide-spike-05-actions-network.

Why this PR exists:

  • Earlier stack layers moved graph walking, read-only queries, and mutating actions toward the new gitoxide boundary.
  • This PR wires those lower-layer changes through App state, drawing, input, startup, reload, and graph-service event handling.
  • The main app-level change is that repository state no longer has to be eagerly held as an opened git2::Repository.
  • Instead, App stores a lazy RepoHandle that keeps the repo path and opens the remaining git2 handle only when older UI/action paths still need it.
  • This is the integration layer where the lower-level graph/query/action migration becomes visible to UI flow and startup/reload behavior.

What changed:

  • Replaces App.repo: Option<Rc<Repository>> with App.repo: Option<RepoHandle>.
  • Adds RepoHandle, which stores:
    • repository path
    • lazy git2::Repository initialization through OnceCell
    • helpers for repo path, git dir, and legacy git2 access
  • Adds App::git2_repo() as the explicit compatibility path for UI surfaces that still need git2.
  • Adds background-task lifecycle helpers:
    • shutdown_background_tasks
    • wait_until_graph_complete
  • Adds load_startup_config so startup config loading is centralized.
  • Changes the main event loop to call sync_lazy() rather than syncing through an eagerly cloned repo.
  • Adds graph_event_tx so graph-service events can be wired through the app layer.
  • Adds cached remote state on App.
  • Adds symbol_theme_loaded so tests/CLI paths can pre-load symbols without reloading them from config.
  • Adds separate uncommitted-status state:
    • is_uncommitted_loaded
    • is_uncommitted_detail_loaded
    • is_uncommitted_detail_loading
  • Keeps the initial uncommitted summary path staged-only, then loads full unstaged details when the uncommitted row is selected.
  • Adds graph projection caching keyed by graph version, visible range, selected row, label toggles, uncommitted-row rendering, and status counts.
  • Adds graph-service events for:
    • uncommitted summary status
    • uncommitted detail status
  • Wires path-based query helpers through app state:
    • git user info
    • staged status
    • submodules
    • worktrees
    • remotes
    • branch visibility
  • Updates worktree/submodule/remote/status code paths to use cached or path-based data where possible.
  • Updates branch/tag deletion flows to work with projected graph-pane rows and the lazy repo handle.
  • Updates remote modal prefill to use cached remotes.
  • Updates default-remote selection to prefer cached remotes and fall back to path-based lookup.
  • Updates status viewer/status-clickability behavior so unstaged detail rows are only clickable once uncommitted details are loaded.
  • Adds --exit-when-graph-complete for non-interactive graph-load completion measurement.
  • Updates tests across app state, input, worktrees, submodules, graph service, renderers, and submodule actions.

Algorithm difference:

  • App startup no longer has to open and retain the legacy git2::Repository as the central repository handle.
  • Reload/startup paths can operate from a repo path and only open the compatibility repo handle when needed.
  • Graph progress and graph completion are now observable through app-level wait/shutdown helpers.
  • Uncommitted status is split into a staged-only summary path and a detailed path for unstaged rows.
  • Worktree metadata can be refreshed without forcing full dirty checks everywhere.
  • Remote data is cached on App and reused by UI modals/default-remote decisions.
  • Graph projection can be reused when the version/range/selection/status key has not changed.
  • UI/input behavior is intended to remain the same while reaching lower layers through the new graph/query/action contracts.

Performance story:

  • startup, reload, first graph progress, and repeated redraw costs may improve.
  • wins come from:
    • deferring legacy git2::Repository opens
    • using path-based migrated queries
    • caching remotes
    • splitting uncommitted summary/detail work
    • caching graph projection output
    • avoiding unnecessary worktree dirty checks in metadata-only paths
  • --exit-when-graph-complete gives a concrete way to measure graph-load completion outside the interactive TUI.

Benchmark Results for this PR

Command shape: hyperfine --warmup 5 './target/release/guitar /home/mjc/src/linux --exit-when-graph-complete'.

CPU: M1 MacBook Pro 16GB

Ref Total vs main User System CPU
06-app-integration 1.826s 86.13x 1.51s 0.10s 88%
06-app-integration 1.879s 83.70x 1.44s 0.11s 82%

CPU: 5950x Linux/ZFS

Ref Total vs main User System CPU
06-app-integration 1.639s 60.55x 1.40s 0.22s 98%

Memory: 5950x Linux/ZFS

Ref Peak heap Peak RSS
06-app-integration 419.89M 853.30M
Top 10 heaptrack allocation sites for `06-app-integration`
  1. 28594 calls, 1.61M peak - <>::finish_grow
  2. 17060 calls, 878.18K peak - guitar::core::walker::Walker::new
  3. 17060 calls, 0B peak - gix_ref::raw::convert::<>::from
  4. 11448 calls, 0B peak - <>::push_back_tracked_path_component
  5. 10179 calls, 154.43M peak - alloc::raw_vec::RawVecInner<>::finish_grow
  6. 9776 calls, 7.47K peak - gix_config::parse::event::<>::to_owned
  7. 2816 calls, 519B peak - gix_config::file::util::<>::push_section_internal
  8. 1308 calls, 0B peak - gix_index::extension::tree::decode::one_recursive
  9. 902 calls, 99B peak - facet_core::impls::alloc::string::<>::SHAPE::{{constant}}::VTABLE::parse
  10. 778 calls, 0B peak - facet_reflect::partial::partial_api::lists::<>::begin_list_item

mjc added 30 commits July 1, 2026 12:35
(cherry picked from commit 122fdf1)
Wire a no-TUI entry point that loads the repo, skips workdir status to avoid
case-colliding paths on case-insensitive filesystems, waits for the graph
walker to finish, prints the commit count, and shuts down background tasks.
(cherry picked from commit 4b30648)
(cherry picked from commit 427dce7)
(cherry picked from commit 9854674)
(cherry picked from commit 6ce842f)
(cherry picked from commit dac26d1)
(cherry picked from commit 77e669a)
(cherry picked from commit 1484548)
mjc added 24 commits July 1, 2026 13:26
(cherry picked from commit 7380987)
(cherry picked from commit c7f0055)
(cherry picked from commit 6bb0b5c)
(cherry picked from commit de35af6)
(cherry picked from commit 9d57a25)
(cherry picked from commit d2f44b0)
(cherry picked from commit e5bd31d)
(cherry picked from commit f956dcc)
(cherry picked from commit 4461f87)
(cherry picked from commit 4ccd4cc)
(cherry picked from commit 28598c0)
(cherry picked from commit 3ddc288)
(cherry picked from commit dc4e23c)
Skip commit diff refresh for the uncommitted pseudo-row when the first
GraphWindow is applied, and add a regression test that reproduces the
spike-06 TUI crash.
Copilot AI review requested due to automatic review settings July 1, 2026 21:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates the ongoing gitoxide (gix) graph/query/action migration into the app layer, shifting App toward path-based/lazy repository access while wiring new graph-service events, caches, and lifecycle helpers through startup/reload/input/draw flows.

Changes:

  • Introduces a lazy repo-handle approach (path-first; legacy git2 opened only when needed) and threads it through app input/draw/state.
  • Ports multiple query/action paths to gix (worktrees, remotes, reflogs, tracked-file search, tag/branch/checkout/fetch/submodule flows), plus adds supporting helpers and tests.
  • Adds performance/UX-oriented caching and control hooks (graph projection caching, uncommitted summary/detail split, --exit-when-graph-complete).

Reviewed changes

Copilot reviewed 100 out of 101 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/tests/helpers/localisation.rs Uses shared language test guard and safer temp language file paths.
src/tests/helpers/keymap.rs Stabilizes localisation behavior during keymap serialization tests.
src/tests/helpers/heatmap.rs Adds heatmap helper tests for streamed/scanned commit counting and prefix aliasing.
src/tests/helpers/branch_visibility.rs Migrates temp config handling and expands branch-visibility edge-case coverage.
src/tests/git/queries/worktrees.rs Updates worktree query tests for new metadata/dirty policies and path-based variants.
src/tests/git/queries/remotes.rs Updates remote query tests to use path-based remote resolution (incl. bare repos).
src/tests/git/queries/reflogs.rs Updates reflog query tests for gix-backed reflog reading and edge cases.
src/tests/git/queries/files.rs Updates tracked-file search tests and adds staged/deleted enumeration coverage.
src/tests/git/queries/file_history.rs Expands file-history tests and switches to gix-repo based status lookup.
src/tests/git/os/path.rs Uses shared TestDir helper for repo-root path tests.
src/tests/git/auth.rs Adds tests for gix credentials integration and SSH key preference ordering.
src/tests/git/actions/worktrees.rs Uses shared TestDir helper; keeps worktree action tests aligned with new helpers.
src/tests/git/actions/tagging.rs Adds tests for new tag/untag behavior.
src/tests/git/actions/reverting.rs Refactors revert tests to shared fixtures/helpers for divergence and file assertions.
src/tests/git/actions/resetting.rs Adds tests for reset-to-commit and per-file reset behavior in linked worktrees.
src/tests/git/actions/remotes.rs Refactors remote action tests to shared temp repo helper.
src/tests/git/actions/rebasing.rs Refactors rebase tests to shared divergence/workdir helpers.
src/tests/git/actions/pushing.rs Adds push/delete-remote-branch/push-tags integration tests.
src/tests/git/actions/fetching.rs Adds fetch integration tests incl. pruning stale refs and linked worktree behavior.
src/tests/git/actions/cherrypicking.rs Refactors cherrypick tests to shared divergence/workdir helpers.
src/tests/git/actions/checkout.rs Adds checkout tests for detach/branch checkout and remote-tracking bootstrap.
src/tests/git/actions/branching.rs Expands branch action tests for upstream-config preservation and config cleanup.
src/tests/core/reflogs.rs Updates core reflog tests to use gix::date::Time.
src/tests/core/oids.rs Adds tests for new OID alias/prefix lookup behavior.
src/tests/app/input/worktrees.rs Updates app-input worktree tests for gix::ObjectId heads.
src/tests/app/input/submodules.rs Updates submodule input tests for RepoHandle and shared git test support helpers.
src/tests/app/draw/worktrees.rs Updates draw tests for gix::ObjectId worktree heads.
src/tests/app/draw/status.rs Updates graph-row test builder defaults and uncommitted fields.
src/tests/app/draw/settings.rs Ensures localisation isolation for shortcut rendering tests.
src/tests/app/draw/search.rs Updates history-row OID construction to avoid invalid fixed prefixes.
src/tests/app/draw/graph.rs Updates graph-history construction and removes short-oid plumbing in tests.
src/main.rs Adds --exit-when-graph-complete and centralizes symbol theme loading.
src/lib.rs Exposes new git::gix, git::test_support (test-only), and git::actions::gix_support.
src/helpers/time.rs Adds gix timestamp formatting helpers alongside git2 variants.
src/helpers/heatmap.rs Reworks heatmap counting/building around gix, adds HeatmapCounts, and test module hook.
src/helpers/branch_visibility.rs Switches branch enumeration to gix, adds UTF-8-only ref parsing helper.
src/git/test_support.rs Adds shared git test scaffolding (repos, commits, worktrees, remotes, language guard).
src/git/queries/worktrees.rs Reimplements worktree listing/metadata via gix worktree proxies and path-based open.
src/git/queries/remotes.rs Reimplements remote listing/default-remote resolution via path-based gix repo open.
src/git/queries/reflogs.rs Reimplements HEAD reflog reading via gix logs and filters non-commit entries.
src/git/queries/helpers.rs Extends tree-walk to treat commit entries as “added” and simplifies hunk/line storage.
src/git/queries/files.rs Switches tracked-file enumeration to gix index and refactors ranking/fuzzy match internals.
src/git/queries/commits.rs Switches tip/tag/stash enumeration and batching plumbing to gix and new batcher API.
src/git/gix.rs Adds shared gix helpers (cache sizing, branch tip iteration, error mapping).
src/git/auth.rs Adds gix credentials adapter that prefers session secrets and falls back to helpers.
src/git/actions/tagging.rs Implements tag/untag via gix reference transactions with existence checks.
src/git/actions/submodules.rs Reimplements sync/stage/unstage/update flows via gix config/index/fetch/checkout.
src/git/actions/staging.rs Updates stage-all to integrate submodule pointer staging via submodule query/action helpers.
src/git/actions/resetting.rs Adds test module hook for reset behavior.
src/git/actions/pushing.rs Adds test module hook for push behavior.
src/git/actions/gix_support.rs Adds shared gix helpers for refs/config/index/checkout used by multiple actions.
src/git/actions/fetching.rs Reimplements fetch via gix remote fetch + git2-based pruning of stale tracking refs; adds tests.
src/git/actions/checkout.rs Reimplements checkout (detach/local/remote bootstrap) via gix refs/config + worktree checkout.
src/git/actions/branching.rs Reimplements create/rename/delete via gix ref transactions and config edits; adds tests.
src/core/worktrees.rs Switches worktree head type to gix::ObjectId.
src/core/submodules.rs Switches submodule OID fields to gix::ObjectId.
src/core/reflogs.rs Switches reflog time type to gix::date::Time.
src/core/oids.rs Reworks OID interning/aliasing around gix::ObjectId + prefix lookup support.
src/core/layers.rs Optimizes layer token storage (borrowed symbols) and flattened lane representation; adds tests.
src/core/chunk.rs Makes Chunk Copy to reduce cloning.
src/app/state/defaults.rs Adds symbol theme preloading option, remotes cache, graph event tx, and uncommitted detail flags.
src/app/input/worktrees.rs Updates alias mapping to new Oids API.
src/app/input/remotes.rs Prefills remote inputs from cached remotes and updates hidden remote prefix rewriting.
src/app/input/navigation.rs Adds open_status_viewer helper and uncommitted detail preloading on selection.
src/app/input/modals.rs Uses OID prefix lookup for SHA navigation and updates diff loading to use resolved OID.
src/app/input/handler.rs Refactors key handling to prioritize modal/context/settings escape and centralizes command dispatch.
src/app/input/events.rs Simplifies mouse scroll matching, refactors left-pane hit-testing, updates status clickability gating.
src/app/input/context_menu.rs Updates status clickability gating for uncommitted detail loading.
src/app/draw/stashes.rs Updates commit lookup call sites to new OID API.
src/app/draw/settings.rs Switches remotes listing/default-remote lookup to path-based remotes query.
src/app/draw/search.rs Renders abbreviated OID directly from full OID rather than stored short OID.
src/app/draw/inspector.rs Switches reflog timestamp formatting to gix time formatting helper.
src/app/draw/graph.rs Generalizes projection alignment over non-'static lifetimes.
Cargo.toml Adds gix/worktree crates and supporting deps (iddqd, smallvec, rustc-hash).
benches/render_graph_projection.rs Refactors uncommitted-row fixture and updates row fields.
benches/fixtures.rs Updates benchmark graph row fixtures with new fields/default collections.
benches/commit_batching.rs Updates batching benchmarks to gix-repo + new batcher API and adds error propagation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +75 to 79
fn remote_push_url(repo: &gix::Repository, remote_name: &str) -> Option<String> {
let key = format!("remote.{remote_name}.pushUrl");
let value = repo.config_snapshot().string(&key)?;
Some(value.to_str().ok()?.to_string())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants