Skip to content

Latest commit

 

History

History
283 lines (235 loc) · 29.9 KB

README.md

File metadata and controls

283 lines (235 loc) · 29.9 KB

GitDown

A native, GPU-rendered Git workbench targeting Git 2.51+. It uses a location/history/inspector layout and adds named multi-repository workspaces, worktree navigation, explicit AI tooling evidence and a recorded interactive command workflow. Windows and the existing WSL setup are the qualified targets; Linux builds and runs but has no standalone desktop qualification (scope).

Run

Install stable Rust (workspace minimum 1.92; the dependency-free core supports 1.85), Git 2.51 or newer and native build tools. Windows uses the MSVC C++ toolchain; Linux needs a linker, Wayland/X11 development libraries, Fontconfig/FreeType and OpenGL/EGL (see the CI package list).

cargo run -p gitdown-ui --locked -- /path/to/repository

On Windows, .\scripts\run.ps1 -Repository C:\work\your-repository (optional -Release) does the same. Git comes from GITDOWN_GIT if set, else the portable Git under target/tools/git-2.51 when present (not checked in), else PATH. Git older than 2.51 allows browsing but disables command execution, and the UI states the detected version. Configured hooks and subsection aliases are probed independently in a disposable repository for the selected executable; direct commands keep the installed Git's semantics.

$env:GITDOWN_GIT = 'C:\path\to\Git\cmd\git.exe'
cargo run -p gitdown-ui --locked

The command line, Open repository, the repository switcher and workspace import share one local opening service. Open a checkout, subdirectory, .git directory or gitfile, bare repository or plain parent folder. A parent folder creates an ephemeral workspace and progressively discovers its immediate child repositories; --discovery-depth 1..16 (default 1) goes deeper, stops at repository boundaries and does not follow symlinks. Linked checkouts share a repository group but keep separate checkout identities.

Opening shows the first 100 commits from HEAD and restores the selected commit or working changes before loading the remaining repository details. Watch registration and its recursive file-ID cache scan run independently of repository reads. Other branches, worktree status and command guards fill in afterward; write actions become available when those guards are ready.

The sidebar's Save and Open export and import versioned JSON workspace documents; relative roots resolve against the document's directory and version-1 files stay readable. Automatic local sessions keep checkout-specific drafts, selections, queries and viewport anchors, and explicit exports omit that editor state. The session lives in the platform config directory; --session /path/session.json selects an isolated or portable one.

External code review

