Skip to content

Repository files navigation

git-manager

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 sync

Why

Managing 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 admin to 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.

What It Manages

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

Quick Start

# 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 sync

That's it. Your GitHub org now matches your YAML.

Configuration

Config lives in .git-manager/ (customizable via --config-dir). Three files define your org:

org.yml -- Organization & Auth

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: 78901234

users.yml -- User Registry

users:
  - github_username: alice
    display_name: "Alice Smith"
    email: alice@company.com
    tags: [engineering, backend]

  - github_username: bob
    display_name: "Bob Jones"
    tags: [engineering, frontend]

repos.yml -- Repositories, Permissions, Settings & Protection

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: false

Authentication

Personal Access Token (default)

Create a token with repo and admin:org scopes:

export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx

SSO-protected orgs: Authorize the token at https://github.com/orgs/<ORG>/sso after creating it.

GitHub App (recommended for automation)

More secure than PATs -- scoped to the org, no personal account needed:

uv sync --extra github-app   # from the repo root

Then configure app_id, private_key_path, and installation_id in org.yml.

Commands

plan -- Preview changes (dry-run)

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 view

Shows colored diff output by default -- green for additions, red for removals, yellow for updates. Exit code 0 = no changes, 2 = changes pending.

sync -- Apply changes to GitHub

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 plan

audit -- Detect drift

git-manager audit                   # Colored diff
git-manager audit --format json     # For compliance reporting

Exit code 0 = no drift, 2 = drift detected. Perfect for CI gates.

validate -- Offline config check

git-manager validate               # No GitHub token needed

Validates YAML syntax, Pydantic schemas, and cross-references (e.g., every user in repos.yml exists in users.yml).

backup -- Snapshot org state

git-manager backup                            # Full backup
git-manager backup --output-dir ./snapshots   # Custom path
git-manager backup --include-archived         # Include archived repos

Exports users, repos, and collaborator permissions as timestamped YAML to backups/<org>-<YYYYMMDD-HHMMSS>/.

import -- Bootstrap from existing org

git-manager import --org my-github-org
git-manager import --org my-github-org --include-archived

users / repos -- Manage config locally

# 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 list

Multi-Organization Support

Managing 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-org

Then 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 orgs

Real-World Workflows

Onboard a new hire

git-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 sync

Offboard in one command

git-manager users remove olddev   # Removes from ALL repos
git-manager sync

CI/CD drift detection

# .github/workflows/access-audit.yml
- run: uv sync
- run: uv run git-manager audit --format json
  # Fails with exit code 2 if drift detected

Disaster recovery

git-manager backup   # Run nightly via cron
# Restore: copy backup YAML into .git-manager/ and sync

How It Works

YAML config  -->  Desired state  --\
                                    |--> Diff --> Plan --> Apply
GitHub API   -->  Actual state   --/
  1. Load -- Reads and validates YAML with Pydantic
  2. Desired state -- Your config defines the target
  3. Actual state -- Queries GitHub API for current permissions, settings, and branch protection
  4. Diff -- Computes add/update/remove actions
  5. Apply -- Executes changes with confirmation

Key behaviors:

  • Opt-in: Only repos in repos.yml are managed. Everything else is untouched.
  • Idempotent: Running sync twice 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 Levels

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)

Repository Settings

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

Branch Protection Rules

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

Installation

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-app

For development (includes test and lint tooling):

uv sync --extra dev

Contributing

See CONTRIBUTING.md for development setup, testing, and code style guidelines.

License

Apache 2.0 -- see LICENSE.

About

CLI tool to manage GitHub Organization access control via YAML configuration - like Terraform, but for repo permissions.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages