Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
af5059f
update
hoangsvit Jun 28, 2026
d40b992
update
hoangsvit Jun 28, 2026
04befef
update
hoangsvit Jun 28, 2026
6ad3136
update
hoangsvit Jun 28, 2026
0689530
update
hoangsvit Jun 28, 2026
1dbcdcf
update
hoangsvit Jun 28, 2026
7ab2ef1
update
hoangsvit Jun 28, 2026
386e2d5
UPDATE LAYOUT
hoangsvit Jun 28, 2026
7a4862f
UPDATE LAYOUT
hoangsvit Jun 28, 2026
1d8e041
feat: enhance sidebar and status panel with item counts and collapsib…
hoangsvit Jun 29, 2026
013c75c
style: update color scheme across components for improved UI consistency
hoangsvit Jun 29, 2026
06a7358
feat: add insertion and deletion stats to commit info and enhance his…
hoangsvit Jun 29, 2026
f7b4cbb
feat: implement commit graph functionality with parsing and visualiza…
hoangsvit Jun 29, 2026
4e926fa
feat: implement merge conflict resolution panel with file selection a…
hoangsvit Jun 29, 2026
847a980
feat: add fetch all remotes functionality and enhance branch tracking…
hoangsvit Jun 29, 2026
b0b2c98
feat: update git history command to use topo-order and enhance graph …
hoangsvit Jun 29, 2026
bde2d06
feat: enhance GitGraph with branch tooltip and improve edge rendering…
hoangsvit Jun 29, 2026
38f31b9
feat: add auto fetch interval setting and improve branch tooltip display
hoangsvit Jun 29, 2026
dba6852
feat: add hover badge for branch details with portal rendering
hoangsvit Jun 29, 2026
c476f6b
feat: refactor GraphSvg into GraphLayer for improved SVG rendering an…
hoangsvit Jun 29, 2026
5db565d
feat: adjust lane width and stroke width for improved branch visibili…
hoangsvit Jun 29, 2026
84eaca0
feat: enhance GraphLayer with lane hover effects and opacity adjustme…
hoangsvit Jun 29, 2026
a3c0d9e
feat: enhance commit graph functionality with remote tracking and ups…
hoangsvit Jun 29, 2026
b96c9b3
feat: add GitPilotIcon component with SVG representation for improved…
hoangsvit Jun 29, 2026
449c886
feat: implement WelcomeScreen component and integrate GitPilotIcon fo…
hoangsvit Jun 29, 2026
627bde9
feat: add adaptive icons and improve repo/branch switching UI
hoangsvit Jun 29, 2026
de188ea
Improve GitKraken-style context menus
hoangsvit Jun 29, 2026
32a73f1
Merge pull request #20 from ePlus-DEV/codex/toi-uu-code-va-kiem-tra-t…
hoangsvit Jun 29, 2026
e1ae840
Add welcome setup unit tests
hoangsvit Jun 29, 2026
e7e7a3e
Merge pull request #21 from ePlus-DEV/codex/cap-nhat-ui-man-hinh-cai-app
hoangsvit Jun 29, 2026
673c229
feat: enhance context menu for branch actions and add header support
hoangsvit Jun 30, 2026
c5126c4
feat: implement column configuration menu and layout management
hoangsvit Jun 30, 2026
547e169
feat: add system commands for opening terminal and file manager, and …
hoangsvit Jun 30, 2026
cef64ae
feat: add updater and process plugins with permission configurations
hoangsvit Jun 30, 2026
f1d2c90
feat: add GitHub Actions workflow for release automation and configur…
hoangsvit Jun 30, 2026
1d8c315
feat: enhance auto-update check on startup to show dialog if an updat…
hoangsvit Jun 30, 2026
b6c226e
feat: enhance update dialog with test mode and add relaunch option in…
hoangsvit Jun 30, 2026
cc491b5
feat: update settings management to use unified settingsTab state and…
hoangsvit Jun 30, 2026
2570a86
feat: add New Tab functionality with repository management options
hoangsvit Jun 30, 2026
6894069
feat: improve tab activation logic and handle new tab state on tab click
hoangsvit Jun 30, 2026
cccf3e7
feat: refactor RepoTabs component to improve tab rendering and close …
hoangsvit Jun 30, 2026
d2576f1
feat: implement run_shell_command to execute shell commands and retur…
hoangsvit Jun 30, 2026
eb18d19
feat: add revert_hunk command to restore changes from a specific hunk…
hoangsvit Jun 30, 2026
8b4e5a2
feat: enhance history retrieval with optional skip parameter and impr…
hoangsvit Jun 30, 2026
4ab5006
feat: enhance UI components with improved styling and search function…
hoangsvit Jun 30, 2026
6b02b89
feat: enhance user prompts and confirmations across components
hoangsvit Jun 30, 2026
b26ab74
feat: update branch handling in get_status and improve layout in TopB…
hoangsvit Jun 30, 2026
9bf2848
feat: manage busy state during async operations in run function
hoangsvit Jun 30, 2026
b2b1756
feat: enhance commit information structure with author email and impr…
hoangsvit Jun 30, 2026
83a4f70
feat: enhance undo/redo functionality with loading states and improve…
hoangsvit Jun 30, 2026
110ad50
feat: add update channel selection and enhance version handling for r…
hoangsvit Jun 30, 2026
c510c8f
feat: adjust SVG height calculation and refactor list reference handl…
hoangsvit Jun 30, 2026
7a2440c
feat: add per-repo auto-fetch configuration in Sidebar and enhance re…
hoangsvit Jun 30, 2026
aa5623e
feat: add unit tests for SettingsPanel component and configure Vitest
hoangsvit Jun 30, 2026
08fa2a9
Update README.md
hoangsvit Jun 30, 2026
d16cf49
feat: add UI tests for SettingsPanel and enhance mock implementations
hoangsvit Jun 30, 2026
c09be1a
fix: add TypeScript error suppression for dynamic URL checks in updater
hoangsvit Jun 30, 2026
01c7f42
feat: enhance artifact summary in CI workflow with size and updated date
hoangsvit Jun 30, 2026
dbc8243
feat: improve rendering logic for merge panel and diff viewer in App …
hoangsvit Jun 30, 2026
005c3ba
feat: enhance GitGraph component with compact mode and improved badge…
hoangsvit Jun 30, 2026
ea0b788
feat: update release workflow to support numeric-only pre-release ver…
hoangsvit Jun 30, 2026
fdc1b03
fix: remove alpha suffix from tauri.conf.json version for MSI compati…
hoangsvit Jun 30, 2026
377a10c
fix: remove version from tauri.conf.json — reads from package.json (s…
hoangsvit Jun 30, 2026
30db8e3
docs: update RELEASE.md — single source of truth versioning via packa…
hoangsvit Jun 30, 2026
d1696f9
feat: show update channel badge (alpha/beta) next to version in statu…
hoangsvit Jun 30, 2026
b5abae4
feat: replace alpha channel with beta channel across settings, update…
hoangsvit Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(npm view *)",
"Bash(npm search *)"
]
}
}
16 changes: 11 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,23 +111,29 @@ jobs:
per_page: 100,
});
const artifactByName = new Map(artifacts.map((artifact) => [artifact.name, artifact]));
const fmtSize = (bytes) => `${(bytes / 1_048_576).toFixed(1)} MB`;
const fmtDate = (iso) => {
const d = new Date(iso);
return d.toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
};
const artifactLines = artifactNames.map((name) => {
const artifact = artifactByName.get(name);
const label = name.replace('gitpilot-', '');
if (!artifact) {
return `- ${label}: \`${name}\` (open [workflow run](${runUrl}) to download)`;
return `- **${label}**: \`${name}\` (open [workflow run](${runUrl}) to download)`;
}
const artifactUrl = `${runUrl}/artifacts/${artifact.id}`;
return `- ${label}: [\`${name}\`](${artifactUrl})`;
const size = fmtSize(artifact.size_in_bytes);
const updated = fmtDate(artifact.updated_at);
return `- **${label}**: [\`${name}\`](${artifactUrl}) — ${size} · updated ${updated}`;
});

