๐ 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-branchInto actual, usable code, letting you get back to the important stuff. โจ
Ready to ditch the conflict drama? Let's get you set up. Choose your install method:
-
Build from Source:
- Since this is a Rust project, you'll need the Rust toolchain installed.
- Clone this repo and run:
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):
- Declarative (Profile): Install directly into your user profile:
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
rizzleras an input to yourflake.nixand include it in yourenvironment.systemPackagesorhome.packages.
- Declarative (Profile): Install directly into your user profile:
-
Download from GitHub Releases:
- Go to the latest releases page.
- Find the archive (
.tar.gzor.zip) for your operating system (Linux, macOS, Windows) and architecture (e.g.,x86_64,aarch64). - Download and extract the archive.
- Copy the
rizzlerbinary to a directory in your system'sPATH(e.g.,/usr/local/binor~/.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
.gitconfigand sets up a.gitattributesfile. This step is for enabling automatic conflict resolution.
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 therizzlercommand with these file paths (%O,%A,%B,%Pare 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 therizzlermerge 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.
So yeah, that's the behind-the-scenes tea on how rizzler becomes your automated merge conflict wingman.
Okay, fam, let's keep it ๐ฏ. rizzler is cool, but AI ain't magic (yet!).
-
No Cap, It's Not Actually Reading Code: Neither
rizzlernor 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 duplicatedgoto 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
rizzlerblindly on your main production branches (main,master,trunk, whatever your vibe is). It's giving... risky. ๐ฌ Instead, userizzlerfor the lower-stakes game: resolving conflicts when rebasing your feature branch from the main branch. Get your local branch up-to-date, letrizzlerhandle the rebase conflicts, review the changes carefully, and then merge your clean feature branch. -
The Glow-Up Goal: We want
rizzlerto 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. โจ
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.
Key Environment Variables:
RIZZLER_PROVIDER_DEFAULT: 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).RIZZLER_SYSTEM_PROMPT: Give the AI custom instructions (optional).RIZZLER_LOG_LEVEL: How chatty should the logs be? (error,warn,info,debug,trace). Default:info.RIZZLER_LOG_FILE: Path to write logs to (optional).- API Keys (Mandatory for most providers):
RIZZLER_OPENAI_API_KEYRIZZLER_CLAUDE_API_KEYRIZZLER_GEMINI_API_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 ai_provider.default_model
# Set a setting (locally by default)
rizzler config set ai_provider.default_model gpt-4-turbo
# Set a setting globally
rizzler config set --global ai_provider.default_provider openaiSo 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, theHEAD/--oursversion) 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).
Setting Strategies:
You can control which strategy gets used:
- Default Strategy: Set globally or per-repo using
rizzler config set resolution.default_strategy <strategy_name>or theRIZZLER_DEFAULT_STRATEGYenvironment variable. - Per-Extension Strategies: Map specific file extensions to strategies for fine-grained control:
- Env Var:
RIZZLER_EXTENSION_STRATEGY_<ext>=<strategy_name>(e.g.,RIZZLER_EXTENSION_STRATEGY_MD=whitespace-only) - Git Config:
git config rizzler.extension_strategy.<ext> <strategy_name>(e.g.,git config rizzler.extension_strategy.md whitespace-only) .rizzlerfile: Add mappings under the[resolution.extension_strategies]table in your repo's.rizzlerTOML file.
- Env Var:
AI Providers: Choose Your Fighter
rizzler isn't locked into one AI. You've got options! Choose your fave provider via RIZZLER_PROVIDER_DEFAULT or the ai_provider.default_provider config key.
- OpenAI: (
openai)- Requires
RIZZLER_OPENAI_API_KEY. - Supports models like
gpt-4,gpt-4-turbo,gpt-3.5-turbo. - Can use custom base URLs (
RIZZLER_OPENAI_BASE_URL) for Azure, local models, etc.
- Requires
- Anthropic (Claude): (
anthropic)- Requires
RIZZLER_CLAUDE_API_KEY. - Supports models like
claude-3-opus-20240229,claude-3-sonnet-20240229.
- Requires
- Google (Gemini): (
gemini)- Requires
RIZZLER_GEMINI_API_KEY. - Supports models like
gemini-pro.
- Requires
- AWS Bedrock: (
bedrock)- Uses your standard AWS credentials chain (env vars, config files, IAM roles).
- Needs your AWS region configured.
- Supports various models available on Bedrock (including Claude).
Don't forget to set the specific model you want with RIZZLER_MODEL or ai_provider.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
RIZZLER_FALLBACK_ORDERenvironment variable. Separate provider names (lowercase) with commas.# Example: Try Claude first, then OpenAI if Claude fails export RIZZLER_FALLBACK_ORDER="claude,openai"
- Availability: Only providers that are configured correctly (e.g., have API keys set) will be included in the fallback chain.
This makes 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:
RIZZLER_SYSTEM_PROMPT="Your custom instructions here..." - Git Config:
rizzler config set ai_provider.system_prompt "Your custom instructions here..." .rizzlerfile: Setsystem_promptunder[ai_provider].
This lets you fine-tune how the AI approaches the merge resolution.
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
rizzlersees 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.
The Lowdown:
- 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 theRIZZLER_CACHE_DIRenvironment 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.
Tune the Cache Vibe (Env Vars):
RIZZLER_USE_CACHE: Turn it on (true, default) or off (false).RIZZLER_CACHE_DIR: Pick where the cache files live.RIZZLER_CACHE_TTL_HOURS: Set the expiry time in hours (default:24).RIZZLER_CACHE_MAX_ENTRIES: Cap the number of saved files (default:1000).RIZZLER_CACHE_AUTO_CLEANUP: Letrizzlerautomatically clean up old files (true, default) or not (false).
Basically, the disk cache helps rizzler work smarter, not harder. โจ
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.cssrizzler 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.
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. ๐ค
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.
Check out the CONTRIBUTING.md (if it exists) for more detailed guidelines.
Stop letting merge conflicts ruin your day. Let rizzler handle the drama. โจ