The Review menu's Connect code review… binds a checkout remote to a Gerrit service URL (including its deployment path), project and optional explicit target branch. With no saved binding the form starts from a remote's fetch URL (the upstream's remote, then origin): the origin, or for ssh:// the host over HTTPS, and the path as the project. A deployment path is never guessed, so move it from the project to the service. Choose REST for Git HTTP helper credentials or SSH for the clone's default SSH credentials. WSL checkouts connect and resolve credentials inside the Linux worker. Connect and Retry are noninteractive; authenticate with Git first when a credential manager requires interaction. GitDown stores no secret.

History shows a status cluster on each reviewed commit's second line: lifecycle, the server's Code-Review and Verified verdicts, and unresolved comments. Selecting a commit adds its review number, patch set, Change-Id (with Copy) and an Open in browser button to the commit details, and a Code review strip before the diff with submission requirements, votes, check results and discussion grouped by patch set and file. Threads written on the selected patch set appear in the diff at their lines, file headers count them, and T / Shift+T (or the strip's buttons) jump to the next or previous unresolved thread. Review actions offers refresh, browser access, reconnect, association choice and disconnect. Ambiguous matches require an explicit choice; older and unuploaded revisions do not inherit current approval. SSH lacks reply IDs and resolution metadata, so its discussion is explicitly partial. Reads do not change local Reviewed marks or Git command availability. Local sessions keep only connection and association choices; portable exports omit them.

The disposable Gerrit 3.13.1 fixture qualifies the development path. Production credentials, TLS/proxies, interactive credential recovery and native Windows SSH authentication remain release qualification gaps.

Release package

python scripts/package.py builds and packages a release for the host it runs on. It needs Python 3.11+ and the run requirements above, and writes to dist/:

Host Archive Contents
Windows gitdown-<version>-windows-x64.zip gitdown-ui.exe and a Linux gitdown-worker built in WSL
Linux, or inside WSL gitdown-<version>-linux-x64.tar.gz gitdown-ui and gitdown-worker

Each archive has a .sha256 file and the license notices. WSL is required on Windows unless --no-wsl skips the worker. Packaging refuses a tree with uncommitted changes or stale notices, and reads the archive back before it writes the checksum; scripts/release_smoke.ps1 then starts the unpacked app in an empty folder. Set GITDOWN_SIGN_THUMBPRINT (and optionally GITDOWN_TIMESTAMP_URL) to sign and verify gitdown-ui.exe with signtool; the smoke script reports the signature status. The app finds a worker beside its executable (default WSL mount only); start it with --session session.json to keep its session in the folder. Packages need Git 2.51+ on the target (PATH or GITDOWN_GIT), the Visual C++ Redistributable on Windows, and a glibc no older than the build host's on Linux. Release builds use the Windows GUI subsystem, so --help and argument errors print nothing from a terminal.

Features

  • System/Dark/Light themes, a flat dense desktop component set, persisted resizable panes, graph paths, branch/tag chips and contextual command previews.
  • Reads through gitoxide (SHA-1 and SHA-256, main and linked worktrees, histogram diffs); reftable repositories use documented Git pipe queries and storage is never converted. Bare repositories show history, refs and remotes without staging.
  • Repository tabs with checkout-owned drafts and anchors; commit-wide foldable review; aligned side-by-side and inline diffs with syntax and intraline highlighting; file, hunk and selected-line staging; one-click file, hunk and line discard with Undo; in-place hunk editing; a review column with a fixed commit box, line-wrapped diffs, click-to-select lines and a pinned file header; staged, unstaged and untracked partitions; commit composition; reviewed-state counters and walk.
  • Pull (fetch and rebase with autostash in one click; a diverged branch confirms the replay count and the first predicted conflict first), push, stash, merge (ordinary, fast-forward only or always a merge commit), annotated and lightweight tags and branch/tag/remote/submodule administration from menus and the palette, each stating its scope: fetched divergence choices for push, guarded force variants, leased server-side branch deletion, remote rename, removal and URL copy, and submodule open, update and sync.
  • Guarded history edits from the commit tree: multi-select drop, squash, fixup, reorder (menu, Alt+Up/Alt+Down or drag), reword, edit stops that split or amend, and ordered multi-commit cherry-pick and revert. Each is one Git interactive rebase or pick sequence; reorder, squash, fixup, drop and multi-pick state the first predicted conflict before running, and a rewrite shows a notice with the reflog restore path.
  • Merge, rebase, cherry-pick and revert stops show an operation banner and a three-way resolver; Git's merge-file supplies the regions and the Output editor is authoritative.
  • Renames read as renames in commit review and compare (old → new, contents unchanged or N% similar). Changed PNG, JPEG, GIF, BMP and WebP images (up to 2 MiB a side) show old and new side by side with dimensions and size, in commits and the working copy; Git LFS pointers and unreadable images say so.
  • Read-only file history, blame, line/hunk history and exact-blob version comparison, plus display-only whitespace modes (the canonical patch and staging scope stay exact).
  • Arbitrary-pair endpoint or merge-base diffs in the continuous review document, with captured IDs, moved-ref warnings and independent folds and anchors.
  • Effective Git commit templates for fresh drafts, with explicit insertion from Commit options or the palette that preserves authored text and trailers.
  • Aliases, hooks, signing, credential helpers and SSH run through system Git in a real ConPTY or Unix PTY. A command recorder keeps exact cwd and argv, live output, exit code, terminal input, cancellation, copyable commands and guarded re-runs. Task actions leave it collapsed; running and unsuccessful tasks stay visible in the status bar, including in another or closed tab, and copied selected-line commands carry their own encoded patch.
  • Named multi-repository workspaces and linked worktrees with branch, changed and conflicted counts; new worktrees from a commit, branch, remote-tracking ref or tag; a terminal or editor opened in a worktree's own target (Windows; GITDOWN_EDITOR names a VS Code-compatible command, default code).
  • Local Codex, Claude Code, Cursor, Copilot, Aider, OpenCode and instruction-file markers, observed file activity, terminals GitDown opened and recognized Co-authored-by trailers appear as separate facts; configuration never implies a running agent. Review batches (observed paths) filter navigation, and keyboard staging can turn one into independently reviewed commits.
  • Debounced, rename-aware native watching of every loaded checkout with a 15-second recovery fallback (reads).

Keyboard workflow

Shortcut Action
Ctrl+P, Ctrl+Shift+P, F1 Action palette: ranked actions with key hints, command previews and disabled reasons
Ctrl+Shift+O Recent repositories
Ctrl+F Focus history search
Git command (palette or Tools) Direct Git command; a leading : or git is optional
Up/Down, Enter, Esc Select, execute or dismiss palette results; Backspace on an empty argument step removes its chip
Ctrl+Z outside editors Edit > Undo, named for what it takes back (Undo: discard in src/core.rs): the discard or hunk edit just made; otherwise the eligible guarded local-branch reflog restorations (Undo: rewrite of main). Disabled with a reason when nothing is recoverable; Edit > Redo repeats a recorded restoration. Editors keep their own undo
Alt+Left / Alt+Right Go back / forward through the commits you selected (the Go menu; bounded, not saved)
Ctrl+0 / Ctrl+9 Go to HEAD / Go to Working Copy
Ctrl+Down / Ctrl+Shift+Down / Ctrl+Up Go to the parent / second parent (merges) / nearest loaded child of the selected commit; from the working copy, Parent is HEAD
Ctrl+S / Ctrl+Shift+S outside editors Stash tracked changes / pop the latest stash
Stash row Stashes are rows of the commit graph, drawn off the commit they were made on. Choosing one (here or in the sidebar) scrolls it into view and opens it read-only in the review pane with Apply, Pop, Drop and the restore-staged choice in its header; its context menu offers the same
Stash menu Stash with a message, and Apply or Pop restoring staged changes (--index); plain Apply and Pop bring staged changes back unstaged. Both confirm with a conflict forecast unless it is already known clean
Ctrl+O Open repository folder
Ctrl+Tab / Ctrl+Shift+Tab Next/previous repository tab
Ctrl+W or Ctrl+F4 / Ctrl+Shift+T Close/reopen repository tab
Ctrl+PageDown / Ctrl+PageUp Next/previous repository tab
Alt+PageDown / Alt+PageUp Next/previous commit in the current filtered history
PageDown / PageUp in review Scroll the diff by one page
Ctrl+Shift+L / Ctrl+Shift+U outside editors Pull/push using the configured policies
Ctrl+Shift+R / Ctrl+Shift+G outside editors Publish a review / upload a prepared change for review, with the usual forms and guards
Ctrl+Enter in the commit message Commit staged changes
Ctrl+E on a focused commit, local branch or working file header Edit the commit (amend/split), rename the branch, or open the file with its associated application
`Ctrl+`` Toggle command recorder
j / k Next/previous changed file, respecting the review batch filter
s / u Stage/unstage selected lines, or the complete file when no lines are selected
n / p Next/previous review hunk
r / Shift+R / Shift+N Toggle hunk reviewed / mark file reviewed / next unreviewed
Ctrl+Enter On a focused commit row or local-branch row or chip: check it out (detached for a commit), with the menu entry's guards and confirmation
F2 On a focused local branch: rename it; on a focused commit: reword it; on the workspace header: rename the workspace
Alt+H / Alt+B / Alt+Shift+H History of the selected file / blame of it / history of the selected lines or hunk (fills the search with lines:path:3-8 from:<commit>; path:src/main.rs filters by path the same way)
Alt+L Protect the current reviewed unstaged hunk (memory only; a later write is compared, never blocked)
Alt+Up / Alt+Down Move the selected commit newer / older (one guarded rebase, outside editors)
Ctrl+C / Ctrl+Shift+C On a focused commit row: copy its summary / full ID; on a ref: its full name / the full ID it points at. In the review document: Ctrl+C copies the dragged characters, else the selected lines' text, Ctrl+Shift+C the selected lines, else the current hunk, as patch text
Ctrl+Alt+W Open the new-worktree form at HEAD (outside editors)
Shift+F10 Open the context menu of the focused row
F5 Refresh repository

Single-letter shortcuts do not fire while typing in fields. s does not unstage an already staged file and u does not stage an unstaged one. Click changed rows or a hunk header to select patch content, or drag across code text (Shift+click extends, double-click takes a word, triple-click the line) to select characters, in a commit as well as the working copy: Stage, Unstage and Discard act on the changed lines the selection touches and Ctrl+C copies exactly the selected characters. Esc deselects. Stage batch stages only observed paths, and Commit staged always commits the complete index and shows its staged-file count.

The help button beside history search lists its grammar as a table with one example per operator, then its rules and bounds. Combine author:, message:, change: (commit ID prefix or attribution text), after:, before:, path: and lines: with spaces; all terms must match. Quote phrases with single or double quotes. Dates use author time: after: includes UTC midnight and before: excludes it. Paths are literal, repository-relative and use /; path: compares to the first parent. Choose one scope: in:all (default, HEAD and cached refs), in:HEAD, an exact full ref such as in:refs/heads/main, from:<full commit ID>, or range:refs/heads/main..refs/heads/topic. A range includes commits reachable from its second endpoint excluding those reachable from its first. Endpoints must be full refs or full commit IDs; refs use the captured snapshot. Line queries such as lines:src/main.rs:3-8 trace from HEAD, from:, or the range tip. Results search repository history, return at most 200 matches, and explicitly flag truncation and failures; line history can also be incomplete. Queries are limited to 4096 bytes and arbitrary revspecs such as A..B are unsupported. Query errors remain beside the editable field, including when the history pane is hidden. The query editor suggests operators and published literal values. Use arrow keys to select, Tab to complete and Escape to dismiss; Ctrl+Space requests suggestions. Completion preserves editor undo and replaces only the active token.

The review header's View menu exposes next/previous change, file and unresolved inline thread, plus next unreviewed change, with existing key hints. Commit Message and Details disclosures leave merge-parent and patch-set choices visible. An associated review's Patch sets… menu chooses an uploaded base and compares it with another uploaded patch set in the continuous diff. Both commit identities stay captured. Fetch without checkout explicitly acquires a patch set through the configured Git remote; reopen the comparison afterward. A discussion entry's Code… menu opens its exact revision and commented lines in the source panel. Unknown revision or parent coordinates stay unavailable. Recent-discard recovery names the exact file and restores only its saved bytes; the file must still match the post-discard state. Editor Ctrl+Z keeps its own undo.

Closing waits for accepted edits and the final local-session save. A failed save keeps the session in memory and offers retry or explicit discard. An unreadable or newer session remains protected from automatic saves. An uncached context menu prepares asynchronously and opens where it was asked once it is ready.

Resolver and .gitignore writes refuse multiply linked files; unlink them first. Replacement data is prepared before changing the original. Existing files keep their ownership, modes and ACLs through an in-place write with a synced recovery copy; Windows sharing behavior is preserved. This recovery strategy is not crash-atomic. A failed restoration reports the retained original and replacement recovery paths.

Development

Beyond the run requirements, contributors need:

Tool Install Used for
rustfmt, Clippy, rust-analyzer Installed automatically from rust-toolchain.toml; manually with rustup component add rustfmt clippy rust-analyzer Formatting, lint gate, Rust code intelligence
slint-lsp 1.18.1 cargo install slint-lsp --version 1.18.1 --locked, or the prebuilt binary from the Slint 1.18.1 release Diagnostics, hover and completion for crates/gitdown-ui/ui/*.slint
Rust 1.92.0 and 1.85.0 rustup toolchain install 1.92.0 1.85.0 --profile minimal --component clippy Minimum-version checks that CI runs
Python 3 Any current release; the scripts use only the standard library scripts/create_*_fixture.py, the vendor verifier and the VS Code core-test resolver
cargo-nextest (optional) cargo install cargo-nextest --locked Faster test runs; scripts/test.ps1 uses it when installed

Keep slint-lsp on the version of the pinned slint crate. rust-analyzer and slint-lsp install to ~/.cargo/bin (%USERPROFILE%\.cargo\bin on Windows), which must be on PATH; restart editors and agent sessions started before the install. In VS Code, install the recommended extensions (including Slint.slint) and open GitDown.code-workspace for CodeLLDB, Windows MSVC and Linux GDB launch configurations, Test Explorer, Clippy-on-save and build tasks. slint-viewer is not needed: gitdown-ui captures real renders itself. AGENTS.md holds the agent workflow, skills and plugin setup.

Task Command
Build cargo build --locked (--release for optimized)
Test cargo nextest run --workspace --locked then cargo test --doc --workspace --locked; plain cargo test --locked also works (Windows: scripts/test.ps1)
Test, core only cargo test -p gitdown-core --lib --locked (pure domain tests, no UI or Git executable)
Test, headless backend cargo test -p gitdown-state -p gitdown-git -p gitdown-cli --locked
Test, WSL worker cargo test -p gitdown-wire -p gitdown-worker --locked (native on Windows and Linux; run inside WSL for the Linux worker)
Lint cargo lint (clippy --workspace --all-targets --locked -- -D warnings)
Format cargo format (Rust); python scripts/autoformat.py <file>... (Rust or Slint)
Format check, docs cargo format-check, cargo doc --workspace --no-deps --locked
Clean cargo clean --profile dev or --release; plain cargo clean also deletes target/tools (portable Git) and the UI fixture

Cargo aliases live in .cargo/config.toml, and without -p Cargo commands cover the whole workspace. Edited Rust and Slint files are formatted automatically by scripts/autoformat.py, wired as a Claude Code hook (.claude/settings.json), a Codex hook (.codex/hooks.json; approve it once in Codex) and VS Code format-on-save (.vscode/settings.json). The script skips Slint files that fail to parse; Python formatting is left to user-level Ruff hooks.

For fast Windows iteration, scope the test launcher to the changed behavior:

scripts/test.ps1 -Package gitdown-ui -Lib -Filter operation_wording
scripts/test.ps1 -Package gitdown-ui -Test interaction -Filter toolbar_branch -List
scripts/test.ps1 -Package gitdown-ui -Test interaction -Filter toolbar_branch
scripts/test.ps1 -Package gitdown-state -Test runtime_events -Filter workspace_document
scripts/test.ps1 -Finalize

Focused runs skip workspace doc tests. -Lib selects library unit tests and -Test selects an integration binary; -Filter matches a test-name substring. -List discovers matching tests without executing them. The interaction binary has independently selectable scenarios, each with an isolated headless backend; use nextest for these UI tests. See the test-granularity policy for choosing checks and preserving those boundaries when adding tests. -Finalize runs format checking, workspace Clippy, workspace tests and doc tests sequentially, stops on failure and reports command timings. With no arguments the launcher retains its workspace test/doc-test behavior; -CoreOnly remains available. Do not run Cargo builds alongside active tests in the same target directory. After a UI build, invoke the built executable directly for subsequent captures to avoid repeated Cargo launches. Test launcher changes with python scripts/test_test_launcher.py, which uses a fake Cargo executable.

Automatic tests use a simulated Slint platform and need no display server, and all test repositories are temporary. PTY tests use isolated Git configuration while production commands keep the user's. On Windows scripts/test.ps1 selects the portable baseline Git like the run script; tests of newer configured hooks and subsection aliases return early with a diagnostic when their feature probe is false. CI runs Git 2.51 and 2.54 independently on Windows and Linux. The ignored wsl_reads test reads a real WSL repository through wsl.exe (GITDOWN_WSL_WORKER is the worker's Linux path, GITDOWN_WSL_REPO a \\wsl.localhost\<distro>\... repository; the test prints what it read):

cargo test -p gitdown-state --locked --test wsl_reads -- --ignored --nocapture

To reproduce a native render without touching the normal session:

python scripts/create_ui_fixture.py
cargo run -p gitdown-ui -- target/gitdown-ui-fixture --session target/ui-validation-config/session.json --capture target/gitdown-workbench.png --exit-after-capture

The fixture helper makes real commits and worktrees under target/ and never initializes or commits the source directory; --capture records the application's own GPU output. Add --dark/--light, --narrow or --size WxH, and the validation flags listed by --help (--sheet, --overlay, --dock, --select-commit, --open-stash N, --drag-range, --click-text 2|3, --resolve PATH, --compare REF, --review-demo) to reach other states. python scripts/create_m5_conflict_fixture.py target/conflicts --operation merge|rebase|cherry-pick creates a disposable repository stopped in an operation with UU, AA, DU, UD, binary, symlink, rename/rename and rename/delete conflicts. Captures stay under target/ and are not committed.

Gerrit code review is qualified against a disposable fixture only; see the WSL Gerrit fixture and the remaining gates. From PowerShell, scripts/gerrit_fixture.ps1 up -Check -CheckWindows starts the synthetic service, qualifies WSL adapters plus Windows access, and prints the command to open its WSL clone. Windows access uses mirrored WSL networking and explicit 127.0.0.1 endpoints; see the fixture guide for setup and the remaining native SSH/adapter qualification limits.

For an HTTP connection with an explicit target branch, Review > Prepare Gerrit upload reads the effective push URL and complete ancestry beyond the captured remote target. Upload for Gerrit review… then confirms every included commit and the exact refs/for/<branch> destination. Preparation refuses a mismatched project, multiple push URLs or more than 500 commits. Missing, malformed, duplicate or reused Change-Ids block upload. Fetch first; concurrent server changes can alter acceptance and scope. An interrupted upload requires review reconciliation before another upload. SSH upload and production deployment qualification remain unqualified. Prepare Change-Id hook resolves the effective target-side hooks path and verifies the standard Gerrit 3.13.1 script. Install standard Change-Id hook… requires confirmation, creates an absent hook and never replaces an existing one. Git's Gerrit trailer settings remain effective; explicitly amend a commit when needed, then prepare upload again. Squashing commits with review identities requires an explicit Squash, keep… choice in their context menu. It keeps the chosen full message and Change-Id while combining all selected changes.

Pick one changed line in a commit's diff and press C (or Review > Comment on line…) to write a private comment, or a reply to the thread on that line; Resolve thread and Discard draft comment are in the same menu. Drafts stay on this machine with the checkout and show in the diff as "Draft · you". Review > Publish review… posts a multi-line message, one vote per label the service allowed this account and every draft, in one request, on the selected commit's own current patch set (HTTP connections only). A refusal can be retried. After a timeout or lost connection GitDown cannot tell whether Gerrit applied it: it refreshes the review, keeps the drafts and holds further posts on it until that read, so check the review before posting again. Review > Submit review… is separate, asks for confirmation and is offered only when Gerrit reports the review ready; Gerrit may also submit changes it depends on. Context lines, notification choice and work-in-progress changes are not available.

Deliberate limits

  • History loads the newest 2,000 reachable branch and tag commits. Interactive text diffs are bounded to 2 MiB, 50,000 lines and 16 KiB per line; binary, symlink, submodule, metadata-only and larger changes use file-level staging. Diff text selection is confined to one code row, and gutter patch selection is separate.
  • --profile target/timings.csv writes bounded numeric preparation, publication and render telemetry on normal close; it measures CPU work, not presentation (limits).
  • The recorder supports line-based prompts, not a full-screen TUI. Mutations share one serial queue. Index guards are optimistic checks before Git takes its own locks, not an atomic transaction. AI detection reads no transcripts and claims no process ownership or AI authorship.
  • WSL targets are classified lexically before any host filesystem access. A Linux gitdown-worker (GITDOWN_WSL_WORKER, else the one beside the executable; one persistent wsl.exe per distribution) opens checkouts, serves reads and watchers and runs Git on real PTYs (WSL worker). Lost reads fail without retry, a lost command's completion stays unknown until a reconciling read, and mutations are never resent. Reveal and Open validate in Linux before handing a UNC path to Windows; Export patch is refused for WSL; no ref-storage conversion or credential forwarding exists.
  • Not implemented, and the UI shows no simulated controls for them: word-level highlights against the base and rerere notes (framework limits), universal working-tree/index undo, automatic Smart Absorb and restacking. OS-driven System theme following is waived for Windows build 26300. Captures and native-input runs are manual evidence, apart from automated tests.

Git 2.54 and licensing

Newer Git behavior used when present: the Git 2.54 release notes, its alias syntax and configured hooks. Experimental git history and git replay stay explicit direct-CLI choices, never an automatic rewrite backend.

GitDown is all rights reserved (LICENSE). It uses the Slint toolkit under the Slint Royalty-free Desktop, Mobile, and Web Applications License, which About GitDown attributes; every shipped dependency's license is in THIRD_PARTY_NOTICES.md, regenerated with python scripts/generate_notices.py. JetBrains Mono is bundled under its SIL Open Font License and Inter under its own SIL Open Font License. Application crates are marked publish = false. See architecture.md for boundaries and contracts and design.md for the visual system.