Skip to content

Dxsk/repos-manager

Repository files navigation

repos-manager

Tests Lint GitHub Release License: MIT Buy Me A Coffee

A single CLI tool to clone and sync all your Git repositories, no matter the provider.

Supported providers

Provider CLI Status
GitHub gh Done
GitLab glab Done
Forgejo / Gitea tea Done
Bitbucket bitbucket or API Done
Radicle rad Done

Features

  • Clone all accessible repos (personal, orgs, groups, subgroups)
  • Mirror the remote namespace hierarchy locally: provider/owner/repo
  • Update existing repos with fetch + fast-forward pull
  • Skip repos with uncommitted local changes
  • Remove local repos that no longer exist on the remote (--prune)
  • Preview changes before applying them (--dry-run)
  • SSH and HTTPS support
  • Filter by owner or specific repo (--filter)
  • Exclude repos via .repos-ignore
  • Filter repos via .repos-filter
  • Parallel sync (default: 4 jobs, configurable with --parallel)
  • Lockfile to prevent concurrent syncs on the same base directory
  • Verbose (--verbose) and quiet (--quiet) output modes
  • Status overview: dirty, ahead, behind, diverged repos
  • Fast status scan with live progress indicator, automatic skip of cloud drives and other network mounts
  • Background update check with a one-line banner when a newer release is available
  • Universal login: authenticate all detected providers at once
  • Config file (~/.config/repos-manager/config.json) for defaults
  • Auto-generated sourceme files per host directory
  • Shell completions for bash, zsh and fish
  • Per-provider help (repos-manager github --help)
  • NO_COLOR support

Directory structure

After syncing, your workspace looks like this:

~/Documents/
  .repos-filter
  .repos-ignore
  github.com/
    dxsk/
      my-project/
    my-org/
      other-project/
  gitlab.com/
    my-user/
      project/
    my-group/
      sub-group/
        project/

Installation

Arch / CachyOS

git clone git@github.com:Dxsk/repos-manager.git
cd repos-manager
make install

This installs to ~/.local/bin/repos-manager. To change the prefix:

make install PREFIX=/usr/local

Run lint and tests:

make check   # lint + tests
make lint    # shellcheck + zsh/fish syntax
make test    # bats tests

Manual (any distro)

Source the file matching your shell:

# bash
source sourceme.bash

# zsh
source sourceme.zsh

# fish
source sourceme.fish

You can add the source line to your shell config to make it persistent.

Nix

nix run github:Dxsk/repos-manager -- github sync

Or use as a flake template:

mkdir ~/my-repos && cd ~/my-repos
nix flake init -t github:Dxsk/repos-manager
nix develop

Usage

Configuration

Generate a default config file:

repos-manager init
# Creates ~/.config/repos-manager/config.json
{
  "base_dir": "~/Documents",
  "parallel": 4,
  "protocol": "ssh",
  "check_updates": true,
  "scan_network_mounts": false,
  "hosts": {
    "github":    ["github.com"],
    "gitlab":    ["gitlab.com"],
    "forgejo":   ["codeberg.org"],
    "bitbucket": ["bitbucket.org"]
  }
}

Two behaviours are controlled from the config file:

  • check_updates (default true): on every run except update, version and help, a detached background curl fetches the latest VERSION from main and caches it for 24 hours in ~/.cache/repos-manager/latest-version. The next run compares the cache against the running binary and prints a yellow banner when a newer release is available. Set REPOS_MANAGER_NO_UPDATE_CHECK=1 for a one-shot opt-out.
  • scan_network_mounts (default false): repos-manager status reads /proc/self/mountinfo and prunes every mount point under base_dir whose filesystem type is fuse, fuse.*, nfs, cifs, smb*, smbfs, afs, ceph or davfs. This keeps the scan fast on setups that host cloud drives (kDrive, Dropbox, sshfs) under ~/Documents. Flip it to true if you really do host repos on a reliable network share. The scan will print a warning that it can hang on flaky links.

Each hosts.<provider> key takes a list of hostnames, so you can sync several instances of the same provider (typically a SaaS one plus your self-hosted one):

{
  "hosts": {
    "gitlab":  ["gitlab.com", "gitlab.example.org"],
    "forgejo": ["codeberg.org", "forge.example.org"]
  }
}

repos-manager clones each instance under its own directory (<base_dir>/<host>/...). For self-hosted instances you must have a matching CLI login: glab auth login --hostname <host> for GitLab, tea login add for Forgejo. The legacy single-string form ("gitlab": "gitlab.com") is still accepted.

Authentication

# Login all detected providers at once
repos-manager login

# Or login a specific provider
repos-manager github login
repos-manager gitlab login
repos-manager forgejo login
repos-manager bitbucket login
repos-manager radicle login

