GitHub access control, declared in YAML, applied in seconds.
Stop clicking through GitHub's UI to manage repository permissions. Define your entire organization's access control as code -- users, repos, permissions, settings, branch protection -- and let git-manager reconcile it against GitHub. Think Terraform, but purpose-built for GitHub permissions.
git clone https://github.com/carlos-barreto/git-manager.git
cd git-manager
uv syncManaging GitHub access at scale is painful:
- Manual UI clicks don't scale. Onboarding someone to 15 repos means 15 trips to GitHub settings.
- No audit trail. Who granted
adminto that contractor? When? Nobody knows. - Drift is invisible. Someone changes a permission in the UI and your security posture silently degrades.
- Offboarding is error-prone. Miss one repo and a former employee still has write access.
git-manager solves this with a desired-state model: you declare what access should look like, and the tool makes it so. Your YAML config becomes the single source of truth -- reviewable, version-controlled, and auditable.
| Capability | Description |
|---|---|
| User permissions | Grant, update, or revoke collaborator access across repositories |
| Repository settings | Visibility, merge strategies, feature toggles (issues, wiki, projects) |
| Branch protection | Required reviews, status checks, enforce admins, linear history |
| Multi-org support | Manage multiple GitHub organizations from a single config |
| Backup & snapshots | Export full org state as timestamped YAML for disaster recovery |
# Initialize config for your org
git-manager init --org my-github-org
# Import current GitHub state as your baseline
git-manager init --org my-github-org --import
# Preview what would change
git-manager plan
# Apply changes
git-manager syncThat's it. Your GitHub org now matches your YAML.
Config lives in .git-manager/ (customizable via --config-dir). Three files define your org:
organization: my-github-org
default_permission: read
github:
base_url: null # Set for GitHub Enterprise Server
token_env_var: GITHUB_TOKEN
# Or use GitHub App authentication (more secure, no personal tokens):
# app_id: 123456
# private_key_path: /path/to/app.private-key.pem
# installation_id: 78901234users:
- github_username: alice
display_name: "Alice Smith"
email: alice@company.com
tags: [engineering, backend]
- github_username: bob
display_name: "Bob Jones"
tags: [engineering, frontend]repositories:
- name: api-service
description: "Core API microservice"
collaborators:
alice: write
bob: read
settings:
visibility: private
allow_squash_merge: true
allow_merge_commit: false
delete_branch_on_merge: true
branch_protection:
main:
required_approving_review_count: 2
dismiss_stale_reviews: true
require_code_owner_reviews: true
required_status_checks: [ci/tests, ci/lint]
enforce_admins: false
- name: frontend-app
description: "React frontend"
collaborators:
bob: write
alice: read
settings:
visibility: private
has_wiki: false
has_projects: falseCreate a token with repo and admin:org scopes:
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxSSO-protected orgs: Authorize the token at
https://github.com/orgs/<ORG>/ssoafter creating it.
More secure than PATs -- scoped to the org, no personal account needed:
uv sync --extra github-app # from the repo rootThen configure app_id, private_key_path, and installation_id in org.yml.
git-manager plan # Full diff
git-manager plan --repo api-service # Single repo
git-manager plan --user alice # Single user
git-manager plan --format json # Machine-readable
git-manager plan --format table # Classic table viewShows colored diff output by default -- green for additions, red for removals, yellow for updates. Exit code 0 = no changes, 2 = changes pending.
git-manager sync # Interactive (confirm first)
git-manager sync --yes # Auto-approve (for CI)
git-manager sync --repo api-service # Single repo
git-manager sync --dry-run # Same as plangit-manager audit # Colored diff
git-manager audit --format json # For compliance reportingExit code 0 = no drift, 2 = drift detected. Perfect for CI gates.
git-manager validate # No GitHub token neededValidates YAML syntax, Pydantic schemas, and cross-references (e.g., every user in repos.yml exists in users.yml).
git-manager backup # Full backup
git-manager backup --output-dir ./snapshots # Custom path
git-manager backup --include-archived # Include archived reposExports users, repos, and collaborator permissions as timestamped YAML to backups/<org>-<YYYYMMDD-HHMMSS>/.
git-manager import --org my-github-org
git-manager import --org my-github-org --include-archived# Users
git-manager users add alice --name "Alice Smith" --tag engineering
git-manager users remove alice
git-manager users list --tag engineering
# Repos
git-manager repos add api-service --description "Core API"
git-manager repos grant api-service alice write
git-manager repos revoke api-service alice
git-manager repos listManaging multiple orgs? Add an orgs.yml in your working directory:
organizations:
- name: my-main-org
config_dir: .git-manager/main-org
- name: my-sandbox-org
config_dir: .git-manager/sandbox-orgThen target one or all orgs:
git-manager plan # All orgs
git-manager plan --org my-main-org # Single org
git-manager sync --org my-main-org
git-manager backup # Backup all orgsgit-manager users add newdev --name "New Developer" --tag engineering
git-manager repos grant api-service newdev write
git-manager repos grant frontend-app newdev write
git-manager repos grant docs newdev read
git-manager syncgit-manager users remove olddev # Removes from ALL repos
git-manager sync# .github/workflows/access-audit.yml
- run: uv sync
- run: uv run git-manager audit --format json
# Fails with exit code 2 if drift detectedgit-manager backup # Run nightly via cron
# Restore: copy backup YAML into .git-manager/ and syncYAML config --> Desired state --\
|--> Diff --> Plan --> Apply
GitHub API --> Actual state --/
- Load -- Reads and validates YAML with Pydantic
- Desired state -- Your config defines the target
- Actual state -- Queries GitHub API for current permissions, settings, and branch protection
- Diff -- Computes add/update/remove actions
- Apply -- Executes changes with confirmation
Key behaviors:
- Opt-in: Only repos in
repos.ymlare managed. Everything else is untouched. - Idempotent: Running
synctwice produces zero changes. - Admin-safe: Admin permission changes are blocked in the CLI to prevent privilege escalation.
- Resilient: Automatic retry with exponential backoff on GitHub rate limits (403/429).
- Partial failure: If some API calls fail, execution continues and reports a summary.
| Permission | Description |
|---|---|
read |
Clone, pull |
triage |
Read + manage issues and PRs |
write |
Push commits, merge PRs |
maintain |
Write + manage repo settings |
admin |
Full control (protected -- managed via GitHub UI only) |
Declarable fields in repos.yml under settings::
| Setting | Type | Description |
|---|---|---|
visibility |
public / private / internal |
Repository visibility |
default_branch |
string | Default branch name |
allow_squash_merge |
bool | Allow squash merging |
allow_merge_commit |
bool | Allow merge commits |
allow_rebase_merge |
bool | Allow rebase merging |
delete_branch_on_merge |
bool | Auto-delete head branches |
has_issues |
bool | Enable issues |
has_wiki |
bool | Enable wiki |
has_projects |
bool | Enable projects |
Declarable fields under branch_protection.<branch>::
| Setting | Type | Description |
|---|---|---|
required_approving_review_count |
int | Minimum review approvals |
dismiss_stale_reviews |
bool | Dismiss approvals on new pushes |
require_code_owner_reviews |
bool | Require CODEOWNERS approval |
required_status_checks |
list | Required CI checks to pass |
strict_status_checks |
bool | Require branch to be up to date |
enforce_admins |
bool | Apply rules to admins too |
require_linear_history |
bool | No merge commits |
allow_force_pushes |
bool | Allow force pushes |
allow_deletions |
bool | Allow branch deletion |
Requires Python 3.11+.
git clone https://github.com/carlos-barreto/git-manager.git
cd git-manager
uv sync
# With GitHub App support
uv sync --extra github-appFor development (includes test and lint tooling):
uv sync --extra devSee CONTRIBUTING.md for development setup, testing, and code style guidelines.
Apache 2.0 -- see LICENSE.