The Git Integration module provides the GitManager component, which encapsulates all git repository operations required by the CodeWiki CLI's documentation workflow. It is responsible for validating that a target directory is a git repository, inspecting working-directory cleanliness, creating dedicated documentation branches, committing generated documentation, and deriving useful metadata such as remote URLs, branch names, commit hashes, and GitHub pull-request links.
This module is a child of the CLI Core module and is used primarily by the CLI's generation workflow (see Generation) to safely manage version control state before, during, and after documentation is generated.
When the CLI is run with branch-creation options (e.g. --create-branch), it must:
- Confirm the target path is inside a valid git repository.
- Ensure there are no uncommitted changes that could be silently mixed into a documentation commit (unless the user explicitly forces the operation).
- Create a uniquely named, timestamped branch dedicated to documentation output.
- Stage and commit the generated documentation files.
- Surface repository metadata (current branch, commit hash, remote URL) back to the CLI so it can print helpful summaries.
- Build a ready-to-open GitHub pull-request URL if the remote is hosted on GitHub.
All of this logic is centralized in the GitManager class, keeping git operations isolated from the rest of the CLI so that other components (progress reporting, configuration, documentation generation) do not need to know about the underlying git library (GitPython).
GitManager (CodeWiki.codewiki.cli.git_manager::GitManager) wraps a git.Repo instance (from the GitPython library) and exposes a small, purpose-built API surface consumed by the CLI layer.
On construction, GitManager resolves the given repo_path to an absolute path and attempts to open it as a git repository using git.Repo(repo_path, search_parent_directories=True). The search_parent_directories=True flag allows the manager to locate a .git directory even if repo_path points to a subdirectory of the repository (similar to how the native git command walks upward from the current directory).
If no valid repository is found, a RepositoryError is raised with actionable guidance (e.g., suggesting git init). RepositoryError is a CLI-specific exception type that carries a dedicated exit code (EXIT_REPOSITORY_ERROR), allowing the CLI's top-level error handler to report failures consistently and set correct process exit statuses.
check_clean_working_directory() inspects the repository for uncommitted modifications or untracked files using repo.is_dirty(untracked_files=True). When dirty, it builds a human-readable summary listing up to three modified and three untracked files (with a "... and N more" suffix for longer lists), returning a (is_clean, status_message) tuple. This check underpins the safety guarantee that documentation generation will not accidentally commit unrelated in-progress changes.
create_documentation_branch(force: bool = False) creates and checks out a new branch named docs/codewiki-<timestamp> (format %Y%m%d-%H%M%S). Before creating the branch it re-runs the cleanliness check unless force=True, raising a detailed RepositoryError with copy-pastable remediation commands (git status, git add -A && git commit, git stash) if the working directory is dirty.
To guard against timestamp collisions, it checks existing branch names and appends an incrementing numeric suffix (-1, -2, ...) if a collision would otherwise occur. Branch creation and checkout are performed via repo.create_head(...) followed by .checkout(); any underlying GitCommandError is translated into a RepositoryError.
commit_documentation(docs_path: Path, message: Optional[str] = None) stages the documentation output directory via repo.index.add([str(docs_path)]) and commits it with either a caller-supplied message or the default "Add generated documentation\n\nGenerated by CodeWiki CLI". It returns the resulting commit's hexsha. Failures during add/commit are wrapped in RepositoryError.
get_remote_url(remote_name="origin")— returns the URL of the named remote, orNoneif it does not exist.get_current_branch()— returns the active branch name, or the literal string"HEAD"when in a detached-HEAD state (caught viaTypeErrorfromGitPython).get_commit_hash()— returns the currentHEADcommit's hex SHA.branch_exists(branch_name)— returns whether a branch with the given name already exists locally.
get_github_pr_url(branch_name) derives a ready-to-use GitHub "compare" URL (<repo>/compare/<branch>) from the origin remote, but only when that remote points to github.com. It normalizes the remote URL by:
- Stripping a trailing slash and any
.gitsuffix. - Converting SSH-style remotes (
git@github.com:org/repo) into HTTPS form (https://github.com/org/repo).
If there is no remote or it is not a GitHub remote, it returns None, allowing the CLI to gracefully skip printing a PR link for non-GitHub repositories.
All git-related failures surface as RepositoryError (defined outside this module in the CLI's shared error utilities), rather than leaking raw GitCommandError or InvalidGitRepositoryError exceptions from GitPython. This gives the CLI a single, well-known exception type to catch at the top level and translate into a clean error message and a dedicated process exit code, keeping git-library implementation details out of user-facing error handling.
classDiagram
class GitManager {
+Path repo_path
+Repo repo
+__init__(repo_path)
+check_clean_working_directory() Tuple
+create_documentation_branch(force) str
+commit_documentation(docs_path, message) str
+get_remote_url(remote_name) str
+get_current_branch() str
+get_commit_hash() str
+branch_exists(branch_name) bool
+get_github_pr_url(branch_name) str
}
class RepositoryError {
+__init__(message)
}
GitManager ..> RepositoryError : raises
GitManager is typically instantiated by the CLI's generation flow when branch-based documentation workflows are requested. The sequence below illustrates a typical end-to-end interaction: verifying repository state, creating a branch, running documentation generation (handled by CLIDocumentationGenerator in the Generation module), committing the results, and reporting a PR link.
sequenceDiagram
participant CLI as "CLI Entry Point"
participant GM as "GitManager"
participant DocGen as "CLIDocumentationGenerator"
participant Repo as "git.Repo"
CLI->>GM: "GitManager(repo_path)"
GM->>Repo: "git.Repo(repo_path)"
CLI->>GM: "check_clean_working_directory()"
GM-->>CLI: "(is_clean, status_message)"
alt "Working directory dirty and not forced"
GM-->>CLI: "raise RepositoryError"
else "Clean or forced"
CLI->>GM: "create_documentation_branch(force)"
GM->>Repo: "create_head(branch_name)"
GM->>Repo: "checkout()"
GM-->>CLI: "branch_name"
CLI->>DocGen: "generate()"
DocGen-->>CLI: "DocumentationJob"
CLI->>GM: "commit_documentation(docs_path, message)"
GM->>Repo: "index.add([docs_path])"
GM->>Repo: "index.commit(message)"
GM-->>CLI: "commit_hash"
CLI->>GM: "get_github_pr_url(branch_name)"
GM-->>CLI: "pr_url or None"
end
flowchart TD
Start["create_documentation_branch(force)"] --> CheckForce{{force?}}
CheckForce -->|"false"| CheckClean["check_clean_working_directory()"]
CheckForce -->|"true"| GenName["Generate timestamped branch name"]
CheckClean --> IsClean{{"is_clean?"}}
IsClean -->|"false"| RaiseErr["raise RepositoryError with remediation steps"]
IsClean -->|"true"| GenName
GenName --> CheckExists{{"branch name exists?"}}
CheckExists -->|"true"| AppendCounter["Append incrementing counter suffix"]
AppendCounter --> CheckExists
CheckExists -->|"false"| CreateBranch["repo.create_head(branch_name)"]
CreateBranch --> Checkout["new_branch.checkout()"]
Checkout --> ReturnName["return branch_name"]
- CLI Core — the parent module;
GitManageris one of the core services orchestrated alongside configuration management, job models, and progress tracking to deliver the fullcodewiki generateexperience. - Generation —
CLIDocumentationGeneratorperforms the actual documentation generation (dependency analysis, clustering, LLM-driven writing, optional HTML output). The CLI entry point coordinatesGitManagerandCLIDocumentationGeneratortogether: creating a branch before generation, and committing the resulting files afterward. - Job Models — while
GitManageritself does not depend onDocumentationJob, the surrounding CLI workflow often records git-derived metadata (branch name, commit hash) alongside job statistics for reporting purposes.
GitManager depends on the third-party GitPython library (imported as git) for all low-level repository interactions, including git.Repo, git.InvalidGitRepositoryError, and git.exc.GitCommandError. It also depends on the CLI's shared RepositoryError exception type for consistent error reporting across the CLI.