Skip to content

[04/08] replace read-only git query paths with gitoxide#98

Open
mjc wants to merge 26 commits into
asinglebit:mainfrom
mjc:mjc/gitoxide-spike-04-queries-readonly
Open

[04/08] replace read-only git query paths with gitoxide#98
mjc wants to merge 26 commits into
asinglebit:mainfrom
mjc:mjc/gitoxide-spike-04-queries-readonly

Conversation

@mjc

@mjc mjc commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Stacked on mjc/gitoxide-spike-03-graph-walker.

Why this PR exists:

  • Earlier stack layers moved graph walking and commit identity toward gitoxide.
  • This PR applies that same boundary shift to read-only query surfaces used by status panes, file search, remotes, submodules, worktrees, branch visibility, and related UI state.
  • The goal is to reduce read-only query dependence on libgit2 object/status plumbing while keeping mutating Git actions for later branches.
  • This branch does not finish every read-only query surface. Commit graph walking and file-history internals were already moved in earlier stack layers; this PR focuses on the remaining read-only status/metadata/query paths listed below.

What changed:

  • Moves workdir/index status collection toward gix:
    • get_filenames_diff_at_workdir now opens a gix repo and iterates gix status items.
    • staged changes can be computed from gix head-tree/index comparison.
    • submodule paths are filtered through the new submodule query model.
    • final staged/unstaged/conflict counts are still normalized into the existing UncommittedChanges shape.
  • Keeps libgit2 where still needed for existing diff/hunk rendering and submodule status compatibility.
  • Moves tracked-file search path collection from libgit2 index iteration to gix index iteration.
  • Refactors fuzzy file matching to use SmallVec and split the position/scoring logic into smaller helpers.
  • Moves remote listing/default-remote resolution to gix:
    • remote names and fetch URLs come from gix remote APIs.
    • push URLs and default remote config are read from gix config snapshots.
    • effective default remote still follows the existing priority order.
  • Rewrites submodule metadata/status collection around gix:
    • checks for .gitmodules in workdir, committed tree, and index.
    • enumerates submodules through gix.
    • records head/index/workdir IDs as gix::ObjectId.
    • derives open/uninitialized/config/head/index/workdir state.
    • computes index changes, new commits, modified content, and untracked content.
  • Moves worktree metadata listing toward gix:
    • main and linked worktrees are read through gix worktree APIs.
    • worktree heads are stored as gix::ObjectId.
    • dirty checking can be skipped for metadata-only callers.
    • current worktree dirty state can be supplied from already-computed uncommitted changes.
  • Moves branch visibility’s current branch-name collection to gix reference iteration.
  • Updates core model types:
    • reflog alias entry time is now gix::date::Time.
    • submodule OIDs are now gix::ObjectId.
    • worktree heads are now gix::ObjectId.
  • Updates query tests for diffs/status, tracked-file search, remotes, submodules, worktrees, branch visibility, and core model behavior.

Algorithm difference:

  • Status panes no longer rely on git2::statuses as the main source of staged/unstaged file classification.
  • Staged-only status can be computed directly from gix head tree plus index.
  • Worktree status uses gix status summaries and then maps them back into the existing UI-facing buckets:
    • staged added/modified/deleted
    • unstaged added/modified/deleted
    • conflicts
    • clean/staged/unstaged booleans
  • Submodule reporting is now metadata-driven through gix submodule state plus explicit pointer comparisons.
  • Remote default selection preserves the existing policy:
    • guitar.defaultRemote
    • remote.pushDefault
    • current branch upstream remote
    • origin
    • first sorted remote
  • Worktree listing separates metadata reads from dirty checks, so callers that only need worktree identity can avoid full status scans.
  • Branch visibility now reads local and remote branch names through gix refs instead of libgit2 refs.

Performance story:

  • Expected wins are mostly from avoiding repeated libgit2 status/config/ref setup in read-only paths.
  • Worktree metadata callers can skip dirty checks and reuse already-computed current-worktree dirty state.
  • File search avoids libgit2 index iteration and reduces temporary allocation in fuzzy matching.
  • Submodule metadata preflight avoids full submodule enumeration when there is no .gitmodules metadata.

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
04-queries-readonly 3.812s 41.26x 1.47s 0.42s 49%

CPU: 5950x Linux/ZFS

