Metadata-Version: 2.5
Name: gittwin
Version: 0.3.0
Summary: Run multiple git commits, branches, or tags of the same app side by side in isolated environments
Project-URL: Homepage, https://github.com/Shyam-Sundar-Reddy/GitTwin
Project-URL: Repository, https://github.com/Shyam-Sundar-Reddy/GitTwin
License: MIT
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: psutil>=5.9
Requires-Dist: rich>=13.0
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# GitTwin

Run multiple git commits, branches, or tags of the same FastAPI application
side by side, each in its own isolated environment — for comparison,
debugging, regression testing, and demonstrations.

**Status: working MVP.** `gittwin up` actually boots real FastAPI apps
today, with a live dashboard and automatic cleanup. Framework support is
currently **FastAPI only** — see [Supported frameworks](#supported-frameworks)
below.

## Why

Reproducing "it worked on commit X but not on commit Y" usually means
stashing changes, checking out refs one at a time, and juggling ports,
dependencies, and env files by hand. GitTwin makes that a single command:

```bash
gittwin up HEAD abc123
```

Stays attached with a live, color-coded dashboard while both run — press
Ctrl+C and everything (processes, worktrees, envs) is cleaned up
automatically, no separate teardown step needed.

Under the hood, each ref gets its own [git
worktree](https://git-scm.com/docs/git-worktree), its own `uv`-managed
virtual environment with its own dependencies installed, and its own port
— so multiple versions of your app run side by side without one clobbering
another or disturbing your current branch.

## Install

```bash
uv add gittwin
pip install gittwin
```

## Usage

```bash
gittwin up <refs...>               # launch one+ refs, stays attached with a live dashboard
gittwin up <refs...> -d            # same, but detached (returns immediately, keeps running)
gittwin run <ref>                  # shortcut for `up <ref> -d`
gittwin compare <ref1> <ref2> ...  # shortcut for `up <ref1> <ref2> ... -d`
gittwin list                       # list worktrees gittwin has created
gittwin stop <ref>                 # stop one running instance
gittwin clean                      # stop everything, remove all worktrees/envs
gittwin doctor                     # check git/uv are installed, reconcile orphaned instances
gittwin about
gittwin --version
```

`<ref>` accepts any commit SHA, branch name, or tag. An invalid ref fails
immediately with a clear error instead of a raw git traceback.

### Example — attached session (the default)

```bash
cd my-fastapi-project
gittwin up HEAD main
```

```text
HEAD -> http://127.0.0.1:8000
main -> http://127.0.0.1:8001

Press Ctrl+C to stop and clean up.
┌──────┬─────────┬────────────────────────┬───────┬─────────┐
│ Ref  │ Status  │ URL                     │ PID   │ Uptime  │
├──────┼─────────┼────────────────────────┼───────┼─────────┤
│ HEAD │ running │ http://127.0.0.1:8000  │ 18736 │ 0m 12s  │
│ main │ running │ http://127.0.0.1:8001  │ 18804 │ 0m 12s  │
└──────┴─────────┴────────────────────────┴───────┴─────────┘
^C
Stopped 2 instance(s), removed 2 worktree(s), deleted 2 env(s). Session time: 0m 47s
```

The table updates live and a row turns red if that instance's process dies
mid-session. While provisioning (worktree/env/deps/boot), a real terminal
shows an animated spinner per ref instead of the plain text lines above.

### Example — detached (old fire-and-forget style)

```bash
gittwin compare HEAD abc123
# HEAD  -> http://127.0.0.1:8000
# abc123 -> http://127.0.0.1:8001
gittwin clean   # tear both down when you're done
```

## Supported frameworks

**FastAPI only, for now.** `gittwin` detects FastAPI via a `fastapi` entry
in your `pyproject.toml` dependencies, and boots your app with `uvicorn
<module>:<app>` (convention: `main:app`). Flask, Django, Node.js,
Docker-based apps, and other languages are on the backlog, not implemented
yet.

## How it works

- **Worktrees**: each ref is checked out into `<repo>/.gittwin/worktrees/<ref>`,
  so multiple refs can be checked out simultaneously without one clobbering
  another. `gittwin list` shows only worktrees gittwin created — your main
  checkout is never listed as one of them.
- **Environments**: each worktree gets its own `uv`-managed venv under
  `<repo>/.gittwin/envs/<ref>`, with that ref's own `pyproject.toml`
  dependencies installed into it — so different refs can depend on
  different (even incompatible) package versions.
- **Ports**: each instance gets a free port automatically, allocated from
  `gittwin.toml`'s configured range (default `8000`-`8999`), with no
  collisions even when launching several refs concurrently.
- **Foreground sessions**: `gittwin up` (without `-d`) blocks — the CLI
  process itself represents the session's lifetime. Ctrl+C, or a sent
  termination signal, tears everything down before it exits: process
  killed, worktree removed, env deleted, state cleared. Nothing is left
  running behind the CLI's back.
- **Orphan reconciliation**: a hard kill, crash, or power loss can't be
  caught by a signal handler, so a stale entry can still be left behind.
  Every command (`list`/`stop`/`clean`/`run`/`compare`/`up`) silently
  prunes and cleans up any instance whose process is no longer alive
  before doing its own work; `gittwin doctor` reports how many it found.
- **Cleanup**: `gittwin stop <ref>` / `gittwin clean` terminate the running
  process(es) and remove the worktree(s) and env(s) they used. If setup
  for a ref fails partway through, gittwin removes that worktree again
  rather than leaving a half-provisioned one behind.

## Development

This project uses [uv](https://docs.astral.sh/uv/) for dependency management.

```bash
uv sync --extra dev   # install package + dev deps into .venv
uv run pytest -q      # run tests
uv run gittwin about  # run the CLI
```
