Releases: gpambrozio/GitWorkbench
GitWorkbench 1.3.0
What's new in 1.3.0
All remote branches in the rail. The REMOTES section now lists every remote-tracking branch, grouped under its remote, instead of only the current branch's upstream:
- Branches show without the remote prefix (
develop,feat/auto-sync— notorigin/develop), grouped under each remote, so multiple remotes are supported (not just a hardcodedorigin). - The branch your current branch tracks is shown bold + accent-colored.
- Single-click a remote branch to view its history; double-click to check it out locally as a tracking branch (or switch to an existing local branch of the same name).
The section is hidden entirely when there are no remote-tracking branches, and the remote-name sub-headers are non-interactive labels (no hover or tap affordance).
Provider changes
GitWorkbenchProvider gains two methods, mirroring the existing loadBranches() / switchBranch(to:) pair:
func loadRemoteBranches() async throws -> [RemoteBranch]
func checkoutRemoteBranch(_ branch: RemoteBranch) async throwsA new RemoteBranch value (Sendable, Hashable, Identifiable) carries the full ref as its id (origin/feat/auto-sync, unique across remotes), the remote name, and the prefix-stripped name for display.
The bundled MockGitProvider and GitWorkbenchGitKit's CLIGitProvider both implement the new methods. CLIGitProvider reads remotes via git for-each-ref … refs/remotes and checks out with git switch --track.
Upgrading from 1.2.0
These two methods are required (no default implementations). If your host implements GitWorkbenchProvider itself, add loadRemoteBranches() and checkoutRemoteBranch(_:) to your conformance — return [] from the former (the REMOTES section then stays hidden) if you don't want remote-branch support. Hosts using the bundled providers need no changes. No existing method signatures or state shapes changed.
Requirements
- macOS 15+
- Swift 6 (language mode v6)
Installation
.package(url: "https://github.com/gpambrozio/GitWorkbench.git", from: "1.3.0"),GitWorkbench 1.2.0
What's new in 1.2.0
Observe the repository summary. A new public view modifier hands your host a small, stable snapshot of the repository so you can drive your own chrome — a menu-bar item, dock badge, window title, or sidebar badge — without running git again or reaching into the store:
GitWorkbenchView(store: store)
.onRepositorySummaryChange { summary in
// summary.currentBranch, .changedFileCount, .stagedCount, .unstagedCount,
// .hasConflicts, .additions/.deletions, .needsPush/.needsPull, .isClean, .isBusy
}The closure fires once the first load has completed, then once per distinct summary (deduplicated via Hashable) — the pre-load empty placeholder is never delivered, so there's no isEmpty guard to write. Stacking is additive: applying it from two independent feature layers runs both observers.
RepositorySummary is a Sendable, Hashable value whose convenience flags (changedFileCount, needsPush, needsPull, isClean) are computed from its stored primitives, so it can never be internally inconsistent.
Headless store.summary. GitWorkbenchStore is now @Observable and exposes the same snapshot directly:
public private(set) var summary: RepositorySummary? // nil until the first load completesA host that already holds the store can read store.summary in its own SwiftUI body — updated live as the working tree changes — even while no GitWorkbenchView is mounted. Useful for a badge or sidebar branch that's visible when the git UI isn't.
Upgrading from 1.1.0
GitWorkbenchStore moved from ObservableObject to the @Observable macro. If your host stored it with @StateObject / @ObservedObject, switch to @State (for an owned store) or a plain let reference, and use @Bindable where you need a two-way binding. No method or state shapes changed.
Requirements
- macOS 15+
- Swift 6 (language mode v6)
Installation
.package(url: "https://github.com/gpambrozio/GitWorkbench.git", from: "1.2.0"),GitWorkbench 1.1.0
What's new in 1.1.0
Automatic live-refresh. The workbench now keeps itself in sync with the repository on disk — external edits, commits, branch switches, and stashes show up without any host wiring. Providers opt in by vending a change stream:
public protocol GitWorkbenchDataSource {
/// Emits whenever the repository changes on disk. Return nil (the default) to opt out.
func repositoryChanges() -> AsyncStream<Void>?
}CLIGitProvider implements this with an FSEvents-backed watcher out of the box. Pass watchesFileSystem: false to its initializer if your host drives its own refresh instead:
CLIGitProvider(repositoryURL: url) // watches automatically
CLIGitProvider(repositoryURL: url, watchesFileSystem: false) // opt outDiff mode persists. The unified/split toggle is now remembered across launches through the same WorkbenchLayoutStore that already persists the resizable column widths.
Pull / push counts as badges. Pending commits to pull or push appear as neutral count badges on the Pull and Push buttons, matching the Staged/Changes header badges.
History stays fresh after a pull. Pulling now refreshes the History view so the fetched commits appear immediately.
Slimmer toolbar. The toolbar branch pill and the History/Stashes toggle buttons were removed — branch switching and those views already live in the sidebar rail, so they're no longer duplicated up top.
Requirements
- macOS 15+
- Swift 6 (language mode v6)
Installation
.package(url: "https://github.com/gpambrozio/GitWorkbench.git", from: "1.1.0"),GitWorkbench 1.0.1
What's new in 1.0.1
Custom file actions on the Changes tab. Attach your own right-click and double-click behavior to file rows with view modifiers on GitWorkbenchView. Each callback receives the clicked file's URL — absolute when you set WorkbenchConfiguration.repositoryURL (typically the same URL you give CLIGitProvider).
GitWorkbenchView(store: store)
.onChangesDoubleClick { url in NSWorkspace.shared.open(url) }
.onChangesRightClick { url in /* run an action */ }
.onChangesRightClickPopover { url in FileActionsMenu(url: url) } // show your own popoverEverything is opt-in: with no modifier attached, rows behave exactly as before — single-click still selects, and the stage box, discard button, and hover are untouched. Double-clicks landing on the stage box or discard button are ignored so they don't fire your action on top of those controls.
Requirements
- macOS 15+
- Swift 6 (language mode v6)
Installation
.package(url: "https://github.com/gpambrozio/GitWorkbench.git", from: "1.0.1"),GitWorkbench 1.0.0
The first stable release of GitWorkbench — a native macOS git-changes UI for SwiftUI, shipped as a dependency-free Swift package. You supply the repository data; GitWorkbench renders it and turns user actions back into calls you handle.
Highlights
- Changes — stage / unstage / discard, commit, unified and side-by-side diffs, with live filesystem refresh.
- History — commit graph with refs, per-commit changed files and diffs; single-click any branch to browse its history.
- Stash — apply / pop / drop.
- Resizable columns (persisted via a host-supplied store), customizable light + dark themes (swappable at runtime), and draggable horizontal scrolling for long diff lines.
Packaging
Two libraries:
GitWorkbench— the SwiftUI component and its state store. Zero third-party dependencies.GitWorkbenchGitKit— an optional, ready-made provider backed by the systemgitCLI (via FoundationProcess). A separate target on purpose, so UI-only consumers never pull a git backend.
Requirements
- macOS 15+
- Swift 6 (language mode v6)
Installation
.package(url: "https://github.com/gpambrozio/GitWorkbench.git", from: "1.0.0"),See the README for a quick start, and how it was built.