Skip to content

Commit 63110a3

Browse files
committed
feat: tray, notifications, accent themes — v0.4.0
Native bits - System tray icon with branch + ahead/behind status, click toggles app via NSApp-level hide/show (no WebView blackout). - Desktop notifications for remote pushes via tauri-plugin- notification. Fires when `behind` grows on the same branch. Customization - Six accent themes (Neutral, Orange, Blue, Green, Rose, Violet) applied to primary buttons + focus rings. Picker in Settings → Appearance. White text on every accent for WCAG AA contrast in both modes. UX - Run-target status pill in the sidebar (pulsing emerald dot + count + port). Reflects every running target via Tauri events. - App version chip next to the "Git Switch" wordmark in the sidebar header, read from tauri.conf.json via getVersion(). - Undo last commit button in the dashboard header (gated by ahead > 0 || !hasUpstream). - Inline diff viewer + commit history popup wired into ChangedFiles + the ⋯ overflow menu. - Adaptive primary action button (Pull / Push / Publish / Fetch) in GitActionsPanel. - Repository picker reframed for "local repository" with clearer copy. Backend - New Rust commands: undo_last_commit, get_commit_history, get_file_diff, quick_status_batch, update_tray_status. - Tauri tray module with procedural monochrome glyph (44×44 template image, donut dots + cubic-bezier S-curve matching logo.svg). Cleanup - Dropped macOS vibrancy code + `transparent: true` window flag; fixes the empty area around the traffic lights. - Sidebar header now uses real app logo via Logo.tsx. Chore - Bump version 0.3.0 → 0.4.0 across package.json, Cargo.toml, tauri.conf.json.
1 parent 5f6458f commit 63110a3

31 files changed

Lines changed: 2987 additions & 261 deletions

.github/workflows/release.yml

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,15 @@ permissions:
1010
contents: write
1111

1212
jobs:
13+
# ── macOS universal build ─────────────────────────────────────────────
1314
build-macos:
1415
name: Build macOS (universal)
1516
runs-on: macos-14
1617
steps:
1718
- uses: actions/checkout@v4
1819
with:
19-
fetch-depth: 0 # full history for git-cliff to walk commits
20+
fetch-depth: 0 # full history for git-cliff
2021

21-
# Generate release notes from Conventional-Commits since the previous
22-
# tag. orhun/git-cliff-action is a Docker container action and only
23-
# runs on Linux runners; we're on macos-14, so install the native
24-
# binary via Homebrew instead. The brew bottle is cached on the
25-
# runner image so this step is ~2s on warm cache.
2622
- name: Install git-cliff
2723
if: startsWith(github.ref, 'refs/tags/')
2824
run: brew install git-cliff
@@ -37,7 +33,7 @@ jobs:
3733
node-version: 20
3834
cache: yarn
3935

40-
- name: Setup Rust + add both macOS targets
36+
- name: Setup Rust + macOS targets
4137
uses: dtolnay/rust-toolchain@stable
4238
with:
4339
targets: aarch64-apple-darwin,x86_64-apple-darwin
@@ -51,50 +47,103 @@ jobs:
5147
- name: Install JS deps
5248
run: yarn install --frozen-lockfile
5349

54-
# Build a universal binary so a single .dmg works on both Apple Silicon
55-
# and Intel Macs. Tauri's CLI orchestrates the dual build + lipo step.
56-
# No Apple env vars passed → Tauri falls back to ad-hoc signing
57-
# (the `-` signing identity in tauri.conf.json) and skips notarization.
58-
# First-launch users will need to right-click → Open once; that's the
59-
# only cost. To enable real notarized signing later, set APPLE_* secrets
60-
# in repo settings and reintroduce them here.
6150
- name: Build Tauri (universal)
6251
run: yarn tauri build --target universal-apple-darwin
6352