Ref Total vs main User System CPU
04-queries-readonly 1.856s 53.47x 1.58s 0.46s 110%

Memory: 5950x Linux/ZFS

Ref Peak heap Peak RSS
04-queries-readonly 436.12M 977.18M
Top 10 heaptrack allocation sites for `04-queries-readonly`
  1. 190825 calls, 11.40M peak - git__calloc
  2. 101577 calls, 0B peak - <>::next
  3. 100831 calls, 0B peak - gix_dir::walk::readdir::recursive
  4. 89663 calls, 1.27M peak - CRYPTO_malloc
  5. 41425 calls, 1.61M peak - <>::finish_grow
  6. 34119 calls, 0B peak - gix_ref::raw::convert::<>::from
  7. 24684 calls, 0B peak - <>::push_back_tracked_path_component
  8. 17060 calls, 878.18K peak - guitar::core::walker::Walker::new
  9. 13654 calls, 0B peak - std::sys::fs::read_dir
  10. 11856 calls, 154.43M peak - alloc::raw_vec::RawVecInner<>::finish_grow

mjc added 26 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)
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 continues the staged migration of read-only Git query surfaces away from libgit2 and onto gitoxide (gix), updating both production query paths (status/metadata/remotes/submodules/worktrees/branch visibility/file history) and the surrounding model/test infrastructure to use gix-native identifiers and time types.

Changes:

  • Port read-only query implementations (status matrix, tracked-file search, remotes/default remote selection, submodules, worktrees, branch visibility, reflogs, file history) to gix-based APIs while retaining libgit2 where still required for diffs/hunks.
  • Update core model types to use gix::ObjectId and gix::date::Time, and refactor graph-walking plumbing to center around gix::Repository.
  • Add/refresh extensive test coverage and shared test fixtures via git::test_support, plus a new --exit-when-graph-complete CLI mode.

Reviewed changes