Syncing repos

# Sync all repos from GitHub
repos-manager github sync

# Sync all repos from GitLab
repos-manager gitlab sync

# Sync all configured providers at once
repos-manager sync --all

# Parallel sync with 8 jobs
repos-manager sync --all --parallel 8

Status

Check which repos have uncommitted changes, are ahead/behind, or diverged:

repos-manager status

Filtering

# Sync only repos from a specific owner
repos-manager github sync --filter Dxsk/*

# Sync a single repo
repos-manager github sync --filter Dxsk/repos-manager

Other options

# Use HTTPS instead of SSH
repos-manager github sync --https

# Remove local repos that no longer exist on the remote
repos-manager sync --all --prune

# Preview what would happen without making changes
repos-manager sync --all --dry-run

# GitLab self-hosted
repos-manager gitlab sync --host gitlab.self-hosted.com

# Forgejo / Gitea
repos-manager forgejo sync --host forgejo.self-hosted.com

# Custom base directory
repos-manager sync --all --base-dir /path/to/repos

Flags

Flag Description
--filter <pattern> Filter repos by pattern (e.g. Dxsk/* or Dxsk/project)
--base-dir <path> Base directory for repos (default: ~/Documents)
--https Use HTTPS clone URLs instead of SSH
--prune Remove local repos not found on the remote
--dry-run Show what would be done without making any changes
--host <host> Custom host for self-hosted instances
--parallel <n> Number of parallel sync jobs (default: 4)
--verbose, -v Show debug output
--quiet, -q Suppress info/success messages (errors still shown)

Auto-generated sourceme files

After syncing, repos-manager generates sourceme, sourceme.zsh, and sourceme.fish files in each host directory (e.g. ~/Documents/github.com/). These files provide the repos-manager function when you cd into the directory.

If you use the sourceme auto-loader, the function is loaded/unloaded automatically as you navigate.

Filter and ignore files

.repos-filter

Sync only repos matching at least one pattern. If the file is empty or missing, all repos are synced.

# Only sync repos from Dxsk
Dxsk/*

# Plus a specific repo from another org
other-org/some-project

.repos-ignore

Exclude repos from syncing. Applied after .repos-filter.

# Ignore a specific repo
Dxsk/old-project

# Ignore all repos from an owner
test-org/*

Pattern syntax

  • Glob wildcards: *, ?
  • owner/* also matches nested paths (e.g. group/subgroup/project)
  • Lines starting with # are comments
  • Empty lines are ignored

Environment variables

Variable Description Default
REPOS_MANAGER_BASE_DIR Base directory for all repos ~/Documents
REPOS_MANAGER_LIB Path to lib modules Auto-detected
REPOS_MANAGER_PARALLEL Default parallel jobs 4
REPOS_MANAGER_PROTOCOL Default protocol (ssh or https) ssh
REPOS_MANAGER_NO_UPDATE_CHECK Set to 1 to skip the background update check Unset
REPOS_MANAGER_UPDATE_TTL Seconds between update checks 86400
REPOS_MANAGER_UPDATE_CACHE Path to the cached latest-version file ${XDG_CACHE_HOME:-~/.cache}/repos-manager/latest-version
TEA_CONFIG Path to tea's config file, read by the Forgejo provider ~/.config/tea/config.yml
NO_COLOR Disable colored output when set Unset

Requirements

  • bash ≥ 4.0. macOS ships bash 3.2 by default: install a newer one with brew install bash and make sure it's first in your PATH. Older versions miss mapfile, associative arrays and other features the scripts rely on.
  • git
  • jq
  • gh for GitHub
  • glab for GitLab
  • tea for Forgejo / Gitea authentication, plus curl and yq (listing talks to the Forgejo API directly, see docs/providers)
  • bitbucket for Bitbucket (optional, can use API fallback)
  • rad for Radicle

Glossary

Providers

Provider Description CLI Documentation
GitHub The most popular Git hosting platform gh GitHub CLI Manual
GitLab DevOps platform with built-in CI/CD glab GLab Documentation
Forgejo Community-driven self-hosted Git forge (Gitea fork) tea Forgejo Documentation
Gitea Lightweight self-hosted Git service tea Gitea Documentation
Bitbucket Atlassian's Git platform (Cloud & Server) bitbucket Bitbucket API
Radicle Sovereign peer-to-peer code forge built on Git rad Radicle User Guide

Tools

Tool Description Documentation
Git Distributed version control system Git Reference
jq Lightweight CLI JSON processor jq Manual
GNU Stow Symlink farm manager (used for dotfiles) Stow Manual

Support

If this tool saves you time, you can support my work by buying me a coffee. Thank you!

License

MIT