Skip to main content

Sync environment files across linked git worktrees

Project description

git-env

Copies untracked env files to your worktrees

Example

cd ~/repos/myproject                         # primary worktree, has .env
git worktree add ~/worktrees/my-feature      # create a linked worktree
cd ~/worktrees/my-feature
git env sync                                 # copies .env from the primary
$ git env sync
synced  .env
2 files synced, 0 unchanged, 0 conflicts skipped

Run it again later to pick up any changes made in the primary. By default, sync won't clobber a file that has diverged locally — pass --force if you want the primary's copy to win.

Installation

uv tool install git-env

Or, with pipx:

pipx install git-env

This installs a git-env executable on your PATH, which git picks up automatically as the env subcommand:

git env --version

Syncing

git env sync copies env files from the primary worktree into the linked worktree you're standing in. The primary worktree is the original clone — the one whose .git is a real directory, not a file. sync locates it via git rev-parse --git-common-dir.

Files are matched by glob against the entire primary worktree tree. .gitignore is not consulted (env files are normally gitignored, which is the point), but a .envsyncignore file at the primary root is. A file that doesn't exist at the destination is copied. A file that's byte-identical is skipped silently. A file that differs is skipped with a warning and a one-line diff summary, unless --force is given.

Writes are atomic: each file is written to <dest>.envsync.tmp then renamed over the destination. Mode bits (including the executable bit) are preserved; mtimes are not, so a synced file's timestamp tells you when it was synced.

sync must run from a linked worktree — it refuses to run from the primary itself, and refuses on bare repositories.

git env sync [--dry-run] [--force] [--verbose | --quiet]
             [--pattern <glob>]... [--path <subdir>]
Flag Short Meaning
--dry-run -n Print what would happen; change nothing.
--force -f Overwrite local files that differ from the primary, backing up the previous content first.
--verbose -v Print every file considered, including skips.
--quiet -q Suppress non-error output.
--pattern <glob> Override configured patterns for this run. Repeatable.
--path <subdir> Restrict the sync to a subdirectory of the worktree.

--verbose and --quiet are mutually exclusive.

Exit codes

Code Meaning
0 Success, or dry-run with nothing to change.
1 Sync completed but one or more files were skipped due to conflicts.
2 Refused to run (not a git worktree, bare repo, invoked from the primary worktree, or the primary has uncommitted changes to tracked env files).
3 Usage error (bad flag, unknown or reserved subcommand).
4 I/O error while copying.

These codes are part of the contract — scripts can rely on them.

Configuration

All keys live under env.sync.* and are read with standard git config precedence (system → global → local → worktree):

Key Type Default Meaning
env.sync.patterns multi-value .env Globs to sync. Multi-value, so additional git config --add calls append rather than replace.
env.sync.exclude multi-value .env.example, .env.sample, .env.template Patterns never synced, even if they match patterns (typically committed templates).
env.sync.followSymlinks bool false Follow symlinked env files instead of skipping them.
env.sync.maxFileSize int (bytes) 1048576 Files larger than this are skipped with a warning.
env.sync.onConflict enum skip skip, overwrite, or prompt.
env.sync.backup bool true Whether --force writes a <dest>.envsync.bak backup before overwriting.

Set per-repo in the primary worktree's .git/config, or per-worktree in that worktree's own config:

git config env.sync.onConflict overwrite
git config --add env.sync.patterns ".env.local"

.envsync

An optional key=value file at the primary worktree root, for pinning patterns into version control so the whole team gets the same defaults without everyone running git config. Same keys as above, minus the env.sync. prefix:

patterns=.env
exclude=.env.example
followSymlinks=false

Repeated keys accumulate (for multi-value settings). git config values, if set, always take precedence over .envsync.

.envsyncignore

A gitignore-syntax file at the primary worktree root. Paths it matches are excluded from sync regardless of env.sync.patterns — use it to opt a specific file or directory out without changing the glob patterns themselves.

Shell completion

git env --install-completions bash   # print a snippet for your rc file
git env --install-completions zsh --write   # install the completion file directly
git env --install-completions fish

Supported shells: bash, zsh, fish. Without --write, the command prints what to add to your shell config; with --write, it installs the completion file to a standard location for that shell.

FAQ

Why not just symlink the env files instead? A symlink means there's only ever one copy, so editing the file in a linked worktree edits the primary too — that defeats the purpose of having isolated worktrees in the first place (e.g. running two branches with different API keys or feature flags side by side). git env sync gives each worktree its own independent copy, seeded from the primary, that you can then diverge from intentionally.

Does this work with bare repositories? No. git env sync requires a primary worktree with a real working tree to copy from. Bare repos are detected and rejected with exit code 2.

What about secrets in env files? git env sync only ever copies bytes between worktrees on your local filesystem — it doesn't transmit, log, or store file contents anywhere else, and it never touches git history (env files are normally gitignored and stay that way). The usual rules still apply: don't commit secrets, and be mindful that --force backups (<dest>.envsync.bak) leave a second copy of the previous content on disk.

Can I sync changes back from a worktree to the primary? Not yet. sync is one-way (primary → linked). A git env push for the reverse direction is planned but not implemented in v1 — see Limitations.

Limitations

  • One-way sync only. git env sync copies primary → linked. There is no bidirectional sync in v1; pushing changes from a linked worktree back to the primary isn't supported yet.
  • Submodules aren't traversed. Env files inside submodules are not discovered or synced.
  • Single primary per invocation. The tool assumes one primary worktree and doesn't support syncing between two linked worktrees directly.
  • No format parsing. Env files are treated as opaque bytes; git env doesn't understand KEY=VALUE syntax, so it can't merge or diff values semantically — only whole-file conflict detection.
  • --porcelain is reserved but not implemented. Passing it is a usage error in v1, by design, so scripts don't silently depend on output that may change later.

push, diff, status, list, edit, and check are reserved for future official subcommands and will error if invoked, so a third-party git-env-<name> script doesn't collide with them later.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

git_env-0.4.0.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

git_env-0.4.0-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

File details

Details for the file git_env-0.4.0.tar.gz.

File metadata

  • Download URL: git_env-0.4.0.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for git_env-0.4.0.tar.gz
Algorithm Hash digest
SHA256 0029918b5174e88e1212ce72c8b474ddca962d1149238d027465664595ea0963
MD5 1f128e3c14ea84485fb312ee41000487
BLAKE2b-256 e5f54fde05f52baa8130c88abfab470b823b8ddee04572a03ff5bafc8bb3b8d6

See more details on using hashes here.

File details

Details for the file git_env-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: git_env-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 22.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for git_env-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e2dce30076e66a1b5f808d558f161d3f8012bc4a6192b3b8cdc7974a3318bb0
MD5 4a03b933413f92950d274adc3bcec2c1
BLAKE2b-256 b58c0b2004beb914dcea80d813fd30efdbeabf6b57877161126e171ff5d5f111

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page