Copilot reviewed 75 out of 76 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main.rs Adds --exit-when-graph-complete mode and repo path parsing changes.
src/lib.rs Exposes new git::gix and git::test_support modules.
Cargo.toml Introduces gix and supporting crates (iddqd, smallvec, etc.) for the migration.
src/helpers/time.rs Adds gix time formatting helpers while preserving git2 timestamp APIs.
src/helpers/heatmap.rs Reworks heatmap counting/building to use gix commit lookup and a compact counts buffer.
src/helpers/branch_visibility.rs Moves branch-name enumeration to gix refs and adds UTF-8-only ref parsing helper.
src/git/gix.rs Adds shared gix utilities (error mapping, branch tip iteration, object cache enabling).
src/git/test_support.rs New shared test fixtures/helpers for repositories, commits, worktrees, remotes, submodules, and language isolation.
src/git/queries/diffs.rs Migrates workdir/index status path collection to gix and normalizes staged-only computation.
src/git/queries/files.rs Switches tracked-file enumeration to gix index iteration; refactors fuzzy matcher around SmallVec.
src/git/queries/remotes.rs Moves remote listing/default-remote resolution to gix remotes + config snapshot reads.
src/git/queries/submodules.rs Rewrites submodule metadata/status collection around gix submodule APIs and .gitmodules preflight.
src/git/queries/worktrees.rs Migrates worktree listing/metadata/dirty policy to gix worktree proxies and status scanning.
src/git/queries/reflogs.rs Switches reflog reading to gix reference log iteration and gix-native time/OIDs.
src/git/queries/file_history.rs Reimplements file history status classification using gix tree diffs with caching.
src/git/queries/helpers.rs Adjusts tree walking/diff hunk shaping for gitlink entries and new string handling.
src/git/queries/commits.rs Ports tip/tag/stash/root enumeration and batching plumbing to gix-based traversal.
src/core/oids.rs Replaces OID aliasing map with iddqd-backed intern table and adds prefix lookup support.
src/core/walker.rs Converts graph walker to operate on gix::Repository, gix-derived roots, and streamed commit metadata.
src/core/worktrees.rs Updates worktree head IDs to gix::ObjectId.
src/core/submodules.rs Updates submodule head/index/workdir IDs to gix::ObjectId.
src/core/reflogs.rs Moves reflog entry time to gix::date::Time.
src/core/layers.rs Refactors renderer-layer token storage to avoid allocations and use compact lane flags.
src/core/chunk.rs Makes Chunk Copy to support updated buffer semantics.
src/app/app.rs Adds bootstrap/shutdown/wait helpers; improves graph channel disconnect handling; wires new worktrees event.
src/app/input/git.rs Updates stash/reflog flows and default-remote selection to the new gix-backed queries.
src/app/input/modals.rs Switches SHA prefix resolution to Oids::get_alias_by_prefix.
src/app/input/remotes.rs Adjusts remote URL lookup to use new list_remotes(path) API.
src/app/input/navigation.rs Updates commit lookups and alias resolution to new Oids API shape.
src/app/input/worktrees.rs Updates worktree alias resolution to new Oids::get_existing_alias.
src/app/draw/inspector.rs Uses gix timestamp formatting for reflog display.
src/app/draw/search.rs Renders short OID directly from oid rather than a stored short_oid field.
src/app/draw/graph.rs Adjusts alignment helper lifetimes for non-'static spans.
src/app/draw/settings.rs Switches remotes listing/default remote rendering to new path-based API.
src/app/draw/stashes.rs Updates Oid lookup call sites after Oids API changes.
src/core/worktrees.rs Updates worktree head type to gix OIDs for the UI model.
src/tests/helpers/localisation.rs Adds language guard + temp file path handling changes for isolation.
src/tests/helpers/keymap.rs Adds language guard and removes manual language reset.
src/tests/helpers/branch_visibility.rs Refactors temp paths to shared test_support + adds additional branch parsing/path coverage.
src/tests/helpers/heatmap.rs New tests for gix-backed heatmap counting and prefix matching behavior.
src/tests/git/queries/diffs.rs Updates diff/status tests to validate new gix status matrix behavior.
src/tests/git/queries/files.rs Updates file-search tests and adds staged/deleted enumeration coverage.
src/tests/git/queries/remotes.rs Updates remotes tests for path-based gix APIs + bare repo coverage.
src/tests/git/queries/submodules.rs Expands submodule tests for .gitmodules preflight, index scanning, bare repos, and state flags.
src/tests/git/queries/worktrees.rs Adds worktree metadata vs dirty policy tests + lock/prune semantics coverage.
src/tests/git/queries/reflogs.rs Updates reflog tests to gix repo access and new filtering semantics.
src/tests/git/queries/file_history.rs Updates file history tests to use gix repo + adds copy/typechange/normalization coverage.
src/tests/git/actions/submodules.rs Adjusts submodule action tests to gix OID conversions.
src/tests/git/actions/{reverting,rebasing,merging,cherrypicking,branching}.rs Refactors temp repo setup to shared init_repo_at.
src/tests/core/{walker,buffer,reflogs,oids}.rs Updates/extends core tests for new gix-based walker/OID/buffer semantics.
src/tests/app/state/app.rs Adds tests for wait_until_graph_complete behavior and updates row structs.
src/tests/app/input/{navigation,git,events,worktrees}.rs Updates tests for new OID/time types and language guard usage.
src/tests/app/draw/{graph,search,status,settings,worktrees}.rs Updates rendering tests for model shape changes and language isolation.
benches/{commit_batching,fixtures,render_graph_projection}.rs Updates benches to the new gix-backed walker/batcher plumbing and row defaults.

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

Comment thread src/main.rs
Comment on lines +10 to +12
fn repo_path_from_args(args: &[String]) -> Option<String> {
args.iter().skip(1).find(|arg| !arg.starts_with('-')).cloned()
}
Comment thread src/app/draw/search.rs
Comment on lines 90 to 93
lines.push(Line::from(vec![
Span::styled(format!("{} ", status_marker(row.status, &self.symbols)), Style::default().fg(marker_color)),
Span::styled(format!("{} ", row.short_oid), Style::default().fg(self.theme.COLOR_GREY_600)),
Span::styled(format!("{:.8} ", row.oid), Style::default().fg(self.theme.COLOR_GREY_600)),
Span::styled(truncate_with_ellipsis(&row.summary, summary_width), Style::default().fg(self.theme.COLOR_TEXT)),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

bogus comment I am nearly certain

Comment on lines +102 to +107
let ids = (tree_id, parent_tree_id);
COMMIT_TREE_CACHE.with(|cache| {
cache.borrow_mut().insert(oid, ids);
});
Ok(ids)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

worthwhile target for a future pr but I think it was added in an earlier pr in the stack.

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