Skip to main content
Glama
MementoRC

MCP Git Server

by MementoRC

git_diff

Compare differences between branches or commits in a Git repository using the 'git_diff' tool on the MCP Git Server. Simplify version control by analyzing changes with precision.

Instructions

Shows differences between branches or commits

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
repo_pathYes
targetYes

Implementation Reference

  • The core handler function implementing the git_diff tool logic. Executes git diff using dulwich Repo.git.diff with support for commit ranges (commit_range), two-commit comparison (base_commit/target_commit), target branch/commit, paths filtering, stat-only, name-only modes, parameter validation to prevent conflicts, size limiting with truncation warnings, and comprehensive error handling.
    def git_diff(
        repo: Repo,
        target: str | None = None,
        stat_only: bool = False,
        max_lines: int | None = None,
        name_only: bool = False,
        commit_range: str | None = None,
        base_commit: str | None = None,
        target_commit: str | None = None,
        paths: list[str] | None = None,
    ) -> str:
        """Get diff with advanced options including commit ranges and file filtering.
    
        Parameter Precedence (mutually exclusive - only one method should be used):
        1. commit_range: Use git range syntax like "HEAD~1..HEAD" or "main..develop"
        2. base_commit + target_commit: Compare two specific commits/branches
        3. target: Compare working tree against specific branch/commit (default behavior)
        4. None: Compare working tree against HEAD (fallback)
    
        Args:
            repo: Git repository object
            target: Branch/commit to diff against (conflicts with commit_range or base_commit/target_commit)
            stat_only: Show only file change statistics, not content
            max_lines: Limit output to specified number of lines (overridden by name_only/stat_only)
            name_only: Show only names of changed files
            commit_range: Git range syntax like "HEAD~1..HEAD" (conflicts with other diff methods)
            base_commit: Starting commit for comparison (requires target_commit)
            target_commit: Ending commit for comparison (requires base_commit)
            paths: Filter diff to specific files/directories
    
        Returns:
            Formatted diff output with validation warnings if applicable
    
        Raises:
            Returns error message if parameters are conflicting or invalid
        """
        # Validate parameters for conflicts and security
        is_valid, validation_msg = _validate_diff_parameters(
            target=target,
            commit_range=commit_range,
            base_commit=base_commit,
            target_commit=target_commit,
        )
        if not is_valid:
            return f"❌ Parameter validation failed: {validation_msg}"
    
        # If there's a warning, include it in the output
        validation_warning = validation_msg if validation_msg and is_valid else None
        try:
            # Build git diff arguments
            diff_args = []
    
            # Determine what we're diffing
            diff_description = ""
    
            if commit_range:
                # Use commit range syntax like "HEAD~1..HEAD"
                diff_args.append(commit_range)
                diff_description = f"commit range {commit_range}"
            elif base_commit and target_commit:
                # Compare two specific commits
                diff_args.extend([base_commit, target_commit])
                diff_description = f"{base_commit}...{target_commit}"
            elif target:
                # Compare against target branch/commit (original behavior)
                diff_args.append(target)
                diff_description = f"against {target}"
            else:
                # Default to comparing working tree against HEAD
                diff_args.append("HEAD")
                diff_description = "against HEAD"
    
            # Add options based on parameters
            if name_only:
                diff_args.append("--name-only")
            elif stat_only:
                diff_args.append("--stat")
    
            # Add specific paths if provided
            if paths:
                diff_args.extend(["--"] + paths)
    
            # Execute git diff with arguments
            diff_output = repo.git.diff(*diff_args)
    
            # Handle name-only output
            if name_only:
                result = (
                    f"Changed files {diff_description}:\n{diff_output}"
                    if diff_output.strip()
                    else f"No changes {diff_description}"
                )
                if validation_warning:
                    result = f"⚠️ {validation_warning}\n\n{result}"
                return result
    
            # Handle stat-only output
            if stat_only:
                result = (
                    f"Diff {diff_description} summary:\n{diff_output}"
                    if diff_output.strip()
                    else f"No differences {diff_description}"
                )
                if validation_warning:
                    result = f"⚠️ {validation_warning}\n\n{result}"
                return result
    
            # Apply size limiting for full diff output
            result = _apply_diff_size_limiting(
                diff_output, f"diff {diff_description}", stat_only, max_lines
            )
            if validation_warning:
                result = f"⚠️ {validation_warning}\n\n{result}"
            return result
    
        except GitCommandError as e:
            return f"❌ Diff failed: {str(e)}"
        except Exception as e:
            return f"❌ Diff error: {str(e)}"
  • Pydantic input schema/model for the git_diff tool, defining all parameters including repo_path, target, stat_only, max_lines, name_only, commit_range, base_commit, target_commit, and paths.
    class GitDiff(BaseModel):
        repo_path: str
        target: str | None = None  # Made optional for commit range scenarios
        stat_only: bool | None = False
        max_lines: int | None = None
        name_only: bool | None = False
        commit_range: str | None = None
        base_commit: str | None = None
        target_commit: str | None = None
        paths: list[str] | None = None
  • Tool registration in the central ToolRegistry. Defines the MCP Tool with name 'git_diff', description, inputSchema from GitDiff model, and metadata. The actual handler is set later via GitToolRouter.
    ToolDefinition(
        name=GitTools.DIFF,
        category=ToolCategory.GIT,
        description="Show differences between branches or commits",
        schema=GitDiff,
        handler=placeholder_handler,
        requires_repo=True,
  • Handler registration and wrapper creation in CallToolHandler._get_git_handlers(). Imports git_diff from git.operations and creates a wrapped handler with GitPython Repo integration, error handling decorators, and argument mapping.
    "git_diff": self._create_git_handler(
        git_diff,
        requires_repo=True,
        extra_args=["target", "stat_only", "max_lines", "name_only", "paths"],
    ),
  • Tool name definition in GitTools enum for consistent referencing across the codebase.
    DIFF = "git_diff"
    COMMIT = "git_commit"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MementoRC/mcp-git'

If you have feedback or need assistance with the MCP directory API, please join our Discord server