const now = new Date().toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
const body = [
marker,
'### GitPilot build artifacts are ready',
'',
`One CI workflow run built all 3 desktop apps: [open workflow run](${runUrl}).`,
'',
'Download links:',
`Built all 3 desktop apps — [workflow run](${runUrl}) · _last updated ${now}_`,
'',
...artifactLines,
].join('\n');
Expand Down
114 changes: 114 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Release

on:
push:
tags:
- 'v*'

jobs:
release:
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: windows-latest
args: '--target x86_64-pc-windows-msvc'
- platform: macos-latest
args: '--target aarch64-apple-darwin'
- platform: macos-latest
args: '--target x86_64-apple-darwin'
- platform: ubuntu-22.04
args: ''

runs-on: ${{ matrix.platform }}

steps:
- uses: actions/checkout@v4

- name: Detect pre-release
id: meta
shell: bash
run: |
TAG="${{ github.ref_name }}"
VERSION="${TAG#v}"
# MSI requires numeric-only pre-release — strip suffix for bundle version
APP_VERSION="${VERSION%%-*}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "app_version=$APP_VERSION" >> $GITHUB_OUTPUT
if [[ "$TAG" =~ -(alpha|beta|rc) ]]; then
echo "prerelease=true" >> $GITHUB_OUTPUT
else
echo "prerelease=false" >> $GITHUB_OUTPUT
fi

