Skip to content

Releases: gpambrozio/GitWorkbench

GitWorkbench 1.3.0

14 Jun 00:11
697a269

Choose a tag to compare

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 — not origin/develop), grouped under each remote, so multiple remotes are supported (not just a hardcoded origin).
  • 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 throws

A 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

09 Jun 19:52
e4d6ae9

Choose a tag to compare

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 completes

A 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

09 Jun 03:50

Choose a tag to compare

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 out

Diff 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

06 Jun 20:50

Choose a tag to compare

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 popover

Everything 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

04 Jun 22:43

Choose a tag to compare

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 system git CLI (via Foundation Process). 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.