rizzler: stop crying over Git merge conflicts and let AI handle the drama
โจ rizzler: stop crying over Git merge conflicts and let AI handle the drama โจ 
๐ Ugh, merge conflicts. That sinking feeling when Git screams at you? We've all been there. Manually fixing those tangled messes? It's giving... tedious. It's giving... waste of my precious time. ๐ฉ

๐ Enter rizzler: Your new AI bestie that actually gets Git. This ain't your grandpa's merge tool. rizzler slides into your Git workflow and uses โจ AI magic โจ (think OpenAI, Claude, Gemini, Bedrock - the whole squad) to automatically resolve those annoying merge conflicts. Less time untangling, more time coding (or scrolling). You're welcome. ๐
Basically, it turns this:
<<<<<<< HEAD
const message = "Hello from main branch!";
=======
const message = "Waddup from feature branch!";
>>>>>>> feature-branch
Into actual, usable code, letting you get back to the important stuff. โจ
๐ Get Rizzin': Installation
Ready to ditch the conflict drama? Let's get you set up. Choose your install method:
- Build from Source:
cargo build --release
# The binary will be in target/release/rizzler
* Make sure this binary is somewhere in your system's PATH.
- Install with Nix (Recommended):
nix profile install github:ghuntley/rizzler
* Temporary (Run): Try it out without installing permanently:
nix run github:ghuntley/rizzler -- --help # Or any other rizzler command
* NixOS/Home Manager: Add rizzler as an input to your flake.nix and include it in your environment.systemPackages or home.packages.
- Download from GitHub Releases:
.tar.gz or .zip) for your operating system (Linux, macOS, Windows) and architecture (e.g., x86_64, aarch64).
* Download and extract the archive.
* Copy the rizzler binary to a directory in your system's PATH (e.g., /usr/local/bin or ~/.local/bin).
- Hook it up with Git (for automatic resolution): After installing
rizzler, tell Git to use it automatically during merges/pulls for specific file types. You can do this for just one project (--local) or for all your projects (--global).
# Example: Configure for the current repo only
rizzler setup --local --extensions js ts py rs go java
# Example: Configure globally for your user rizzler setup --global --extensions js ts py rs go java md json yaml
This command tweaks your .gitconfig and sets up a .gitattributes file. This step is for enabling automatic conflict resolution.
๐ How it Hooks Up with Git (The Nerdy Deets)
Okay, so how does rizzler actually get triggered by Git? It's not actual magic, just some clever Git config.
- Git Config (
.gitconfig): Therizzler setupcommand adds a custom merge driver definition to your Git configuration. It looks something like this:
[merge "rizzler"]
name = rizzler
driver = rizzler %O %A %B %P
trustExitCode = true
This tells Git: "Hey, there's a merge tool called rizzler. When you need it, run the rizzler command with these file paths (%O, %A, %B, %P are placeholders Git fills in).
- Git Attributes (
.gitattributes): How does Git know when to use therizzlerdriver? That's where.gitattributescomes in (either in your repo or globally). Thesetupcommand adds lines like this:
*.js merge=rizzler
*.py merge=rizzler
# etc...
This tells Git: "For any file ending in .js (or .py, etc.), if there's a merge conflict, use the rizzler merge driver we defined earlier."
- The Hand-off: When you run
git merge(or pull, rebase, etc.) and Git hits a conflict in a file matching one of the patterns in.gitattributes, it automatically runs therizzlercommand specified in your.gitconfig.rizzlerdoes its AI thing, hopefully fixes the file, and then exits.
- Exit Code Matters:
rizzlertells Git if it succeeded by its exit code.0means "All good, conflicts resolved!" and Git continues. Any other number means "Nah, couldn't fix it, you handle it," and Git leaves the conflict markers for you.
rizzler becomes your automated merge conflict wingman.
๐จ Heads Up: Safety & The Real Tea ๐จ
Okay, fam, let's keep it ๐ฏ. rizzler is cool, but AI ain't magic (yet!).
No Cap, It's Not Actually Reading Code: Neither rizzler nor the big brain AIs (GPT, Claude, etc.) truly* understand your code like a compiler or interpreter does. They don't get the deep logic, the Abstract Syntax Tree (AST), or the semantic meaning. They're basically super-powered pattern matchers, guessing based on tons of text they've seen. Sometimes this guess is fire, sometimes it's... not. ๐ฅ vs ๐๏ธ
The Ghost of goto fail;: Remember that time Apple had a massive* security flaw in their SSL/TLS code back in 2014? It was literally because of a duplicated goto fail; line. Like this (oversimplified):
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail; if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; // <--- ๐ THIS EXTRA LINE SKIPPED THE VERIFICATION!!! if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; // ... crucial signature verification code ... fail: // ... error handling ... A tiny, almost invisible change (maybe even something an auto-formatter might do weirdly, or an AI might hallucinate in a merge) completely broke critical security checks. This is the kind of subtle-but-deadly bug that purely text-based merging (like what AI does now) can accidentally introduce because it doesn't understand the consequences of the code structure.
Recommendation Station: Because of this, we strongly advise NOT running rizzler blindly on your main production branches (main, master, trunk, whatever your vibe is). It's giving... risky. ๐ฌ Instead, use rizzler for the lower-stakes game: resolving conflicts when rebasing your feature branch from the main branch. Get your local branch up-to-date, let rizzler handle the rebase conflicts, review the changes carefully, and then* merge your clean feature branch.
The Glow-Up Goal: We want* rizzler to be smarter! The dream is proper semantic merging โ understanding the code structure (AST) to make safer merges. AI could then be a fallback or assistant for the really tricky bits. Wanna help build this? Check out CONTRIBUTING.md! We'd love the help. โจ
โ๏ธ Dial in the Settings: Configuration
rizzler is pretty chill out of the box, but you can customize its vibe. Configs are layered, kinda like your fave fit:
- Environment Variables (Highest Priority): Set these in your shell. They override everything else.
- Git Config: Use
git configor therizzler configcommand. Can be local or global. -
.rizzlerfile: ATOMLfile in your project root for repo-specific settings (lower priority than env/git config). - Defaults: Sensible defaults if nothing else is set.
-
RIZZLERPROVIDERDEFAULT: Which AI fam to use? (openai,anthropic,gemini,bedrock). -
RIZZLER_MODEL: Specific model name (e.g.,gpt-4-turbo,claude-3-opus-20240229,gemini-pro). -
RIZZLER_TIMEOUT: How long to wait for the AI (seconds, default: 30). -
RIZZLERSYSTEMPROMPT: Give the AI custom instructions (optional). -
RIZZLERLOGLEVEL: How chatty should the logs be? (error,warn,info,debug,trace). Default:info. -
RIZZLERLOGFILE: Path to write logs to (optional). - API Keys (Mandatory for most providers):
RIZZLEROPENAIAPI_KEY
* RIZZLERCLAUDEAPI_KEY
* RIZZLERGEMINIAPI_KEY
* (For Bedrock, it uses standard AWS credential chain)
Using rizzler config:
# See current settings
rizzler config list
Get a specific setting
rizzler config get aiprovider.defaultmodel
Set a setting (locally by default)
rizzler config set aiprovider.defaultmodel gpt-4-turbo
Set a setting globally
rizzler config set --global aiprovider.defaultprovider openai
๐ค AI & Strategies: The Brains of the Operation
So how does rizzler actually decide how to fix conflicts? And which AI overlord does it consult? Let's dive in.
Resolution Strategies:
rizzler can use different methods (strategies) to resolve conflicts. Think of them as different playbooks for tackling a merge mess.
-
ai(Default & The Brainiac): This is the main event. It sends the conflicting code snippets (plus maybe some surrounding context) to the configured Large Language Model (LLM) like GPT-4, Claude, etc. The AI analyzes the changes and attempts to generate a semantically correct merged version. This is best for complex logical conflicts.
whitespace-only (The Neat Freak): This is a simple, fast, rule-based strategy. If the only* difference between the conflicting parts is whitespace (spaces, tabs, line endings), this strategy resolves the conflict by just picking one side (specifically, the HEAD/--ours version) and ignoring the whitespace changes. It's great for avoiding AI calls on purely stylistic/formatting differences.
(Other potential strategies like fallback, simple, ai-windowing, etc., might exist depending on the specific build/configuration, often related to different ways of interacting with the AI or handling specific conflict types.)*
How Strategies are Chosen:
- File Extension First: If you've configured a specific strategy for a file extension (e.g., make
.mdfiles usesimple),rizzlertries that first.fallback - Default Strategy: If no extension-specific rule applies, it uses the default strategy (usually
ai). - Engine Fallback: If the chosen strategy fails or can't handle the conflict, the engine might try other available strategies (like
whitespace-onlyif theaistrategy was chosen but the conflict was just whitespace).
You can control which strategy gets used:
- Default Strategy: Set globally or per-repo using
rizzler config set resolution.defaultstrategy <strategyname>or theRIZZLERDEFAULTSTRATEGYenvironment variable. - Per-Extension Strategies: Map specific file extensions to strategies for fine-grained control:
RIZZLEREXTENSIONSTRATEGY<ext>=<strategyname> (e.g., RIZZLEREXTENSIONSTRATEGY_MD=whitespace-only)
* Git Config: git config rizzler.extensionstrategy.<ext> <strategyname> (e.g., git config rizzler.extension_strategy.md whitespace-only)
* .rizzler file: Add mappings under the [resolution.extension_strategies] table in your repo's .rizzler TOML file.
AI Providers: Choose Your Fighter
rizzler isn't locked into one AI. You've got options! Choose your fave provider via RIZZLERPROVIDERDEFAULT or the aiprovider.defaultprovider config key.
- OpenAI: (
openai)
RIZZLEROPENAIAPI_KEY.
* Supports models like gpt-4, gpt-4-turbo, gpt-3.5-turbo.
* Can use custom base URLs (RIZZLEROPENAIBASE_URL) for Azure, local models, etc.
- Anthropic (Claude): (
anthropic)
RIZZLERCLAUDEAPI_KEY.
* Supports models like claude-3-opus-20240229, claude-3-sonnet-20240229.
- Google (Gemini): (
gemini)
RIZZLERGEMINIAPI_KEY.
* Supports models like gemini-pro.
- AWS Bedrock: (
bedrock)
Don't forget to set the specific model you want with RIZZLERMODEL or aiprovider.default_model!
Bonus: The ai-fallback Strategy ๐ก๏ธ
What if your chosen AI is down or being flaky? rizzler has your back with the ai-fallback strategy. If you set your strategy to ai-fallback (e.g., rizzler config set resolution.default_strategy ai-fallback), it will try multiple AI providers in sequence until one successfully resolves the conflict.
- How it works: It attempts resolution with the first provider in its list. If that fails (API error, timeout, etc.), it automatically tries the next one, and so on.
- Default Order:
openai,claude,gemini,bedrock - Custom Order: You can change the sequence and which providers are included using the
RIZZLERFALLBACKORDERenvironment variable. Separate provider names (lowercase) with commas.
# Example: Try Claude first, then OpenAI if Claude fails
export RIZZLERFALLBACKORDER="claude,openai"
- Availability: Only providers that are configured correctly (e.g., have API keys set) will be included in the fallback chain.
rizzler more resilient โ if one service is having a moment, it can just pivot to the next one.
Customizing the AI Prompt:
Wanna give the AI some specific instructions or context? You can override the default system prompt.
- Env Var:
RIZZLERSYSTEMPROMPT="Your custom instructions here..." - Git Config:
rizzler config set aiprovider.systemprompt "Your custom instructions here..." -
.rizzlerfile: Setsystempromptunder[aiprovider].
๐พ Cache = Less $$$, More Speed ๐
Aight, listen up! rizzler is smart with your API keys and your time. It uses a disk cache to remember the answers it gets from the AI. Think of it like your phone remembering Wi-Fi passwords, but for merge conflicts.
Why You Should Care:
Saves $$: If rizzler sees the exact same conflict* it already solved, it grabs the answer from the cache instead of pinging the AI again. Cha-ching! ๐ธ Saves API costs. Speeds Things Up: Cache hits are way* faster than waiting for the AI. Gets you back to coding quicker. โก
- It Remembers!: Since it's on disk, the cache sticks around even after you close your terminal. If you run
rizzlerlater and hit the same conflict, it'll remember the fix. Persistent W.
- Where it Lives: By default, cache files get stashed in a folder called
rizzler-cachein your system's temp directory (like/tmp/rizzler-cache). You can change this spot by setting theRIZZLERCACHEDIRenvironment variable to your preferred path. - How it Works:
rizzlerhashes the conflict details (or file path + content) to make a key, then saves the AI's answer as a.jsonfile using that key. - Expiration: Cache files have a "best before" date (TTL). After the TTL (default: 24 hours), they get automatically deleted to keep things fresh. Old cache = irrelevant cache.
- Max Capacity: It won't hoard files forever. There's a limit (default: 1000 files per type). If it hits the cap, the oldest files get yeeted.
-
RIZZLERUSECACHE: Turn it on (true, default) or off (false). -
RIZZLERCACHEDIR: Pick where the cache files live. -
RIZZLERCACHETTL_HOURS: Set the expiry time in hours (default:24). -
RIZZLERCACHEMAX_ENTRIES: Cap the number of saved files (default:1000). -
RIZZLERCACHEAUTO_CLEANUP: Letrizzlerautomatically clean up old files (true, default) or not (false).
rizzler work smarter, not harder. โจ
๐ฎ How to Play
Automatic Mode (The Chill Way):
Mostly, you just... don't. After running rizzler setup with your desired extensions, rizzler automatically jumps in when Git finds a merge conflict in a configured file type during git merge, git pull, etc. It does its AI thing, fixes the file, and lets Git continue. Easy peasy.
Manual Mode (On-Demand Rizz):
Forgot to add an extension during setup? Or just wanna run rizzler on a specific file right now? No prob!
You can use rizzler manually on any file with Git conflict markers (<<<<<, =====, >>>>>), regardless of whether its extension was included in the setup command.
# This works even if .css wasn't in your 'setup --extensions'
rizzler resolve path/to/your/conflicted_file.css
๐ ๏ธ Commands Lowdown
-
rizzler setup: Configures Git integration (automatic mode). -
rizzler config: View or change settings. -
rizzler resolve <file>: Manually resolve a specific file. -
rizzler doctor: Checks if everything is set up correctly. -
rizzler version: Shows the version.
๐ License
This project is licensed under the MIT License. See the LICENSE file for details. Basically, do what you want, just give credit and don't sue us. ๐ค
๐ Contributing
Wanna help make rizzler even more based? Sick! Contributions are welcome.
- Bugs: Found a glitch? Report it in the Issues section.
- Features: Got a killer idea? Open an issue to discuss it first.
- Code: Wanna submit a Pull Request? Go for it! Make sure your code vibes with the project style and includes tests.
Stop letting merge conflicts ruin your day. Let rizzler handle the drama. โจ