- name: Sync version into tauri.conf.json
shell: bash
run: |
node -e "
const fs = require('fs');
const p = 'src-tauri/tauri.conf.json';
const c = JSON.parse(fs.readFileSync(p, 'utf8'));
c.version = '${{ steps.meta.outputs.app_version }}';
fs.writeFileSync(p, JSON.stringify(c, null, 2) + '\n');
"

- name: Install dependencies (Ubuntu)
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}

- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: ./src-tauri -> target

- name: Install frontend deps
run: npm install

- name: Build & release
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
with:
tagName: ${{ github.ref_name }}
releaseName: 'GitPilot ${{ github.ref_name }}'
releaseBody: |
See the assets below to download and install this version of GitPilot.
releaseDraft: false
prerelease: ${{ steps.meta.outputs.prerelease }}
args: ${{ matrix.args }}
includeUpdaterJson: true

# For pre-releases: push latest.json to beta-channel so beta users get update notifications.
- name: Publish to beta-channel (pre-release only, one runner)
if: steps.meta.outputs.prerelease == 'true' && matrix.platform == 'ubuntu-22.04'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
gh release download ${{ github.ref_name }} --pattern latest.json --output /tmp/latest.json

if gh release view beta-channel &>/dev/null; then
gh release upload beta-channel /tmp/latest.json --clobber
else
gh release create beta-channel /tmp/latest.json \
--title "Beta Channel (auto-updated)" \
--notes "This release is automatically updated to the latest pre-release build. Do not install manually — use the in-app update system." \
--prerelease
fi
73 changes: 73 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Contributing to GitPilot

## Stack

- **Frontend**: React 18, TypeScript, Tailwind CSS, Zustand, Monaco Editor
- **Backend**: Tauri v2, Rust (`std::process::Command` — no shell strings for git operations)
- **Build**: Vite

## Setup

```bash
npm install
npm run tauri dev
```

## Build

```bash
npm run tauri build
```

## Project layout

```
src/
components/ React UI components
store/ Zustand store (gitStore.ts)
services/ IPC wrappers (gitService.ts)
types/ Shared TypeScript types (git.ts)
utils/ Helpers (repoConfig, etc.)

src-tauri/
src/commands/ Tauri commands exposed to frontend
src/services/ Rust git service logic
src/models/ Serde models (git.rs, settings.rs)
```

## Store shape

| Field | Type | Purpose |
| --- | --- | --- |
| `busy` | `boolean` | Any operation in flight |
| `refreshing` | `boolean` | Explicit refresh only (drives Refresh button spinner) |
| `runningOp` | `string \| null` | Label of active operation (drives per-button spinners) |
| `undoStack` | `UndoEntry[]` | Undo history, max 20 entries |
| `redoStack` | `UndoEntry[]` | Redo history |

### `run(label, fn, refreshMode?, undoable?)`

Sets `busy + runningOp`, calls `fn`, optionally pushes to undo stack, then calls `refresh(silent=true)`.

### `refresh(silent?)`

`silent=true` skips the `refreshing` flag so the Refresh button spinner does not fire during background refreshes triggered by `run()`.

## Commit graph virtualization

`GitGraph` uses a `ResizeObserver` attached via a **callback ref** (`useState` + `useCallback`) so the observer re-registers whenever the list DOM element mounts or changes. `svgH = rows.length * ROW_H + ROW_H` adds a one-row buffer so lane lines of the last loaded commit do not clip at the SVG boundary.

## Release process

Tags matching `v*` trigger the GitHub Actions release workflow:

- Detects pre-release from tag suffix (`-alpha`, `-beta`, `-rc`)
- Syncs version from tag into `tauri.conf.json`
- Builds for Windows x64, macOS arm64, macOS x64, Linux
- `includeUpdaterJson: true` on all builds
- Alpha builds push `latest.json` to the permanent `alpha-channel` release via `gh release upload --clobber`

Update channels:

- **Stable**: `releases/latest/download/latest.json`
- **Alpha**: `releases/download/alpha-channel/latest.json`
92 changes: 61 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,79 @@
# GitPilot

GitPilot is a desktop Git GUI client built with Tauri v2, Rust, React, TypeScript, Tailwind CSS, Zustand, and Monaco Editor.
A desktop Git GUI client built with Tauri v2 + Rust + React.

<img width="1919" height="1029" alt="image" src="https://github.com/user-attachments/assets/2bffb8f2-a8be-4930-9af1-fc0fa4553ee9" />


