{"id":34582309,"url":"https://github.com/epilande/repos","last_synced_at":"2026-04-14T04:01:32.885Z","repository":{"id":330262999,"uuid":"1122146340","full_name":"epilande/repos","owner":"epilande","description":"📦 Interactive CLI tool for managing multiple git repositories","archived":false,"fork":false,"pushed_at":"2026-04-13T05:22:29.000Z","size":209,"stargazers_count":33,"open_issues_count":2,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-13T07:20:09.220Z","etag":null,"topics":["cli","command-line","devtools","ink","productivity","tui"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/epilande.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"epilande","buy_me_a_coffee":"epilande"}},"created_at":"2025-12-24T07:14:48.000Z","updated_at":"2026-04-12T07:33:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/epilande/repos","commit_stats":null,"previous_names":["epilande/repos"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/epilande/repos","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epilande%2Frepos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epilande%2Frepos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epilande%2Frepos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epilande%2Frepos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/epilande","download_url":"https://codeload.github.com/epilande/repos/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epilande%2Frepos/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31781292,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T02:24:21.117Z","status":"ssl_error","status_checked_at":"2026-04-14T02:24:20.627Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line","devtools","ink","productivity","tui"],"created_at":"2025-12-24T10:18:42.662Z","updated_at":"2026-04-14T04:01:32.880Z","avatar_url":"https://github.com/epilande.png","language":"TypeScript","funding_links":["https://github.com/sponsors/epilande","https://buymeacoffee.com/epilande"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003eRepos 📦\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eAn interactive CLI tool for managing multiple git repositories.\u003c/strong\u003e\n\u003c/p\u003e\n\n![demo](https://github.com/user-attachments/assets/00fdfece-06bc-4cb6-a4e1-1086bdc8432c)\n\n## ❓ Why?\n\nManaging hundreds of repositories across an organization is tedious. You constantly need to:\n\n- Check which repos have uncommitted changes\n- Pull the latest updates across all projects\n- Clone new repos that have been created\n- Clean up experimental branches and changes\n\n**`repos`** solves this by providing a CLI to manage all your repositories with a terminal UI, parallel operations, and GitHub integration.\n\n## ✨ Features\n\n- 🎯 **Interactive Mode**: Run `repos` without arguments for a menu-driven TUI experience\n- 🔀 **Git-like Commands**: Familiar commands (`fetch`, `pull`, `diff`, `checkout`) work across all repos\n- 📊 **Terminal UI**: Progress bars, tables, spinners, and colored output\n- ⚡ **Parallel Operations**: Fast updates with configurable concurrency\n- 🐙 **GitHub Integration**: Clone repos from any GitHub org (Cloud or Enterprise)\n- 🔧 **Smart Defaults**: Detects `gh` CLI config and respects `.gitignore` patterns\n- 📁 **Config File Support**: Save your settings in `.reposrc.json`\n- 🛠️ **Escape Hatch**: Run any command across repos with `repos exec`\n\n## 📦 Installation\n\n### Homebrew\n\n```sh\nbrew install epilande/tap/repos\n```\n\n### Binary Download\n\nDownload the pre-built binary for your platform from [Releases](https://github.com/epilande/repos/releases/latest):\n\n```sh\n# macOS Apple Silicon\ncurl -L https://github.com/epilande/repos/releases/latest/download/repos-macos-arm64 -o repos\nchmod +x repos\nsudo mv repos /usr/local/bin/\n```\n\n### Build from Source\n\n```sh\ngit clone https://github.com/epilande/repos.git\ncd repos\nbun install\nbun run build\n```\n\n### Development Setup\n\n```sh\ngit clone https://github.com/epilande/repos.git\ncd repos\nbun install\nbun link  # Link globally for development\n```\n\n## 🚀 Quick Start\n\n1. Run the setup wizard to configure your GitHub org:\n\n   ```sh\n   repos init\n   ```\n\n2. Check the status of all repos in your current directory:\n\n   ```sh\n   repos status\n   ```\n\n3. Pull the latest changes across all repos:\n\n   ```sh\n   repos pull\n   ```\n\n4. Clone all active repos from your organization:\n\n   ```sh\n   repos clone --org my-org\n   ```\n\n## 🎮 Usage\n\n### Interactive Mode\n\nRun `repos` without any arguments to launch the interactive menu:\n\n```sh\nrepos\n```\n\n**Keyboard shortcuts:**\n| Key | Action |\n|-----|--------|\n| `↑↓` / `jk` | Navigate menu |\n| `Enter` | Select command |\n| `s,f,p,d,c` | Jump to git commands (Status, Fetch, Pull, Diff, Checkout) |\n| `o,x,e` | Jump to repo commands (Clone, Clean, Exec) |\n| `g,i` | Jump to settings (Config, Init) |\n| `q` | Quit |\n\n### Commands\n\n| Command                   | Description                            |\n| :------------------------ | :------------------------------------- |\n| `repos`                   | Launch interactive menu                |\n| `repos init`              | Setup wizard for configuration         |\n| `repos status`            | Check status of all repositories       |\n| `repos fetch`             | Fetch latest changes from remotes      |\n| `repos pull`              | Pull latest changes for all repos      |\n| `repos diff`              | Show diffs across all repositories     |\n| `repos checkout \u003cbranch\u003e` | Switch branches across all repos       |\n| `repos clone`             | Clone repos from GitHub org            |\n| `repos clean`             | Revert changes in repositories         |\n| `repos exec \"\u003ccommand\u003e\"`  | Run arbitrary command across all repos |\n| `repos config`            | View or modify configuration           |\n\n### Status Command\n\n```sh\nrepos status                   # Full table output\nrepos status --fetch           # Fetch from remotes first\nrepos status --summary         # Just show counts\nrepos status --quiet           # Only show repos with changes\nrepos status --filter 'api-*'  # Filter by pattern\n```\n\n**Example output:**\n\n```\nRepository          Branch         Modified  Staged  Untracked  Sync\n──────────────────────────────────────────────────────────────────────\n✓ webapp            main           0         0       0          ✓\n● api-server        main           2         0       1          ↓32\n✓ auth-service      feature/oauth  0         0       0          ↑3\n```\n\n### Fetch Command\n\n```sh\nrepos fetch                   # Fetch all repos\nrepos fetch --prune           # Remove stale remote-tracking refs\nrepos fetch --all             # Fetch from all remotes\nrepos fetch --dry-run         # Preview what would be fetched\nrepos fetch --filter 'api-*'  # Fetch only matching repos\n```\n\n### Pull Command\n\n```sh\nrepos pull                   # Pull all repos\nrepos pull --dry-run         # Preview what would be updated\nrepos pull --quiet           # Minimal output\nrepos pull --parallel 5      # Limit concurrent operations\nrepos pull --filter 'api-*'  # Pull only matching repos\n```\n\n\u003e [!NOTE]\n\u003e Repos with uncommitted changes are automatically skipped to protect your work.\n\n### Clone Command\n\n```sh\nrepos clone --org my-org           # Clone from organization\nrepos clone --org my-username      # Clone from user account\nrepos clone --host github.abc.com  # Clone from GitHub Enterprise\nrepos clone --days 30              # Only repos active in last 30 days\nrepos clone --parallel 5           # Limit concurrent clone operations\nrepos clone --shallow              # Shallow clone (faster)\nrepos clone --dry-run              # Preview what would be cloned\n```\n\n### Diff Command\n\n```sh\nrepos diff                   # Show diffs (default: 500 lines per repo)\nrepos diff --max-lines 100   # Limit output to 100 lines per repo\nrepos diff --max-lines 0     # Show full diff (no limit)\nrepos diff --stat            # Show diffstat summary\nrepos diff --quiet           # Only list repos with changes\nrepos diff --parallel 5      # Limit concurrent operations\nrepos diff --filter 'api-*'  # Diff only matching repos\n```\n\n### Checkout Command\n\n```sh\nrepos checkout main              # Switch to 'main' branch\nrepos checkout -b feature/new    # Create and switch to new branch\nrepos checkout main --force      # Skip repos with uncommitted changes\nrepos checkout main --parallel 5 # Limit concurrent operations\nrepos checkout main --filter '*' # Checkout only matching repos\n```\n\n\u003e [!NOTE]\n\u003e Repos with uncommitted changes are skipped unless `--force` is used.\n\n### Clean Command\n\n```sh\nrepos clean --dry-run         # Preview what would be cleaned\nrepos clean                   # Revert tracked file changes\nrepos clean --all             # Also remove untracked files\nrepos clean --force           # Skip confirmation prompt\nrepos clean --filter 'api-*'  # Clean only matching repos\n```\n\n\u003e [!WARNING]\n\u003e The clean command will revert changes. Always use `--dry-run` first!\n\n### Exec Command\n\n```sh\nrepos exec \"git log -1 --oneline\"  # Show last commit in each repo\nrepos exec \"npm install\"           # Run npm install in all repos\nrepos exec \"pwd\" --quiet           # Only show repos with output\nrepos exec \"make test\" --parallel 5  # Run with limited concurrency\nrepos exec \"git branch\" --filter 'api-*'  # Run only in matching repos\n```\n\n\u003e [!TIP]\n\u003e Use `repos exec` as an escape hatch for any command not directly supported.\n\n### Config Command\n\n```sh\nrepos config                           # List all config values\nrepos config --list                    # List all config values\nrepos config --get org                 # Get a specific config value\nrepos config --set org --value my-org  # Set a config value\nrepos config --location home           # Use home directory config file\n```\n\n## ⚙️ Configuration\n\nCreate `.reposrc.json` in your project directory or home folder:\n\n```json\n{\n  \"github\": {\n    \"host\": \"github.com\",\n    \"apiUrl\": \"https://api.github.com\"\n  },\n  \"org\": \"my-org\",\n  \"daysThreshold\": 90,\n  \"parallel\": 10,\n  \"timeout\": 30000,\n  \"diffMaxLines\": 500\n}\n```\n\n| Option          | Default                  | Description                           |\n| :-------------- | :----------------------- | :------------------------------------ |\n| `github.host`   | `github.com`             | GitHub host (for Enterprise)          |\n| `github.apiUrl` | `https://api.github.com` | GitHub API URL                        |\n| `org`           | -                        | Default organization to clone from    |\n| `daysThreshold` | `90`                     | Only clone repos active within N days |\n| `parallel`      | `10`                     | Number of concurrent operations       |\n| `timeout`       | `30000`                  | Network timeout in milliseconds       |\n| `diffMaxLines`  | `500`                    | Max lines per diff (0 for unlimited)  |\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eGitHub Enterprise Configuration\u003c/strong\u003e\u003c/summary\u003e\n\n```json\n{\n  \"github\": {\n    \"host\": \"github.mycompany.com\",\n    \"apiUrl\": \"https://github.mycompany.com/api/v3\"\n  },\n  \"org\": \"my-team\"\n}\n```\n\n\u003c/details\u003e\n\n### Configuration Priority\n\n1. **CLI flags** (highest) — `--org`, `--parallel`, etc.\n2. **Project config** — `.reposrc.json` in current directory\n3. **User config** — `~/.reposrc.json`\n4. **gh CLI** — Detected from `~/.config/gh/hosts.yml`\n5. **Defaults** (lowest)\n\n## 🔐 Authentication\n\nFor `repos clone`, authentication is required. The tool checks these sources:\n\n1. **gh CLI** — If you have `gh` installed and authenticated (`gh auth login`)\n2. **Environment variables** — `GITHUB_TOKEN` or `GH_TOKEN`\n3. **Interactive prompt** — Runs setup wizard if no auth found\n\n## 🔧 Development\n\n```sh\n# Install dependencies\nbun install\n\n# Run in development\nbun run src/index.ts status\n\n# Type check\nbun run typecheck\n\n# Build binary\nbun run build\n\n# Cross-compile for all platforms\nbun run build:all\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eProject Structure\u003c/strong\u003e\u003c/summary\u003e\n\n```\nrepos/\n├── src/\n│   ├── index.ts       # CLI entry point\n│   ├── types.ts       # TypeScript interfaces\n│   ├── commands/      # Command implementations\n│   ├── components/    # Reusable Ink components\n│   └── lib/           # Core logic\n├── bin/repos          # Dev wrapper script\n└── package.json\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepilande%2Frepos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepilande%2Frepos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepilande%2Frepos/lists"}