Share your repositories' configuration, and keep it in sync without losing local edits.
Getting Started · Manual · Profiles · Changelog
A profile is a folder of configuration in a git repository: formatter settings, lint rules, CI workflows, whatever your repositories share. devset applies it to a repository, records what it wrote, and later brings in the profile's changes while keeping the repository's own edits. atxp, provided by Atomix Labs, is a collection to start from; anyone can keep a collection of their own the same way.
curl --proto '=https' --tlsv1.2 -fsSL https://atomix-labs.github.io/devset/install.sh | shA static binary for Linux, on x86-64 and Arm, or for macOS on Apple silicon, checked against its release's checksum and build attestation. Or:
| You use | Install | Upgrade | Uninstall |
|---|---|---|---|
| the installer | the line above | the same line again | the line with sh -s -- --uninstall |
| mise | mise use -g github:atomix-labs/devset |
mise upgrade github:atomix-labs/devset |
mise unuse -g github:atomix-labs/devset |
| cargo-binstall | cargo binstall devset-cli |
the same command | cargo uninstall devset-cli |
| cargo | cargo install --locked devset-cli |
the same command | cargo uninstall devset-cli |
The package is devset-cli, and the binary devset; cargo install builds it
with Rust 1.98 or later. Install has the installer's options, checking a
download, the shell completions, and what uninstalling leaves.
A new Rust project, from atxp's bundle, set up and checked:
mkdir hello && cd hello && git init
devset add atxp/rust --git https://github.com/atomix-labs/atxp --tag v0.20.0 --var repository=you/hello
./setup.sh && just checkA repository that has configuration of its own takes profiles the same way. What
it lacks, a profile writes once and leaves to it; what it has, a profile that
owns part of a file joins, taking only its keys or its block. --dry-run shows
what would change first:
devset add atxp/rust --git https://github.com/atomix-labs/atxp --tag v0.20.0 --dry-runIn CI, fail the build when a file has drifted from its profile:
- run: devset status --exit-codeLater, take the profiles' changes:
devset update --dry-run # names the newer releases of each source
devset update atxp --tag <release> # takes one, merging your edits- It keeps your edits. An update merges three ways against what devset wrote; where the profile and the repository changed the same lines, it stops, and leaves the conflict beside the file for you to resolve, never in it.
- It owns only its part of a file. Some keys of a
Cargo.toml, a block of a.gitignore: the rest of the file stays the repository's. - Profiles compose like crates. A profile requires others by name, and offers features that unify across everything that requires it, as Cargo's do.
- Drift fails CI.
.devset/records what devset wrote, sodevset statustells a local edit from a profile's change, and a reformatted file from an edited one. - It never runs a profile's code. A profile is data: files, and when to write them.
atxp, provided by Atomix Labs, holds profiles for any repository and for Rust
ones, one concern each, with a bundle that takes them: use them, build on them,
or contribute. Or write your own: a profile is a directory with a
profile.toml, which says how devset manages each file and when, and files/,
which holds them as a repository should have them.
[profile]
name = "base"
[files.".editorconfig"] # owned: the profile's, so an edit is drift
[files."deny.toml"]
policy = "merge" # the repository's edits are kept, and mergedProfiles do real work beside copying files: a scaffold writes starter files
where a project has none of its own, and a gate applies an entry only when a
feature is on, another profile is applied, or a file exists. Put them in a git
repository, and any repository takes one with devset add base --git <url> --tag <tag>. Designing Profiles has the craft of it.
Collections others publish carry the GitHub topic
devset-collection. A repository
devset manages may say so with
,
which
Getting Started
gives to copy.
cookiecutter starts a project from a template and leaves it there; copier and cruft also carry a template's later changes into the project. devset is built for that second part: a repository takes many small profiles, from one source or several, each owning whole files, a file's keys, or a block of it, and stays current release by release, with drift from them failing CI. A profile is data, so taking one runs nothing; projen, by contrast, writes its files from code, and owns them whole. Comparison sets devset beside copier, cruft, projen, chezmoi and cargo-generate, row by row.
| I want to | Read |
|---|---|
| try devset on a repository | Getting Started |
| start a new Rust project | A New Rust Project |
| adopt a repository that has its own setup | An Existing Repository |
| write a profile | Write a Profile |
| share profiles across repositories | Share a Team's Configuration |
| publish a collection for others | Publish a Collection |
| take a newer release, or resolve a conflict | Update and Resolve Conflicts |
| check for drift in CI | In CI |
| see how devset differs from similar tools | Comparison |
| look a command or a file's keys up | Command Reference, profile.toml |
| run the examples | examples/ |
| use the library | devset-core on docs.rs |
| know how devset is built | ARCHITECTURE.md |
| move across a breaking change | BREAKING-CHANGES.md |
| report a vulnerability | SECURITY.md |
Issues and pull requests are welcome. To work on devset, fork it, clone your
fork, and run ./setup.sh, which installs mise, every tool devset pins and the
nightly Rust toolchain; install.sh is for using devset, not for developing it.
git clone https://github.com/<you>/devset.git && cd devset
./setup.sh
just check # formatting, lints, tests and the docs, as CI runs themCONTRIBUTING.md has the rest: how a pull request lands, the tests and snapshots, and the style. Report a bug, request a feature, or ask a question in Discussions.
MIT: see LICENSE.