6453
- name: Collect artifacts
65-
id: collect
6654
run: |
6755
set -euo pipefail
6856
BUNDLE_DIR="src-tauri/target/universal-apple-darwin/release/bundle"
6957
mkdir -p dist-release
70-
# Copy whatever artifacts exist — names include the version.
7158
find "$BUNDLE_DIR/dmg" -name '*.dmg' -exec cp {} dist-release/ \; || true
72-
# Tarball the .app for users who'd rather not mount a DMG.
7359
APP=$(find "$BUNDLE_DIR/macos" -maxdepth 1 -name '*.app' | head -n1)
7460
if [ -n "$APP" ]; then
7561
tar -C "$BUNDLE_DIR/macos" -czf "dist-release/$(basename "$APP" .app)-${GITHUB_REF_NAME}.app.tar.gz" "$(basename "$APP")"
7662
fi
7763
ls -lah dist-release/
78-
echo "artifacts_dir=dist-release" >> "$GITHUB_OUTPUT"
7964
80-
- name: Upload to GitHub Release
65+
- name: Upload macOS artifacts to Release
8166
if: startsWith(github.ref, 'refs/tags/')
8267
uses: softprops/action-gh-release@v2
8368
with:
8469
draft: false
85-
# body_path overrides GitHub's auto-generated changelog with the
86-
# cliff-formatted notes from the step above. Fallback to the GH
87-
# auto-generator if the file is missing for any reason.
8870
body_path: RELEASE_NOTES.md
8971
generate_release_notes: false
9072
files: |
9173
dist-release/*.dmg
9274
dist-release/*.tar.gz
9375
94-
# Fallback when triggered manually (no tag): keep artifacts on the run.
95-
- name: Upload workflow artifacts
76+
- name: Upload workflow artifacts (no tag)
9677
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
9778
uses: actions/upload-artifact@v4
9879
with:
9980
name: git-switch-macos-universal
10081
path: dist-release/*
82+
83+
# ── Linux x86_64 build ────────────────────────────────────────────────
84+
build-linux:
85+
name: Build Linux (x86_64)
86+
runs-on: ubuntu-22.04
87+
steps:
88+
- uses: actions/checkout@v4
89+
90+
- name: Setup Node
91+
uses: actions/setup-node@v4
92+
with:
93+
node-version: 20
94+
cache: yarn
95+
96+
- name: Setup Rust
97+
uses: dtolnay/rust-toolchain@stable
98+
99+
- name: Cache cargo
100+
uses: Swatinem/rust-cache@v2
101+
with:
102+
workspaces: src-tauri
103+
key: release-linux
104+
105+
# Tauri needs WebKitGTK + GTK + libayatana-appindicator (for the tray)
106+
# plus librsvg2 (for the bundle icon step) and patchelf (for AppImage
107+
# path fixups). These are the canonical Tauri 2 Linux build deps.
108+
- name: Install Linux build dependencies
109+
run: |
110+
sudo apt update
111+
sudo apt install -y \
112+
libwebkit2gtk-4.1-dev \
113+
libgtk-3-dev \
114+
libayatana-appindicator3-dev \
115+
librsvg2-dev \
116+
patchelf
117+
118+
- name: Install JS deps
119+
run: yarn install --frozen-lockfile
120+
121+
- name: Build Tauri (.deb + AppImage)
122+
run: yarn tauri build
123+
124+
- name: Collect artifacts
125+
run: |
126+
set -euo pipefail
127+
BUNDLE_DIR="src-tauri/target/release/bundle"
128+
mkdir -p dist-release
129+
find "$BUNDLE_DIR/deb" -name '*.deb' -exec cp {} dist-release/ \; || true
130+
find "$BUNDLE_DIR/appimage" -name '*.AppImage' -exec cp {} dist-release/ \; || true
131+
find "$BUNDLE_DIR/rpm" -name '*.rpm' -exec cp {} dist-release/ \; || true
132+
ls -lah dist-release/
133+
134+
- name: Upload Linux artifacts to Release
135+
if: startsWith(github.ref, 'refs/tags/')
136+
uses: softprops/action-gh-release@v2
137+
with:
138+
draft: false
139+
files: |
140+
dist-release/*.deb
141+
dist-release/*.AppImage
142+
dist-release/*.rpm
143+
144+
- name: Upload workflow artifacts (no tag)
145+
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
146+
uses: actions/upload-artifact@v4
147+
with:
148+
name: git-switch-linux-x86_64
149+
path: dist-release/*

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ refactor / docs / test / chore / ci / build / revert).
1818
_Pending the next tagged release. New commits will appear here once you run
1919
`git cliff` or push a `v*` tag._
2020

21-
## [0.2.0] initial public release
21+
## [0.2.0] · initial public release
2222

2323
First versioned release. See README for the full feature list.

README.md

Lines changed: 49 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,90 @@
11
<div align="center">
22

3-
<img src="assets/logo.svg" alt="Git Switch" width="128" height="128" />
3+
<img src="assets/logo.svg" alt="Git Switch" width="96" height="96" />
44

55
# Git Switch
66

7-
**A fast, native macOS Git client that runs your dev servers, too.**
7+
A fast, native Git client that runs your dev servers too.
88

9-
[![Tauri](https://img.shields.io/badge/Tauri-2.x-24C8DB?logo=tauri&logoColor=white)](https://tauri.app)
9+
[![Tauri](https://img.shields.io/badge/Tauri-2-24C8DB?logo=tauri&logoColor=white)](https://tauri.app)
1010
[![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=white)](https://react.dev)
11-
[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
12-
[![Tailwind](https://img.shields.io/badge/Tailwind-v4-38BDF8?logo=tailwindcss&logoColor=white)](https://tailwindcss.com)
13-
[![Rust](https://img.shields.io/badge/Rust-DEA584?logo=rust&logoColor=white)](https://www.rust-lang.org)
14-
[![macOS](https://img.shields.io/badge/macOS-Apple_Silicon_%2B_Intel-000000?logo=apple&logoColor=white)](#install)
15-
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
11+
[![Rust](https://img.shields.io/badge/Rust-stable-DEA584?logo=rust&logoColor=white)](https://www.rust-lang.org)
12+
[![macOS](https://img.shields.io/badge/macOS-Apple_Silicon_%2B_Intel-000?logo=apple&logoColor=white)](#install)
13+
[![Linux](https://img.shields.io/badge/Linux-x86__64-FCC624?logo=linux&logoColor=black)](#install)
14+
[![MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
1615

1716
</div>
1817

1918
---
2019

21-
## Features
22-
23-
**Git**
24-
- Multi-repo sidebar — folder picker (multi-select) or drag-and-drop, persists across launches
25-
- Per-repo status tints in the sidebar — behind = rose · uncommitted = amber · ahead = emerald
26-
- Searchable branch picker · create branch from scratch (`git switch -c`) or check out remote as local
27-
- Dirty-tree guard before switching, with confirmation dialog
28-
- Adaptive primary action button — switches between **Pull / Push / Publish / Fetch** based on ahead / behind / upstream state
29-
- `` overflow menu consolidates every git action: refresh, fetch, pull, push, create branch, publish branch, show history
30-
- Publish branch with one click (`git push -u origin <branch>`) when upstream is missing
31-
- Stage / unstage selected · stage all · commit · optimistic UI (file list flips instantly)
32-
- **Undo last commit** — safe `git reset --soft HEAD~1`, only shown when the commit hasn't been pushed
33-
- **Inline diff viewer** for any changed file (eye icon on the row) — syntax-light unified diff with sticky line-number gutter
34-
- **Commit history popup** — last 50 commits with author, short hash, relative time
35-
- Sensitive files (`.env`, `*.pem`, SSH keys, …) surface at the top of the changes list in red — one click adds them to `.gitignore` and untracks
36-
- Ahead / behind indicators in the dashboard header
37-
- Native FS watcher (`notify` / FSEvents) auto-refreshes the GUI when the terminal touches the repo
38-
- Shift-click range select · `⌘↵` commit · `⌘R` refresh · `⌘P` pull · `⌘⇧P` push
39-
40-
**AI commits**
41-
- ✨ Generate Conventional-Commits messages from the staged diff via Gemini
42-
- Live model picker — only shows models your API key can actually invoke, auto-falls back when quota's hit
43-
44-
**Run / dev environments**
45-
- Multiple run targets per repo — `yarn dev`, `yarn dev:worker`, `cargo run`, each with its own terminal tab, port, and restart command
46-
- Real PTY (xterm.js + `portable-pty`) → ANSI colors, progress bars, `⌃C`, login-shell PATH all work
47-
- Smart port management — read from `.env` or set per-target; conflicts prompt before killing the holder
48-
- Process-group kills (`setsid` + `killpg`) — `nodemon` orphans and detached `node` children die with the parent, no zombie servers
49-
- Branch-aware auto-restart — switch branch, every running target relaunches
50-
- Sleep-safe; clean shutdown on app close
51-
52-
**Groups**
53-
- Bundle multiple repos as a group, fire them all in parallel with one click
54-
- Filterable picker with sticky select-all row (handy when you've added 20+ repos)
55-
- Color-coded bulk actions (Run / Stop / Restart) react to live aggregate status
56-
- Each member runs with **its own** saved config — the group is just a launcher
57-
58-
**UX & performance**
59-
- Light + dark themes that propagate instantly across every panel (including xterm.js)
60-
- macOS-style frosted-glass toasts (Sonner) with severity-encoded icons
61-
- Tooltips on every icon and the adaptive sync button (shows the underlying git command)
62-
- Rolling command-output log with per-row status
63-
- Async backend — `git fetch` / `pull` / `push` never freeze the UI
64-
- Batched sidebar refresh — one IPC fetches quick-status for every repo in parallel
65-
- Lazy-loaded heavy panels (xterm.js, every dialog) — small initial JS payload
20+
## What it does
6621

67-
---
22+
Multi-repo Git GUI with a built-in PTY-backed dev-server launcher. Switch
23+
branches, commit, push, and start every project's dev server from one
24+
window.
25+
26+
## Highlights
27+
28+
- **Multi-repo sidebar** with live status tints and an FS watcher.
29+
- **Adaptive sync button** that switches between Pull / Push / Publish / Fetch based on branch state.
30+
- **Inline diff viewer** and **commit history popup**.
31+
- **Undo last commit** (safe `git reset --soft`, never on pushed history).
32+
- **AI commit messages** via Gemini, with auto-fallback when a model is rate-limited.
33+
- **Run targets** like `yarn dev`, `cargo run`, each with its own xterm tab and port management.
34+
- **Groups** to bundle repos and run them in parallel.
35+
- **Menu-bar tray** showing the active repo's branch and ahead/behind status.
36+
- **Desktop notifications** when teammates push new commits to your branch.
37+
- **Six accent themes** (Neutral, Orange, Blue, Green, Rose, Violet) plus light/dark mode.
38+
- **Async backend**, so `git fetch` / `pull` / `push` never freeze the UI.
6839

6940
## Install
7041

42+
One command. Detects your OS, fetches the latest release, drops it in
43+
the right place. Re-run to update.
44+
7145
```bash
72-
# Prerequisites (one-time)
73-
xcode-select --install # git
74-
brew install node # Node 20+
75-
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && source "$HOME/.cargo/env"
76-
brew install librsvg # for icon generation
46+
curl -fsSL https://raw.githubusercontent.com/Avijit07x/git-switch/main/install.sh | bash
47+
```
48+
49+
### Build from source
7750

78-
# Clone + run
51+
```bash
7952
git clone git@github.com:Avijit07x/git-switch.git
8053
cd git-switch
8154
yarn install
8255
yarn tauri:dev
8356
```
8457

85-
First launch compiles ~400 Rust crates — expect 2–5 min cold, seconds thereafter.
86-
87-
### Build a `.app` / `.dmg`
58+
Prerequisites: Git, Node 20+, Rust stable. On Debian / Ubuntu also install
59+
`libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf`.
8860

89-
```bash
90-
yarn tauri icon assets/logo.svg # first time only
91-
yarn tauri:build
92-
```
61+
First launch compiles roughly 400 Rust crates. Expect 2 to 5 minutes
62+
cold, seconds thereafter.
9363

94-
Output: `src-tauri/target/release/bundle/macos/Git Switch.app` and the matching `.dmg`. For a Universal binary:
64+
### Build a release bundle
9565

9666
```bash
97-
rustup target add x86_64-apple-darwin aarch64-apple-darwin
98-
yarn tauri build --target universal-apple-darwin
67+
yarn tauri:build
9968
```
10069

101-
### First launch on macOS
102-
103-
Git Switch ships with **ad-hoc signing** (free, no Apple Developer account). macOS Gatekeeper will warn you the very first time:
104-
105-
1. Right-click **Git Switch.app** in Finder → **Open**
106-
2. Confirm in the dialog that appears
107-
3. macOS remembers your choice — every launch after that is normal
108-
109-
If you'd rather skip the prompt entirely, you can strip the quarantine flag once:
70+
Output lands in `src-tauri/target/release/bundle/`. The installer script
71+
handles signing quirks automatically; if you're distributing a manual
72+
build on macOS, strip the quarantine flag once:
11073

11174
```bash
11275
xattr -dr com.apple.quarantine "/Applications/Git Switch.app"
11376
```
11477

115-
---
116-
11778
## Safety
11879

119-
Out of scope by design: force push, rebase, hard reset, discard, stash, merge-conflict resolution, raw command input. The one carve-out is `git reset --soft HEAD~1` (the **Undo last commit** button), which never touches your working tree and only appears when the commit hasn't been pushed.
120-
121-
Auth relies on your existing Git setup (SSH keys, Keychain, `gh`, credential helper) — Git Switch stores nothing related to remotes.
122-
123-
The Gemini API key (if set) lives in `localStorage` and is only ever sent to `generativelanguage.googleapis.com` when you click ✨ Generate.
80+
Out of scope: force push, rebase, hard reset, discard, stash, and
81+
merge-conflict resolution. The one carve-out is `git reset --soft HEAD~1`
82+
behind the **Undo** button, which only appears for local-only commits
83+
that haven't been pushed.
12484

125-
126-
---
85+
Auth uses your existing Git setup (SSH keys, Keychain, `gh`, credential
86+
helper). The Gemini API key, if set, lives in `localStorage` and is only
87+
sent to `generativelanguage.googleapis.com` when you click ✨ Generate.
12788

12889
## License
12990

0 commit comments

Comments
 (0)