Metadata-Version: 2.4
Name: git-alibi
Version: 0.1.0
Summary: Rewrite git commit timestamps to fit within or exclude certain time windows
Author-email: Zach Light <zachary.j.light@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/zlight97/git-alibi
Project-URL: Issues, https://github.com/zlight97/git-alibi/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Topic :: Software Development :: Version Control
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.0
Requires-Dist: gitpython>=3.1
Requires-Dist: tomlkit>=0.12
Requires-Dist: git-filter-repo>=2.38
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# git-alibi

Rewrite git commit timestamps to fit within (or avoid) configured time windows.

Useful for keeping commit history clean when you work odd hours, across timezones,
or want commits to consistently appear within business hours. Alibi saves a backup
before every rewrite so changes can always be undone.

## Requirements

- Python 3.11 or newer
- git 2.25 or newer

## Installation

**pip** (simplest):
```bash
cd git-alibi
pip install .
```

**pipx** (isolated, recommended for CLI tools):
```bash
pipx install /path/to/git-alibi
```

**Virtual environment** (if you prefer not to touch system Python):
```bash
cd git-alibi
python3 -m venv .venv
source .venv/bin/activate      # Windows: .venv\Scripts\activate
pip install .
```

Verify the install:
```bash
git-alibi --help
# git also picks it up automatically:
git alibi --help
```

## Uninstallation

```bash
pip uninstall git-alibi      # if installed with pip
pipx uninstall git-alibi     # if installed with pipx
rm -rf .venv                 # if installed into a venv, just delete it
```

## Quick start

Preview what would change without touching the repo:
```bash
git-alibi rewrite --dry-run
```

Apply the rewrite:
```bash
git-alibi rewrite
```

If the branch was already pushed:
```bash
git push --force-with-lease
```

Undo the last rewrite:
```bash
git-alibi restore
```

## Configuration

Alibi is configured with TOML files. Settings in the local file take precedence
over the global one.

| File | Scope |
|------|-------|
| `~/.config/alibi/config.toml` | Global (all repos) |
| `.git/alibi/config.toml` | Local (this repo only) |

Open a config file in `$EDITOR` (created with commented-out defaults if it doesn't exist):
```bash
git-alibi config local
git-alibi config global
```

### Example config

```toml
[behavior]
timezone = "America/Chicago"
out_of_window = "nearest"   # nearest / previous / next / random
spacing = "preserve"        # preserve / proportional / even / random

[days]
block = ["SAT", "SUN"]      # never place commits on weekends

[times]
allow = ["09:00-17:00"]     # only allow commits during business hours

[authors]
# CURRENT expands to the email in git config user.email
emails = ["CURRENT"]

[markers]
# Commits containing this string in their message are never rewritten
skip = ["[no-alibi]"]
```

## Commands

### `rewrite`

Rewrites commit timestamps to fit within the configured windows. Operates on
commits in the current branch since it diverged from `main`/`master` (or the
upstream tracking branch), for the current git user's commits only.

```bash
git-alibi rewrite [OPTIONS] [REF]
```

| Option | Description |
|--------|-------------|
| `--dry-run` | Preview changes without modifying the repo |
| `-v, --verbose` | Show all commits in dry-run output, not just changed ones |
| `--no-backup` | Skip saving a backup before rewriting |
| `--shift DURATION` | Shift timestamps by a fixed amount instead of fitting windows (e.g. `+2h`, `-5h30m`, `+5:30`) |
| `--timezone TZ` | Override the timezone (IANA name, e.g. `America/Chicago`) |
| `--allow-days DAYS` | Comma-separated days to allow (e.g. `MON,TUE,WED,THU,FRI`) |
| `--block-days DAYS` | Comma-separated days to block (e.g. `SAT,SUN`) |
| `--allow-times RANGES` | Time ranges to allow (e.g. `09:00-17:00`, `MON+FRI@09:00-12:00`) |
| `--block-times RANGES` | Time ranges to block |
| `--allow-dates DATES` | Dates or ranges to allow (e.g. `2024-03-01:2024-03-31`) |
| `--block-dates DATES` | Dates or ranges to block (e.g. `2024-12-25`) |
| `--out-of-window` | How to handle commits outside all windows: `nearest` (default), `previous`, `next`, `random` |
| `--spacing` | How to distribute commits within a window: `preserve` (default), `proportional`, `even`, `random` |
| `--author-emails EMAILS` | Comma-separated emails to rewrite; `CURRENT` = git config `user.email` |
| `--all-authors` | Rewrite commits by all authors, not just the current user |
| `--all-history` | Rewrite all reachable history, not just the current branch |
| `--skip-markers MARKERS` | Comma-separated message markers that exempt a commit (default: `[no-alibi]`) |
| `-f, --force` | Proceed even if signed commits would be rewritten |

#### Timezone correction with `--shift`

If you committed in the wrong timezone, shift all timestamps by a fixed offset:

```bash
git-alibi rewrite --shift +5:30    # move everything forward 5h30m
git-alibi rewrite --shift -8h      # move everything back 8 hours
git-alibi rewrite --dry-run --shift +2h   # preview first
```

#### Opting out of rewriting

Add `[no-alibi]` anywhere in a commit message to permanently exempt that commit:

```
fix: correct off-by-one error [no-alibi]
```

The marker string is configurable via `[markers] skip` in the config file or
`--skip-markers` on the command line.

### `restore`

Restores commit timestamps from the backup saved before a previous rewrite.

```bash
git-alibi restore [OPTIONS] [REF]
```

| Option | Description |
|--------|-------------|
| `--dry-run` | Preview what would be restored without applying |
| `-v, --verbose` | Show all commits, not just changed ones |
| `--last N` | Undo the Nth most recent rewrite (default: `1` = last) |
| `--rewrite ID` | Restore a specific rewrite by ID (see `history`) |
| `-f, --force` | Proceed even if signed commits would be rewritten |

```bash
git-alibi restore              # undo the last rewrite
git-alibi restore --last 2    # undo the second-to-last rewrite
git-alibi restore --rewrite 3 # restore to a specific snapshot ID
```

### `history`

Shows all recorded rewrites and the exact command to restore each one.

```bash
git-alibi history [-v]
```

```
Rewrite history — 3 snapshots in .git/alibi/backup.json

  ID    WHEN                     COMMITS  --last  RESTORE
  ───────────────────────────────────────────────────────
  1     2024-01-06 Sat 09:15:00        5       3  alibi restore --last 3
  2     2024-01-07 Sun 14:30:00        3       2  alibi restore --last 2
  3     2024-01-08 Mon 11:15:00        2       1  alibi restore ← latest
```

Use `-v` to also list the individual commits and their original timestamps.

### `config`

Opens a config file in `$EDITOR`, creating it with commented-out defaults if it
doesn't exist yet.

```bash
git-alibi config local    # .git/alibi/config.toml
git-alibi config global   # ~/.config/alibi/config.toml
```
