Anvil
_ _
(_) |
__ _ _ ____ ___| |
/ _` | '_ \ \ / / | |
| (_| | | | \ V /| | |
\__,_|_| |_|\_/ |_|_|
Create isolated multi-repository workspaces for engineering tasks.
Installation
From PyPI (the published package is still named git-anvil):
uv tool install git-anvil
From GitHub:
uv tool install git+https://github.com/felixscherz/anvil
Both methods install the anvil command. The PyPI package keeps its existing distribution name because anvil belongs to another project.
Getting started
Create a workspace
Provide a target directory and one or more repository specifiers. Each specifier can be a local path to an existing Git repository or any remote URL accepted by git clone.
anvil create --target /tmp/workspaces/feature-abc \
~/repos/my-service \
git@github.com:org/other-service.git
To override the inferred branch name, pass --branch (-b):
anvil create --target /tmp/workspaces/feature-abc --branch my-feature \
~/repos/my-service
Anvil will:
- Infer the branch name from the target directory name (
feature-abc), or use the value of--branchwhen provided. - For local paths — create a
git worktreeon a new branch at the tip of the default branch. - For remote URLs — clone the repository and check out a new branch.
- Write a manifest to
/tmp/workspaces/feature-abc/.anvil/manifest.json. - Write an
AGENTS.mdat the workspace root describing the workspace layout for coding agents. It points to.anvil/manifest.jsonas the source of truth for the current repositories, and is removed onclean. - Record the workspace in the nearest dedicated
.anvil/workspaces.jsoninventory.
Example output:
Creating Anvil workspace: /tmp/workspaces/feature-abc
Branch: feature-abc
+ my-service -> /tmp/workspaces/feature-abc/my-service
+ other-service -> /tmp/workspaces/feature-abc/other-service
Created Anvil workspace: /tmp/workspaces/feature-abc
Branch: feature-abc
- my-service -> /tmp/workspaces/feature-abc/my-service
- other-service -> /tmp/workspaces/feature-abc/other-service
Clean up a workspace
anvil clean /tmp/workspaces/feature-abc
anvil remove is an alias for anvil clean. Both remove the workspace from workspaces.json after cleanup.
If you are inside the workspace (or any subdirectory of it), the path can be omitted - Anvil walks up from the current directory until it finds an .anvil/manifest.json:
cd /tmp/workspaces/feature-abc
anvil clean
Anvil reads the manifest, prints a summary, and prompts for confirmation before removing everything.
Anvil workspace: /tmp/workspaces/feature-abc
Branch: feature-abc
Repositories (2):
- my-service (worktree) -> /tmp/workspaces/feature-abc/my-service
- other-service (clone) -> /tmp/workspaces/feature-abc/other-service
Remove Anvil workspace at /tmp/workspaces/feature-abc containing 2 repositories? [y/N]
Skip the prompt with --yes:
anvil clean /tmp/workspaces/feature-abc --yes
Add a repository to an existing workspace
anvil add --target /tmp/workspaces/feature-abc ~/repos/another-service
Or, from anywhere inside the workspace:
cd /tmp/workspaces/feature-abc
anvil add ~/repos/another-service
Anvil reads the branch name from the existing manifest (feature-abc) and creates the new repository on that same branch. The manifest is updated in place with the new entry appended. Rollback applies only to repos added in the current run - existing workspace members are untouched. clean and run likewise discover the workspace from the current directory when the workspace path / --workspace is omitted.
List workspaces
Create a dedicated .anvil directory in a parent of your workspaces, then run anvil list from anywhere beneath it:
mkdir -p /tmp/workspaces/.anvil
anvil list
Anvil walks upward from the current directory to find the nearest dedicated .anvil directory. A workspace's own .anvil/manifest.json directory is skipped. If there is no dedicated directory, Anvil uses ~/.config/anvil/workspaces.json. For create, add, and remove, inventory selection starts at the workspace's parent directory, so explicit workspace paths update the inventory that contains them. The file records each workspace path, branch, and repository names; add refreshes its entry.
Notes
- The branch name is derived from the basename of
--target./tmp/workspaces/feature-abc→feature-abc. Pass--branch/-bto override it; the value is sanitized the same way as the inferred name. anvil addreads the branch name from the existing manifest - the target directory name is irrelevant.add,clean, andruninfer the workspace by walking up from the current directory when the workspace path /--target/--workspaceis omitted.createalways requires--targetbecause it creates a new workspace.- The same branch name is created in every repository in the workspace - this is expected and correct.
- If any repository fails during
createoradd, Anvil rolls back only the repos created in that run. - Anvil will refuse to proceed if the target is non-empty, if a derived branch already exists, or if two repositories share the same derived name.
Metadata
Release files for git-anvil 0.4.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_anvil-0.4.0.tar.gz | 46.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| git_anvil-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 68.2 kB
Release files / git_anvil-0.4.0.tar.gz
| Download URL | git_anvil-0.4.0.tar.gz |
|---|---|
| Size | 46.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f88b87646933dc5a1c589a8d6e2071575b92d1d880a5a3948f0c40acc959686e
|
|
BLAKE2b-256 checksum How to use checksums |
4394edcfd961ce3601e7e83496c1eca70cf67dea885453acd92fe29cb311f6d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / git_anvil-0.4.0-py3-none-any.whl
| Download URL | git_anvil-0.4.0-py3-none-any.whl |
|---|---|
| Size | 21.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75ebb2a9943a70e192ef155eaba2426041bc69babdbbe4dce6c19dab5efc44de
|
|
BLAKE2b-256 checksum How to use checksums |
f708c096a0126e243bf6f7c9c0a2278747e793a5a7c83a67826e17d137d045c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|