Skip to content

Git coupling

git_coupling

Git change coupling — files that historically co-change.

Analyzes git log to find files that change together, revealing hidden dependencies invisible to static analysis.

The coupling formula follows Axon's approach::

coupling(A, B) = co_changes(A, B) / max(changes(A), changes(B))
Example

from axm_ast.core.git_coupling import git_coupled_files git_coupled_files("src/core.py", Path("/project"), months=6) [{"file": "src/utils.py", "strength": 0.75, "co_changes": 6}]

git_coupled_files(file_path, project_root, *, months=6, min_strength=0.3, min_co_changes=3)

Find files that historically co-change with the target file.

Analyzes git log over months of history to compute change coupling strength for each file that co-occurs with file_path in commits.

Parameters:

Name Type Description Default
file_path str | Path

Relative path to the target file within the repo.

required
project_root Path

Root of the git repository.

required
months int

Number of months of history to analyze.

6
min_strength float

Minimum coupling strength (0.0-1.0).

0.3
min_co_changes int

Minimum number of co-changes required.

3

Returns:

Type Description
list[dict[str, Any]]

List of dicts with file, strength, co_changes,

list[dict[str, Any]]

sorted by strength descending. Returns empty list if not

list[dict[str, Any]]

in a git repo or on error.

Example

result = git_coupled_files("src/core.py", Path(".")) result[0]["file"] 'src/utils.py'

Source code in packages/axm-ast/src/axm_ast/core/git_coupling.py
def git_coupled_files(
    file_path: str | Path,
    project_root: Path,
    *,
    months: int = 6,
    min_strength: float = 0.3,
    min_co_changes: int = 3,
) -> list[dict[str, Any]]:
    """Find files that historically co-change with the target file.

    Analyzes ``git log`` over ``months`` of history to compute
    change coupling strength for each file that co-occurs with
    *file_path* in commits.

    Args:
        file_path: Relative path to the target file within the repo.
        project_root: Root of the git repository.
        months: Number of months of history to analyze.
        min_strength: Minimum coupling strength (0.0-1.0).
        min_co_changes: Minimum number of co-changes required.

    Returns:
        List of dicts with ``file``, ``strength``, ``co_changes``,
        sorted by strength descending.  Returns empty list if not
        in a git repo or on error.

    Example:
        >>> result = git_coupled_files("src/core.py", Path("."))
        >>> result[0]["file"]
        'src/utils.py'
    """
    commits = _parse_git_log(project_root, months)
    if not commits:
        return []

    return _compute_coupling_scores(
        str(file_path),
        commits,
        min_strength=min_strength,
        min_co_changes=min_co_changes,
    )