As developers, we commit code constantly. The annoying part is that quick commits tend to force a slow workflow:
- Open a heavy IDE (often just to stage files and write a message), or
- Run
git add . && git commit -m "fix"in a terminal and hope you remember what changed.
I wanted the best parts of both worlds: visual staging like a GUI, but the speed of a terminal.
So I built GitPop: a lightweight Windows File Explorer extension that adds a modern Git commit UI to your right-click menu, with an optional local AI commit generator.
What GitPop does
From File Explorer, you can right-click inside any repo folder and choose GitPop Here to open a small popup that lets you:
- See changed files instantly
- Stage and unstage with a clean UI
- Review diffs (without switching to a separate app) - Coming soon.
- Generate commit messages from staged diffs using local models via Ollama (or your preferred API)
The core goal is simple: make the “small commit” workflow as fast as a shell command, but less blind.
Tech stack and why Tauri
For a context menu popup, the most important metric is startup time. If right-clicking a folder and selecting GitPop Here takes a noticeable moment, it feels broken.
GitPop uses:
- Frontend: React + TypeScript + vanilla CSS (glassmorphism-style dark UI)
- Backend: Rust
- Framework: Tauri v2
I ruled out Electron because it ships a full Chromium runtime and commonly incurs large binary sizes and heavier memory overhead compared to a native-webview approach. Tauri uses the system webview (WebView2 on Windows) with a Rust backend, which fits the “open instantly” requirement much better.
The engineering challenges
Windows integration looks simple from the outside, but there are a few spicy corners. These were the big three.
1. Registering a File Explorer context menu entry (from Rust)
To show GitPop Here in the right-click menu, GitPop needs to register a command in the Windows Registry.
Instead of asking users to run a .reg file (which feels sketchy even when it is not), GitPop can do this via a Rust command in a “Setup Mode”.
This uses the winreg crate and registers under:
HKCU\Software\Classes\Directory\Background\shell\GitPop
That keeps the install per-user (no admin required) and binds the command to the app executable path:
use winreg::enums::*;
use winreg::RegKey;
#[tauri::command]
fn install_context_menu() -> Result<(), String> {
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let exe_path = std::env::current_exe()
.map_err(|e| e.to_string())?
.to_string_lossy()
.into_owned();
let bg_path = r#"Software\Classes\Directory\Background\shell\GitPop"#;
let (bg_key, _) = hkcu
.create_subkey(bg_path)
.map_err(|e| e.to_string())?;
bg_key.set_value("", &"GitPop Here").map_err(|e| e.to_string())?;
bg_key
.set_value("Icon", &format!("\"{}\"", exe_path))
.map_err(|e| e.to_string())?;
let (bg_cmd, _) = bg_key
.create_subkey("command")
.map_err(|e| e.to_string())?;
// %V resolves to the clicked folder path for Directory\Background handlers.
bg_cmd
.set_value("", &format!("\"{}\" \"%V\"", exe_path))
.map_err(|e| e.to_string())?;
Ok(())
}
Why this approach works well:
- It is self-contained and reversible
- It avoids “copy this registry text and trust me” instructions
- It stays compatible with existing Git setups because GitPop does not try to reconfigure Git
2. The “flashing terminal” bug when spawning Git on Windows
GitPop does not use libgit2. Instead, the Rust backend spawns native Git CLI commands like:
git status --porcelaingit diff --cachedgit commit -m ...
This is intentional: the Git CLI automatically respects the user’s existing SSH keys, credential helpers, hooks, and global configs.
On Windows, though, naïvely calling Command::new("git") can cause a CMD window to flash briefly. It is the kind of micro-annoyance that makes an app feel janky.
The fix is to set a Windows-specific process creation flag so child processes run hidden:
use std::process::Command;
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
#[cfg(target_os = "windows")]
const CREATE_NO_WINDOW: u32 = 0x08000000;
fn build_hidden_cmd(program: &str) -> Command {
let mut cmd = Command::new(program);
#[cfg(target_os = "windows")]
{
cmd.creation_flags(CREATE_NO_WINDOW);
}
cmd
}
From there, all Git calls use build_hidden_cmd("git") instead of Command::new("git").
3. Tauri v2 capabilities, window transparency, and the invisible app trap
I wanted a transparent, glassy popup. That means:
"transparent": true- Start hidden to avoid a white flash while React loads:
"visible": false - Show the window once the UI is ready (
window.show())
The catch is that Tauri v2 locks down frontend APIs by default. Without the right capability permissions, the window did not crash, it just stayed invisible while the process happily ran in the background.
The fix is to explicitly allow the window operations your frontend performs in capabilities/default.json:
{
"permissions": [
"core:window:default",
"core:window:allow-show",
"core:window:allow-close",
"process:allow-exit"
]
}
This is one of those “security first” defaults that is correct, but it will absolutely prank you the first time you try to do anything window-related.
The sparkle button: AI commit generation (locally, by default)
Writing commit messages is small, but it adds friction. GitPop’s ✨ Sparkle button reduces that friction:
- Stage files
- GitPop runs
git diff --cached - The staged diff is sent to an LLM to propose a commit message
Privacy matters. Shipping proprietary diffs to a cloud API is a non-starter for a lot of dev work. So GitPop defaults to Ollama, running locally. It detects installed models (for example llama3.2 or qwen2.5-coder) and generates commit messages without API keys, paid tokens, or network calls.
GitPop also supports OpenAI, Anthropic, Gemini, and custom endpoints for people who prefer hosted models. The model selection is an implementation detail. The UX goal is consistent: stage, sparkle, commit, done.
Try it out
If you are on Windows (Soon OSx) and this fits your workflow, grab the latest installer from the repository:
Feedback, issues, and PRs are welcome. I am also exploring what it would take to bring the same “right-click commit UI” to macOS Finder, where the integration constraints are different but the pain is identical.
Happy committing.

Top comments (0)