git-epic
A Python CLI for our epic-based Git workflow, with no runtime Python dependencies.
Git discovers the git-epic
executable automatically, so commands use git epic ….
Install
Requires Python 3.11+, Git 2.31+, and glab. Authenticate once with your GitLab host:
glab auth login --hostname gitlab.wonderbeauties.com
After the first PyPI release, install with pipx:
pipx install git-epic
pipx ensurepath
git epic -h
For local development before publication:
pipx install .
pipx ensurepath
git epic -h
If ensurepath changes your PATH, open a new terminal. Upgrade with
pipx upgrade git-epic. The package is not yet published; pipx install . works
from a local checkout today.
Commands
Use git epic -h for CLI help. Git reserves git epic --help for a system manual
page; this MVP does not install one. Direct invocation also supports
git-epic --help.
| Command | Behavior |
|---|---|
git epic init |
Write shared .git-epic.json; defaults to production, origin, and GitLab. |
git epic start <name> |
Fetch production; create and switch to local epic/<name>. |
git epic task start <name> |
From an epic, fetch and fast-forward remote epic changes if possible; create task/<epic>/<name>. |
git epic task submit |
Push committed task changes; create or return its parent epic MR. Publish the local parent epic if it is not yet on the remote. |
git epic sync |
From an epic, fetch and merge production. Push the result yourself or with release. |
git epic status |
Fetch; show current task/epic, labelled local/remote epic drift, related open MRs (including task MRs when on an epic), and their latest reported CI status. |
git epic release |
Push committed epic changes; create or return an MR targeting production. Never merges or deploys. |
GitLab calls PRs merge requests (MRs). Submission commands also push new commits when returning an existing MR; they do not create a duplicate.
Names are single segments: letters, numbers, dots, underscores, and hyphens, starting with a letter or number. Git's branch-name restrictions also apply.
For repositories using a different production branch or remote:
git epic init --production main --remote origin
git add .git-epic.json
git commit -m "Configure git-epic"
git push
Commit this file on production before creating epics so all branches and teammates
inherit it. It contains no credentials. Existing configuration is never overwritten;
edit the file to change settings. An initial production commit must already exist on
the remote; init does not bootstrap an empty application repository.
Typical workflow
git epic start checkout
git epic task start payment
# Implement and commit your task.
git epic task submit
# Review, CI, and merge the task MR in GitLab.
git switch epic/checkout
# Bring merged tasks into the local epic.
git fetch origin
git merge --ff-only origin/epic/checkout
git epic sync
git push origin epic/checkout
# Deploy OTF and obtain QA approval through the existing team process.
git epic release
# Review, required CI, and merge in GitLab; CI/CD deploys production.
OTF deployment and QA approval are external to this CLI. Approval belongs to an
exact commit/build. If the candidate or production changes, update and revalidate
before merging. release refuses an epic that is behind current production, but
the hosting platform/CI must also enforce release checks at merge time. The CLI
does not record or verify QA approval.
Git behavior
- Branch and submission operations require a clean working tree and no unfinished
merge/rebase/cherry-pick/revert.
statusallows uncommitted changes. - Fetch updates remote-tracking refs. No command force-pushes, resets, deletes a branch, merges an MR, or deploys.
startcreates a local epic. Submission publishes branches with ordinary pushes; non-fast-forward pushes are rejected rather than overwriting teammates' work.task startstops if local and remote epic histories have diverged. Reconcile the epic using Git before retrying.releasesimilarly requires your local epic to include remote epic work before a push can succeed.- If
syncconflicts, resolve and commit, or usegit merge --abort. - An MR/API failure after a push leaves the branch published; retry the command.
- GitLab authentication is managed by
glab, and Git authentication by Git.
Development and release
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'
ruff check .
ruff format --check .
python -m unittest discover -s tests -v
python -m build
python -m twine check --strict dist/*.whl dist/*.tar.gz
Tests create temporary local Git repositories and a fake glab; they never create
real MRs or touch production. GitLab API behavior is delegated to the installed
glab. CI checks Python 3.11 and 3.14, builds a wheel and source distribution,
validates metadata with Twine, and smoke-tests the installed wheel via Git.
Publish to PyPI
Local publication helper
From a clean, committed checkout with a configured Git upstream, run:
./publish.sh
The helper uses uv to prompt for a PEP 440 version (press Enter to keep the
current version for the first release), update the version and README release-tag
examples, run tests, clean and build distributions, validate with Twine, upload
to PyPI, and commit/push the release changes. Set PYPI_API_TOKEN or
TWINE_PASSWORD in your shell; otherwise Twine prompts for authentication.
It does not create a release tag or trigger the CI publication job.
GitLab CI publication
The distribution name is git-epic, import package is git_epic, and CLI
entry point is git-epic. Version is defined once in
src/git_epic/__init__.py.
- Create a PyPI account and an API token. For the first release, a token with account scope is needed; after creating the project, use a project-scoped token.
- In GitLab CI/CD variables, add
PYPI_API_TOKENas a masked, protected variable. Protect the release tag pattern (v*) so tagged jobs can access it. - Update the version, then push a matching tag, for example
v0.1.0. - After verification and build jobs pass, manually run
publish:pypi.
The job uploads only the validated wheel and source distribution from the build job. A release tag must match the package version. PyPI does not allow reusing an uploaded version: use a new version for subsequent releases.
An optional publish:testpypi job uses TESTPYPI_API_TOKEN and the separate
TestPyPI registry. TestPyPI accounts and tokens are independent of PyPI. A test
installation uses pipx install --index-url https://test.pypi.org/simple/ git-epic.
For a manual upload of locally built, validated distributions:
export TWINE_USERNAME=__token__
# Set TWINE_PASSWORD to your PyPI API token in your shell.
python -m twine upload --non-interactive dist/*.whl dist/*.tar.gz
Credentials are supplied by the shell or CI, never stored in project files. PyPI Trusted Publishing currently supports GitLab.com, not this self-managed GitLab host, so the release jobs use API tokens. Package-name availability is determined by PyPI at upload time. A public PyPI release includes the source code even when the GitLab repository is private.
Metadata
Release files for git-epic 0.1.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 | |
|---|---|---|---|
| git_epic-0.1.0.tar.gz | 20.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| git_epic-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.5 kB
Release files / git_epic-0.1.0.tar.gz
| Download URL | git_epic-0.1.0.tar.gz |
|---|---|
| Size | 20.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
628162de276db2f96129bfe09cec3a552da2ee95d2b27f11548220dbeeca3fe5
|
|
BLAKE2b-256 checksum How to use checksums |
77f80b472f9e98d93705d6eb9ed2dd8ad02d97f22d02c0f2b71bf7a8ddbb351a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.14
|
Release files / git_epic-0.1.0-py3-none-any.whl
| Download URL | git_epic-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
80629c6b8d4080658a92d562f6e76a5b748fab7e79036eb9cf51301f65c350c4
|
|
BLAKE2b-256 checksum How to use checksums |
57078183e27c2055159535741213ed0e8cf25bedf96b279a97150beb6363a5c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.14
|