๐ 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. โจ
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
rizzler
as an input to yourflake.nix
and include it in yourenvironment.systemPackages
orhome.packages
.
- Declarative (Profile): Install directly into your user profile:
-
Download from GitHub Releases:
- Go to the latest releases page.
- Find the archive (
.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'sPATH
(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.
Okay, so how does rizzler
actually get triggered by Git? It's not actual magic, just some clever Git config.
-
Git Config (
.gitconfig
): Therizzler setup
command 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 therizzler
command with these file paths (%O
,%A
,%B
,%P
are placeholders Git fills in). -
Git Attributes (
.gitattributes
): How does Git know when to use therizzler
driver? That's where.gitattributes
comes in (either in your repo or globally). Thesetup
command 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 therizzler
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 therizzler
command specified in your.gitconfig
.rizzler
does its AI thing, hopefully fixes the file, and then exits. -
Exit Code Matters:
rizzler
tells Git if it succeeded by its exit code.0
means "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
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 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
rizzler
blindly on your main production branches (main
,master
,trunk
, whatever your vibe is). It's giving... risky. ๐ฌ Instead, userizzler
for the lower-stakes game: resolving conflicts when rebasing your feature branch from the main branch. Get your local branch up-to-date, letrizzler
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. โจ
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 config
or therizzler config
command. Can be local or global. .rizzler
file: ATOML
file 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_KEY
RIZZLER_CLAUDE_API_KEY
RIZZLER_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 openai
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, theHEAD
/--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
.md
files usesimple
),rizzler
tries 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-only
if theai
strategy 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_STRATEGY
environment 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
) .rizzler
file: Add mappings under the[resolution.extension_strategies]
table in your repo's.rizzler
TOML 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_ORDER
environment 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..."
.rizzler
file: Setsystem_prompt
under[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
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
rizzler
later 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-cache
in your system's temp directory (like/tmp/rizzler-cache
). You can change this spot by setting theRIZZLER_CACHE_DIR
environment variable to your preferred path. - How it Works:
rizzler
hashes the conflict details (or file path + content) to make a key, then saves the AI's answer as a.json
file 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
: Letrizzler
automatically 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.css
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.
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. โจ