## Features

- Repository management with validation, current branch display, and recent repositories.
- Git status from `git status --porcelain=v1 -b` grouped as staged, unstaged, untracked, and conflicted.
- Stage, unstage, discard, delete untracked files, stage all, and unstage all.
- Monaco side-by-side and inline diff viewer with binary-file handling.
- Commit staged files, amend last commit, and generate command output.
- Branch, remote, history, graph, merge, rebase, stash, tag, validation, AI assistant, settings, and keyboard shortcut support.
- 3-pane merge conflict resolver with conflict marker parsing and save + git add workflow.
### Repository management

- Recent-repository list with quick switching
- Per-repo auto-fetch interval override (Sidebar › Repositories › ⚙)
- Open, clone, or init repositories from the top bar or native menu
- Tab-based multi-repo interface

### History & commit graph

- Virtualized commit graph with branch lanes, bezier merge curves, and HEAD indicator
- Filter by branch, author, date range, file path, or free-text search
- Dim/hide merge commits toggle; load-more pagination
- Commit details: author `name <email>`, date, SHA, parents — click any field to copy
- Right-click commit: checkout, cherry-pick, rebase, reset (soft/mixed/hard), revert, create branch/tag/worktree, copy SHA, create patch

### Branch management

- Branch switcher with right-click context menu: Pull, Push, Rename, Delete, Copy, Create tag
- Sidebar branch list with full context menu: Checkout, Merge, Rebase, Reset, Push, Pull, Fetch, Delete, Rename
- Correct display of branch names containing dots (e.g. `feature/v1.2.0`)

### Working directory & commits

- Stage, unstage, discard, delete untracked; stage all / unstage all
- Monaco side-by-side and inline diff viewer with binary-file handling
- Commit with message, amend last commit
- Commit is undoable — Undo runs `git reset HEAD~1 --soft`; Redo re-commits

### Undo / Redo

- Dedicated Undo and Redo buttons in the top bar (separate from Refresh)
- 20-entry undo/redo history

### Conflict resolution & rebase

## Install
- 3-pane merge conflict resolver (current / incoming / result) with accept-current, accept-incoming, accept-both, and manual edit
- Rebase: start, continue, abort, skip; interactive todo editor for pick, reword, edit, squash, fixup, drop, reorder
- Cherry-pick: apply commit, abort in-progress cherry-pick

```bash
npm install
```
### Stash, tags, worktrees

## Run development app
- Stash: list, push, pop, apply, drop
- Tags: list, create lightweight and annotated, delete
- Worktrees: list, create from branch or commit, remove

```bash
npm run tauri dev
```
### AI assistant

## Build desktop app
- Configurable provider (Ollama, OpenAI, Anthropic, Groq), API key, and model
- Generate commit message from staged diff; explain diff in natural language

```bash
npm run tauri build
```
### Auto-updates

## Architecture
- **Stable channel**: official releases only
- **Alpha channel**: opt-in in Settings › General › Update Channel for early test builds
- In-app update dialog with download progress and one-click install + relaunch

Rust commands live in `src-tauri/src/commands`, shared services in `src-tauri/src/services`, and serialized models in `src-tauri/src/models`. The backend uses native Git CLI through `std::process::Command` with argument arrays; shell strings are not used for Git operations.
### Settings

React UI lives in `src/components`, state in `src/store/gitStore.ts`, IPC services in `src/services/gitService.ts`, and shared TypeScript types in `src/types/git.ts`.
- General: global auto-fetch interval, update channel
- Git: custom git binary path
- AI: provider, API key, model, default target branch
- About: version info

## GitPilot feature coverage
## Download

GitPilot now includes first-pass production workflows for the highest-priority Git operations:
See [Releases](https://github.com/ePlus-DEV/GitPilot/releases) for the latest build.

- Visual conflict resolution parses conflict markers, presents current/incoming/result panes, supports accept-current, accept-incoming, accept-both, manual edits, and stages files after all markers are removed.
- Rebase tooling supports normal rebase, paused-state detection, continue, abort, skip, and an interactive todo editor for pick, reword, edit, squash, fixup, drop, and reorder operations.
- Cherry-pick commands support applying a selected commit and aborting an in-progress cherry-pick so conflicts can route through the same resolver.
- Stash management supports list, push, apply, pop, drop, and rename from the stash panel.
- Productivity primitives are available for blame, fuzzy smart search, and worktree list/create/remove commands.
## License

Some larger roadmap items, such as provider-backed pull-request review, CI aggregation, enterprise telemetry, and release signing, are intentionally exposed as modular command/service seams for follow-up hardening rather than hard-coded into the UI.
[MIT](LICENSE)
Loading
Loading