A CLI tool for AI-assisted merge conflict resolution, designed for maintaining long-running forks that regularly sync with upstream repositories.
mergai automates the merge workflow by:
- Prioritizing which upstream commits to merge next based on configurable strategies (conflicts, large commits, important files)
- Capturing conflict context (diffs, conflict markers, commit history) and passing it to an AI agent
- Storing all merge metadata and AI solutions as git notes, allowing them to travel with commits
- Managing branches and PRs for both clean merges and conflict resolution workflows
Currently, the tool uses Gemini CLI as the AI agent.
This is under active development; use with caution.
- Python 3.10+ and git installed.
- Gemini CLI available on your
PATH(used as the default agent). Setup authentication on your own. - Optional:
GITHUB_TOKENorGH_TOKENfor commands that read/write PRs. - Run
mergai configto configure git settings (conflictstyle, notes display). - Run
mergai fork initto initialize the upstream remote from config.
python -m venv .venv
source .venv/bin/activate
pip install -e .Verify with mergai --help.
mergai is configured via .mergai/config.yml in your repository root.
Additionally, .mergai/invariants.md is appended to AI prompts when present. Use it to provide project-specific instructions or constraints for the AI agent.
| Section | Description |
|---|---|
fork |
Upstream repository settings and merge-pick prioritization strategies |
resolve |
AI agent type and retry attempts |
branch |
Branch naming format with token substitution |
commit |
Commit message footer |
pr |
PR title formats and labels for main/solution PRs |
prompt |
Commit fields included in AI prompts |
finalize |
Post-merge finalization mode (squash/keep/fast-forward) |
merge |
Merge command behavior (auto-describe after merge) |
config |
Git settings (conflictstyle, notes display) |
fork:
upstream_url: https://github.com/upstream-org/upstream-repo.git
upstream_branch: main
upstream_remote: upstream
merge_picks:
most_recent_fallback: true
# Strategies evaluated in order; first match determines priority
strategies:
- conflict: true
- huge_commit: "(num_of_files >= 100 or num_of_lines >= 5000 or num_of_dirs > 10)"
- branching_point: true
- important_files:
- src/core/critical_module.cpp
- src/api/public_api.h
resolve:
agent: gemini-cli:gemini-2.5-pro
max_attempts: 3
branch:
name_format: "mergai/%(target_branch)-%(target_branch_short_sha)-%(merge_commit_short_sha)/%(type)"
commit:
footer: "Note: commit created by mergai"
pr:
main:
title_format: "Merge '%(merge_commit_short_sha)' into '%(target_branch)'"
labels:
- "ci-skip-format"
solution:
title_format: "Resolve conflicts for merge '%(merge_commit_short_sha)' into '%(target_branch)'"
labels:
- "ci-skip-format"
prompt:
# Valid values: hexsha, short_sha, author, authored_date, summary, message, parents
commit_fields:
- hexsha
finalize:
# Available modes: squash, keep, fast-forward
mode: fast-forward
merge:
# When to auto-run 'describe' after merge: never, always, success, conflict
describe: never
config:
git:
conflictstyle: diff3
notes:
display: true
marker_text: "mergai note available, use `mergai show <commit>` to view it."The fork.merge_picks.strategies list defines how mergai fork merge-pick prioritizes unmerged commits. Strategies are evaluated in order; the first matching strategy determines a commit's priority.
| Strategy | Description |
|---|---|
conflict: true |
Prioritizes the first commit that would cause merge conflicts |
huge_commit: "<expr>" |
Prioritizes commits matching a size expression. Variables: num_of_files, num_of_lines, lines_added, lines_deleted, num_of_dirs |
branching_point: true |
Prioritizes commits that are branching points in upstream (have multiple children) |
important_files: [...] |
Prioritizes commits that modify any of the listed file paths |
Set most_recent_fallback: true to select the most recent unmerged commit when no strategy matches.
The branch.name_format setting controls how mergai names branches. Available tokens:
| Token | Description | Required |
|---|---|---|
%(target_branch) |
Target branch name | yes |
%(target_branch_sha) |
Full SHA of target branch (40 chars) | one of these |
%(target_branch_short_sha) |
Short SHA of target branch (11 chars) | one of these |
%(merge_commit_sha) |
Full SHA of merge commit (40 chars) | one of these |
%(merge_commit_short_sha) |
Short SHA of merge commit (11 chars) | one of these |
%(type) |
Branch type: main, conflict, or solution |
no |
The format must contain %(target_branch), at least one of the target branch SHA tokens, and at least one of the merge commit SHA tokens.
Example: mergai/%(target_branch)-%(target_branch_short_sha)-%(merge_commit_short_sha)/%(type) produces mergai/release-8.0-abc12345678-def98765432/solution.
The merge section controls behavior of the mergai merge command.
| Setting | Values | Description |
|---|---|---|
describe |
never (default), always, success, conflict |
When to auto-run the describe command after merge |
The describe command uses an AI agent to analyze the merge and generate a summary description stored as merge_description in the note. This description is included in PR bodies when available.
| Value | Behavior |
|---|---|
never |
Don't run describe (default) |
always |
Run describe after every merge, regardless of outcome |
success |
Run describe only when merge succeeds (no conflicts) |
conflict |
Run describe only when merge results in conflicts |
Note: The describe command is only run when --no-context is NOT specified, since describe creates a field in the context.
mergai stores context and solutions as git notes attached to commits. This allows metadata to travel with commits without modifying commit history.
Note references:
refs/notes/mergai- main note storage containing context, solutions, and merge inforefs/notes/mergai-marker- lightweight markers for quick identification ingit log
Note contents and when they are created:
| Field | Description | Created by |
|---|---|---|
merge_info |
Merge metadata (target branch, merge commit SHA, target branch SHA) | mergai context init |
merge_context |
Auto-merged files info, merge strategy | mergai merge (on success or conflict) |
conflict_context |
Conflicting files with diffs and conflict markers | mergai merge (on conflict only) |
merge_description |
AI-generated merge summary and review notes | mergai describe, mergai merge (if configured) |
solutions |
AI or human resolutions with file changes | mergai resolve, mergai commit sync |
Commands:
mergai notes update- Fetch and merge notes from remotemergai notes push- Push notes to remotemergai show <commit>- View note contentsmergai context drop- Remove note pieces
Notes are automatically attached when using mergai commit subcommands. Use mergai context init to rebuild local state from existing notes.
| Command | Description |
|---|---|
mergai config |
Configure git settings (conflictstyle, notes display) |
mergai fork merge-pick |
Get prioritized commits from upstream based on configured strategies |
mergai fork fetch |
Fetch upstream repository |
mergai context init |
Initialize merge context with commit SHA and target branch |
mergai notes update |
Fetch and merge notes from remote |
mergai notes push |
Push mergai notes to remote |
mergai merge |
Attempt merge of the context commit |
mergai describe |
Generate AI merge description (auto-runs based on merge.describe config) |
mergai resolve |
Run AI conflict resolution (-y for yolo mode) |
mergai commit |
Commit with note attached (subcommands: merge, conflict, solution, sync) |
mergai branch create |
Create working branch (types: main, conflict, solution) |
mergai branch push |
Push branch to origin |
mergai finalize |
Finalize merge after solution PR is merged |
mergai pr create |
Create pull request |
mergai pr update |
Update PR body with current note data |
mergai log |
List commits with mergai notes |
mergai show |
Show stored context/solution for a commit |
mergai status |
Show current state |
mergai prompt |
Show the prompt that would be sent to the agent |
mergai context drop |
Remove note pieces (--solution, --context, --all) |
mergai fork merge-pick --next # Get next prioritized commit from upstream
mergai context init <commit> # Initialize merge context with commit SHA
mergai notes update # Fetch and merge notes from remote
mergai merge # Attempt merge (succeeds if no conflicts)
mergai commit merge # Create merge commit with note attached
mergai branch create main # Create main working branch
mergai branch push main # Push main branch to origin
mergai notes push # Push mergai notes to remote
mergai pr --repo <repo> create main # Open PR for the mergemergai fork merge-pick --next # Get next prioritized commit from upstream
mergai context init <commit> # Initialize merge context with commit SHA
mergai notes update # Fetch and merge notes from remote
mergai merge # Attempt merge (exits 1 on conflicts)
mergai commit conflict # Commit conflict state with markers
mergai branch create conflict # Create branch with conflict markers
mergai branch create solution # Create branch for AI solution
mergai resolve -y # Run AI conflict resolution (yolo mode)
mergai commit solution # Commit resolved files with note
mergai branch push solution # Push solution branch
mergai branch push conflict # Push conflict branch
mergai notes push # Push mergai notes to remote
mergai pr --repo <repo> create solution # Open PR for the solutionAfter the solution PR is merged into the conflict branch:
mergai notes update # Fetch and merge notes from remote
mergai context init # Rebuild context from commit notes
mergai branch create main # Create main working branch
mergai commit sync # Sync manual commits to notes
mergai finalize # Finalize into final merge commit
mergai branch push main # Push main branch to origin
mergai notes push # Push mergai notes to remote
mergai pr --repo <repo> create main # Open PR for the finalized mergemergai log # List commits that carry mergai notes
mergai show <commit> # Print stored context and solution
mergai show <commit> --context # Show only the conflict context
mergai show <commit> --solution # Show only the solution
mergai show <commit> --raw # Show raw note datamergai prompt # Show the prompt that would be sent to the agent
mergai resolve # Run AI resolution (add -y for yolo mode)
mergai commit solution # Commit AI solution and attach note
mergai status # Inspect current stategit add <files> # Stage manually resolved files
git commit -m "Fix remaining conflicts" # Create regular git commit
mergai commit sync # Sync human commits to notes
mergai pr --repo <repo> update solution # Update PR body with new solutionsInstall the package with development dependencies:
pip install -e ".[dev]"Set up pre-commit hooks to automatically check formatting before commits:
pre-commit installThe project uses several tools to maintain code quality:
| Tool | Purpose | Config |
|---|---|---|
| Black | Code formatter (line length 88, Python 3.10+) | pyproject.toml |
| Ruff | Fast linter (pycodestyle, Pyflakes, isort, flake8-bugbear, flake8-comprehensions, pyupgrade, flake8-simplify) | pyproject.toml |
| mypy | Static type checking | pyproject.toml |
| deptry | Unused/missing dependency detection | pyproject.toml |
| pip-audit | Dependency vulnerability scanning | - |
# Format code with Black
black src/
# Check formatting without modifying files
black --check --diff src/
# Run Ruff linter
ruff check src/
# Auto-fix linting issues where possible
ruff check --fix src/
# Run type checker
mypy src/mergai --ignore-missing-imports
# Check for unused/missing dependencies
deptry src/
# Scan dependencies for security vulnerabilities
pip-audit --skip-editableThe project uses pre-commit with Black configured to check formatting before each commit. The configuration is in .pre-commit-config.yaml.
To run pre-commit manually on all files:
pre-commit run --all-filesGitHub Actions workflows run automatically on push and pull requests:
| Workflow | Checks | Schedule |
|---|---|---|
| Format Check | Black formatting | push, PR |
| Lint | Ruff linter, mypy type checking | push, PR |
| Dependency Check | deptry unused dependencies | push, PR |
| Security Scan | pip-audit vulnerabilities, CodeQL analysis | push to main/master, PR, weekly |