repodb
Keep a SQLite database of git project clone URLs. Clone, compare and change the projects in bulk.
Each project is stored as (owner, name, url), keyed by url: https and ssh urls of one repo are one project. The name is the clone directory, and OWNER/NAME is unique too. The owner is the first path component after the host (alice in github.com/alice/r or git@gitlab.com:alice/r), for any host.
Install
pip install repodb
This installs repodb.
Usage
Add and remove projects
repodb scan ~/src # add origin URLs of local projects
repodb github USER [--source] [--ssh] # add USER's GitHub repos and topics (needs gh)
repodb github --refresh [USER] # update topics of stored GitHub repos; add none
repodb github --refresh --prune [--yes] # list, then remove, repos gh no longer lists
repodb import projects.json
repodb remove OWNER/NAME [NAME ...] | --owner USER --all
Select projects
list, export, clone, status and apply take the same filters. A project must match all of them.
--owner USER # one owner's projects
-s SET # a named set (see below)
-t TOPIC [-t ...] # every topic given; with --any, at least one
repodb list [-g] [-u | --slugs] [--topics] # names, URLs, or OWNER/REPO
repodb topics [--owner USER] # each topic and its project count
repodb set --name SET SPEC ... # add projects to a set
repodb set [--name SET [--remove SPEC ... | --delete]] # list or change sets
repodb export [-g] -o projects.json
repodb info # format, counts, hosts, topics; read-only
-
A SPEC is
OWNER/NAME, orNAMEif only one owner has it. -
A set is a local, named selection, unrelated to topics. Adding to a set is idempotent and all-or-nothing.
-
Topics come from
githubandimport. -
list --slugsprintsOWNER/REPOfrom each url, for tools such as git-xargs or multi-gitter.
Clone and compare
repodb clone DEST [-g] [-j N] # selected projects into DEST/NAME or DEST/OWNER/NAME
repodb clone DEST -r OWNER/NAME [-r ...] # named projects
repodb clone DEST --json projects.json [-t TOPIC]
repodb clone DEST -- --depth 1 # options after -- go to git clone
repodb status DEST [-g] # compare DEST with the database
-
cloneskips targets that exist.-j Nruns N clones at once. -
statusprintsmissing,untracked,differs,not a git repoorno originper project, and exits 1 if it prints anything.
Change many repos
repodb apply RUN -s SET --exec 'python fix.py' -m "Message"
repodb apply RUN -s SET --replace 'actions/checkout@v\d+' 'actions/checkout@v5' \
--glob '.github/workflows/*.y*ml' -m "Bump actions/checkout to v5" -j 8
repodb review RUN [SPEC ...] [--diff] # per-repo state; full diffs
repodb publish RUN [--draft] # push repodb/RUN, open a PR per repo (needs gh)
repodb publish RUN --push-default # push to the default branch instead
repodb runs [RUN --discard] # list runs, or delete one
-
applyclones each repo into a work directory, runs the change, and commits onrepodb/RUN. Nothing is pushed untilpublish. -
Rerunning
applyorpublishresumes the run. A changed command or message needs--redo. -
publishrefuses a repo whose default branch moved sinceapply. -
Edits under
.github/workflows/pushed over HTTPS needgh auth refresh -s workflow. -
Details:
docs/dev/apply.md.
JSON
The JSON form is {name: url}, or with -g {owner: {name: url}}. A project with topics has {"url": url, "topics": [...]} in place of the url. Both forms round-trip byte for byte. Sets are not included.
The flat forms refuse a name held by two owners, ignoring case; use -g.
The database defaults to ~/.local/share/repodb/repos.sqlite; override with --db. Runs are kept in runs/ next to it.
Library
from pathlib import Path
from repodb import GitRepoDB, Run, apply_run, clone, runs_dir
with GitRepoDB() as db:
rows = db.rows(set_name="agents")
failed = clone(rows, Path("~/src").expanduser(), jobs=4)
run = Run.create("bump", "Bump checkout", replace=[r"checkout@v\d+", "checkout@v5"],
glob=[".github/workflows/*.yml"])
run.add(rows)
apply_run(run, runs_dir(db.db_path) / run.name)
Functions return data and raise exceptions. Progress goes to the repodb logger, which is silent unless configured. See the docstrings in repodb.core and repodb.apply.
Development
make qa # ruff lint and format check, mypy, pytest
Metadata
Release files for repodb 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| repodb-0.2.0.tar.gz | 48.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| repodb-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 79.0 kB
Release files / repodb-0.2.0.tar.gz
| Download URL | repodb-0.2.0.tar.gz |
|---|---|
| Size | 48.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
56ae7c099334e1344f789ddaf7aa7661e26e1366b46ea38fefdbb7e1fc0d446b
|
|
BLAKE2b-256 checksum How to use checksums |
cb11567219eab0f384f2fb51f55b7cae61afede162d28f5ae36ca2065edc1ada
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / repodb-0.2.0-py3-none-any.whl
| Download URL | repodb-0.2.0-py3-none-any.whl |
|---|---|
| Size | 30.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d166e7bf97a3406a5b38a79f547a233aa22a9662dc0e27a0de659bc23e78194e
|
|
BLAKE2b-256 checksum How to use checksums |
20fac6919564938fbc74c5ec052f7171e9550252be7911fe61d471c19cf31dcd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Security for repodb 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.