Metadata-Version: 2.4
Name: git-maintainer-tools
Version: 1.1.1
Summary: Small CLIs (git-setup-remotes, git-sign-push) for fork-based OSS maintainer workflows.
Author-email: Kevin Veen-Birkenbach <kevin@veen.world>
License: MIT
Project-URL: Homepage, https://github.com/kevinveenbirkenbach/git-maintainer-tools
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Provides-Extra: publish
Requires-Dist: build>=1.0; extra == "publish"
Requires-Dist: twine>=5.0; extra == "publish"
Requires-Dist: keyring>=24.0; extra == "publish"
Dynamic: license-file

# git-maintainer-tools 🧰
[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate)


Small CLIs for a fork-based OSS maintainer workflow.

Homepage: [github.com/kevinveenbirkenbach/git-maintainer-tools](https://github.com/kevinveenbirkenbach/git-maintainer-tools)

Originally extracted from [s.infinito.nexus/code](https://s.infinito.nexus/code), where these helpers started as shell scripts under `scripts/git/` before being rewritten in Python and split out as a standalone tool.

## Tools 🔧

### `git-setup-remotes` 🌐

Configures a clone for a fork-based workflow and is idempotent.

- `origin` points at the canonical repository.
- `fork` points at the maintainer's personal fork.
- `main` tracks `origin/main`.
- `remote.pushDefault` = `fork`, `push.default` = `current` so every `git push` and every `git push -u` for a new branch lands on the fork, not on the canonical repo.
- `branch.main.pushRemote` = `origin` so a direct push on the canonical branch targets upstream, not the personal fork (whose branch-protection rules can diverge).

Usage:

```bash
git-setup-remotes \
  --canonical git@github.com:<org>/<repo>.git \
  --fork git@github.com:<user>/<fork>.git
```

Both URLs may be provided via environment variables instead (`CANONICAL_URL`, `FORK_URL`). If `--fork` / `FORK_URL` is not given, the tool reuses an existing `fork` remote or an existing `origin` that does not point at canonical (clone-from-fork case).

### `git-sign-push` 🔐

GPG-signs every unpushed commit on the current branch and pushes.

- Refuses to run inside the Claude sandbox (where `~/.gnupg` is unreadable) and when the working tree is dirty.
- For a branch with an upstream: `git push --force-with-lease` after any required re-sign.
- For a branch without upstream: `git push -u <remote>` where `<remote>` is resolved from `remote.pushDefault` (fallback: `origin`). In a repo configured by `git-setup-remotes`, this means new branches land on the fork.

Usage:

```bash
git-sign-push
```

## Install 📦

From the repo checkout:

```bash
pip install .
```

Or for development:

```bash
pip install -e '.[dev]'
```

Both entry points are registered in `pyproject.toml` and will be on your `$PATH` after install.

## Publish 🚀

Build sdist + wheel into `dist/` and upload to PyPI:

```bash
make publish
```

`make publish` pulls in the `publish` extras (`build`, `twine`, `keyring`) automatically. Auth resolves in the following order:

1. **System keyring** (recommended) via the `keyring` package. Store the token once and every subsequent `make publish` runs without a prompt:
   ```bash
   keyring set https://upload.pypi.org/legacy/ __token__   # enter pypi-AgEI... when prompted
   ```
2. **`~/.pypirc`** or the `TWINE_USERNAME` / `TWINE_PASSWORD` environment variables (use `__token__` as the username and the PyPI API token as the password).

`make publish-test` targets TestPyPI instead; register its token under `https://test.pypi.org/legacy/` in the keyring.

## Sandbox 🏜️

Both CLIs refuse to run when `CLAUDE_CODE` or `CLAUDECODE` is set in the environment, because the Claude sandbox blocks `.git/config` writes (for `git-setup-remotes`) and access to `~/.gnupg` (for `git-sign-push`). The tools MUST be run by the human operator outside the sandbox.

## Author ✍️

Kevin Veen-Birkenbach, [veen.world](https://www.veen.world/)

## License 📜

Licensed under the [MIT License](LICENSE).
