A modern Rust Git merge tool
  • Rust 95.9%
  • Shell 4.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jeroen f3c1c1891c chore(claude): add a commit-push skill
Encodes the Conventional Commits format, the no-attribution-trailer rule,
path-scoped commits, and the Forgejo remote, so those conventions do not
have to be restated each time.
2026-07-28 17:56:22 +02:00
.cargo chore(build): link with lld to cut rebuild time 2026-07-28 17:55:49 +02:00
.claude/skills/commit-push chore(claude): add a commit-push skill 2026-07-28 17:56:22 +02:00
docs docs: move guides into docs/ and rewrite the README 2026-07-28 17:56:16 +02:00
scripts chore(scripts): add a demo repo generator for manual testing 2026-07-28 17:56:22 +02:00
src feat(merge): resolve conflicts per region in an editable result pane 2026-07-28 17:56:08 +02:00
.gitignore Initial commit: helld - Modern git merge tool in Rust 2026-07-28 16:33:36 +02:00
Cargo.toml feat(merge): resolve conflicts per region in an editable result pane 2026-07-28 17:56:08 +02:00
README.md docs: move guides into docs/ and rewrite the README 2026-07-28 17:56:16 +02:00

helld

A GUI merge tool for resolving git conflicts. Three panels, keyboard driven, written in Rust with iced.

helld shows the two conflicting versions of a file side by side with their common ancestor in the middle. You pick a side per file, it writes the result and stages it. It does not commit.

Requirements

  • Rust 1.75 or newer (rustup toolchain install stable)
  • A GPU driver with Vulkan, or set WGPU_BACKEND=gl to fall back to OpenGL
  • Linux, macOS or Windows

The first build compiles iced and wgpu and takes a few minutes. Later builds take about a second.

Setup

git clone <repository-url> helld
cd helld
cargo build --release

Optionally install it onto your PATH:

cargo install --path .

Then configure git to record the common ancestor in conflicted files:

git config --global merge.conflictStyle zdiff3

This is worth doing. Without it git never writes the ancestor text, so the BASE panel stays empty and the B key refuses. See docs/DEVELOPMENT.md for why zdiff3 beats diff3.

Try it

The repository ships a script that builds a throwaway repo with real conflicts, so you can learn the tool without risking your own work:

./scripts/demo-repo.sh          # creates /tmp/helld-demo
cargo run -- /tmp/helld-demo

It creates two conflicting files: config.rs, where the branches disagree on a field name, and utils.rs, a one-line conflict for testing navigation between files.

Run the script again at any time to reset the demo to its starting state.

Usage

helld                 # use the repository containing the current directory
helld /path/to/repo   # or any path inside a working tree

helld opens on the first conflicted file. Parent directories are searched for a .git, so any path inside a checkout works.

Layout

+----------------+----------------+----------------+
|      OURS      |     RESULT     |     THEIRS     |
|   your branch  |   (editable)   |  merged branch |
+----------------+----------------+----------------+
                  press Tab to show
                  BASE here instead

The middle pane is the file you are building. It starts as the conflicted file git left behind, markers and all. L/R/B write a side into it, you can type into it directly, and Ctrl+S writes it exactly as shown.

BASE (the common ancestor) shares the middle slot and is one Tab away.

The interface is a subtle monochromatic dark teal, with syntax highlighting per language picked from the file extension.

Conflict state lives in the gutter bar on the left of each line, so it never competes with the syntax colours. It is a luminance ramp in the same hue:

Gutter Meaning
bright the region you are currently deciding
mid another region, still undecided
dim a region you have already decided, so it recedes

Keys

Each conflict region is handled independently, so one file can take OURS for one region and THEIRS for another:

Key Action
L / R / B Write OURS / THEIRS / BASE into the current region
Shift+L / Shift+R / Shift+B Write that side into every remaining region
Ctrl+S Save, once no conflict markers remain

Nothing reaches disk until Ctrl+S, and a result that still contains conflict markers is refused rather than staged as if it were resolved.

Editing:

Key Action
Click Start editing the result pane
Esc Leave the editor

While the editor has focus it takes every keystroke, so L, N and the rest type characters instead of acting. Esc hands the keyboard back.

Moving around:

Key Action
N / P Next / previous conflict region, crossing into the next file at the ends
] / [ Next / previous file
Tab Swap the middle pane between RESULT and BASE
1 / 2 / 3 Focus OURS / BASE / THEIRS
Up / Down Scroll the focused panel
PgUp / PgDn Page scroll
Home / End Jump to start / end

N and P scroll the OURS and THEIRS panels to the region so they stay lined up.

Other:

Key Action
? or Esc Toggle help
Ctrl+A Abort the merge, press twice to confirm
Q Quit immediately, without confirmation

Ctrl+A hard resets your working tree, which is why it asks twice.

Finishing a merge

helld stages each resolved file but never commits. When the last conflict is resolved, commit yourself:

git commit

Limitations

  • Editing the conflict markers by hand can desync L/R/B from the regions they target. helld detects this and says so; finish that file by hand.
  • The result pane does not scroll to follow N / P.
  • Binary and unreadable files are skipped.
  • Syntax highlighting is chosen from the file extension. Extensionless files such as Makefile render as plain text.

Development

See docs/DEVELOPMENT.md for the module layout, the key data structures, and the build setup, which is tuned for fast rebuilds.

cargo check    # fastest feedback, about 0.3s
cargo build    # about 0.8s after a one-line edit
cargo test
cargo clippy

License

MIT. Note that no LICENSE file has been added to the repository yet.