bight
Patches .env files automatically on git checkout — keeping local environments in sync with the current branch.
git checkout feat-login
# bight: .env → DB_NAME=myapp_feat-login
# bight: .env → JWT_SECRET=***
Only the listed vars are touched. The rest of your .env is left untouched.
Installation
With Homebrew:
brew install andrewadev/tap/bight
With Go:
go install github.com/AndrewADev/bight@latest
From a release binary:
Download the binary for your platform from the releases page:
| Platform |
File |
| macOS (Apple Silicon) |
bight-darwin-arm64 |
| macOS (Intel) |
bight-darwin-amd64 |
| Linux (x86-64) |
bight-linux-amd64 |
| Linux (ARM64) |
bight-linux-arm64 |
| Windows |
bight-windows-amd64.exe |
Then make it executable and put it on your PATH:
chmod +x bight-darwin-arm64
mv bight-darwin-arm64 /usr/local/bin/bight
Each release includes a checksums.txt for verification:
sha256sum -c checksums.txt --ignore-missing
Getting started
1. Install
Run once per repo, after cloning:
bight install
This writes the git hook and walks you through creating a .bight.yml config:
bight: hook installed
bight: no config file found. Create .bight.yml? [Y/n]
Project name [myapp]:
Env file path [.env]:
Add env vars to track? [Y/n]
(blank name to finish)
Var name: DB_NAME
Strategy:
1) template - interpolate branch/project name (default)
2) random - fresh random value on each checkout
Choice [1]: 1
Var name:
bight: created .bight.yml
2. Confirm everything is wired up
bight doctor
bight doctor:
[ok] git repo detected
[ok] config: .bight.yml loaded
[ok] config: project = "myapp", 1 env file(s)
[ok] hook: installed
[ok] env file: .env
[ok] vars: all strategies valid
[ok] vars: all triggers valid
3. Preview before it fires automatically
bight run --dry-run
# bight (dry-run): .env → DB_NAME=myapp_main
No files are touched. When you're happy with what you see, you're done — the hook fires on every checkout from here on.
4. Switch branches
git checkout -b feat-login
# bight: .env → DB_NAME=myapp_feat-login
Reference
Config file
bight install generates a starter config, but you can hand-edit .bight.yml at any time:
project: myapp
defaults:
branch_template: "{{.Project}}_{{.Branch}}" # used by the template strategy
env_files:
- path: .env
backup: true # write .env.bak before patching (optional, default false)
vars:
- name: DB_NAME
strategy: template # renders to e.g. myapp_feat-login
on: checkout
- name: JWT_SECRET
strategy: random # fresh 64-char hex string on every branch switch
on: checkout
sensitive: true # mask value in console output
Using a non-default config file
If your config isn't named .bight.yml or lives at a non-standard path, use --config:
bight run --config path/to/custom.bight.yml
bight doctor --config path/to/custom.bight.yml
--config is a global flag — it works with any subcommand that reads config.
Manual patching
To apply env patching for the current branch without switching:
bight run
Tip: to test how another branch would be patched, suppress the hook when switching so bight doesn't fire automatically, then use --dry-run:
git -c core.hooksPath=/dev/null checkout other-branch
bight run --dry-run
Strategies
| Strategy |
Output |
Typical use |
template |
Rendered from {{.Project}} / {{.Branch}} |
DB_NAME |
random |
Fresh 32-byte hex string |
JWT_SECRET, tokens |
deterministic |
Stable 64-char hex derived from project + branch |
DB_NAME (same value across machines) |
Sensitive vars (sensitive)
Mark a var sensitive: true to prevent its value from appearing in console output. The value is still written to the .env file normally — only the terminal display is affected.
- name: JWT_SECRET
strategy: random
on: checkout
sensitive: true
Output with sensitive: true:
bight: .env → JWT_SECRET=***
Backup files (backup)
Set backup: true on an env file entry to write a copy of the file to {path}.bak before each patch is applied. Useful for inspecting what changed or recovering a previous value.
env_files:
- path: .env
backup: true
vars:
- name: DB_NAME
strategy: template
on: checkout
The backup is a verbatim copy of the file as it was immediately before patching. It is overwritten on each checkout — only the most recent pre-patch state is kept.
Full comment preservation is not supported, as the package we use, godotenv, strips comments on rewrite. As a partial workaround, defaults.collect-comments re-appends comments collected before the patch was applied:
Note: This is a best-effort feature. Comments are collected from the file before patching and re-appended at the end afterwards — their original positions are not restored, and inline comments (KEY=val # note) are lost entirely.
| Value |
Behavior |
all |
Re-appends every full-line comment |
blocks-only |
Re-appends only contiguous comment blocks (≥ 2 lines) — skips isolated # notes |
unset / none |
Comments are not preserved (default) |
defaults:
collect-comments: blocks-only
Comments are always written after the key=value pairs.
Triggers (on)
| Value |
When |
checkout |
Every branch switch |
Global config (~/.bight.yml)
Settings in ~/.bight.yml apply across all repos and are overridden field-by-field by the repo's .bight.yml. Only defaults fields are supported globally — env_files and vars must be defined in the repo config. If a repo has no .bight.yml, bight does nothing — the global config alone is not enough to trigger patching.
defaults:
branch_template: "{{.Project}}_{{.Branch}}"
collect-comments: blocks-only
Developing
See DEVELOPING.md