起因
每个项目都有一堆需要跑的命令:测试、lint、构建、迁移、部署。
用 npm script 写 → 只适合 Node 项目;写在 README → 复制粘贴慢;
用 Makefile → tab 缩进诡异、.PHONY 麻烦、shell quoting 各种坑、
Windows 上 make 不一定有。
just 是 Rust 写的命令运行器,专为"项目级 task runner"设计,
没有 make 的历史包袱。
安装
# macOS
brew install just
# Debian / Ubuntu
sudo apt install just # Ubuntu 24.04+
# 或下载二进制
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh \
| bash -s -- --to /usr/local/bin
# Windows
scoop install just
just --version
justfile 例
放在项目根目录 justfile(无后缀):
# 默认 recipe(just 不带参数时跑)
default: list
# 列所有 recipe
list:
@just --list
# 测试
test:
pytest -x
# 跑某个测试
test-one TEST:
pytest -x -v {{TEST}}
# 启动开发服务器
dev:
uvicorn app.main:app --reload
# Lint + format
lint:
ruff check .
mypy src/
fmt:
ruff format .
ruff check --fix .
# 跑数据库迁移
migrate:
alembic upgrade head
migrate-create MESSAGE:
alembic revision --autogenerate -m "{{MESSAGE}}"
# 多步组合
ci: lint test
@echo "✅ all green"
# 部署到生产
deploy ENV='staging':
@echo "Deploying to {{ENV}}"
./scripts/deploy.sh {{ENV}}
# 用 docker 构建镜像
build VERSION:
docker build -t myapp:{{VERSION}} .
docker tag myapp:{{VERSION}} myapp:latest
# 清理
clean:
rm -rf dist build .pytest_cache .ruff_cache __pycache__
just # 同 `just default`
just test
just test-one tests/test_user.py::test_create
just migrate-create "add email field"
just ci
just deploy prod
与 Makefile 对比
# Makefile
.PHONY: test lint deploy
test:
pytest -x
lint:
ruff check .
mypy src/
deploy:
@echo "Deploying"
./scripts/deploy.sh $(ENV)
make test
make deploy ENV=prod # 注意要写 ENV=prod,just 是位置参数 deploy prod
just 的胜出:
- 不需要 .PHONY(recipe 永远跑)
- 不需要 tab(空格即可,4 / 2 都行)
- 命令默认 echo(不需要
@) - 多行字符串 / heredoc 简单
- 参数语法直接(位置 + 默认值)
- 跨平台(Windows / Linux / Mac 一致)
高级特性
多 shell
# 默认 sh -cu
hello:
echo "from sh"
# 用 bash
[shell: bash]
fancy:
echo $BASH_VERSION
arr=(1 2 3); echo "${arr[@]}"
# 用 python
[shell: python]
math:
print(2 ** 10)
# 用 powershell
[shell: pwsh -c]
greet:
Write-Host "from PowerShell"
跨平台条件
[unix]
clean:
rm -rf build/
[windows]
clean:
Remove-Item -Recurse -Force build/
依赖
build: lint test
cargo build --release
release VERSION: build
git tag v{{VERSION}}
git push origin v{{VERSION}}
just release 1.2.3 → 自动先跑 build → build 先跑 lint + test。
变量
version := `git describe --tags --always`
docker_repo := "ghcr.io/myorg/myapp"
build:
docker build -t {{docker_repo}}:{{version}} .
docker push {{docker_repo}}:{{version}}
env 读 .env
set dotenv-load
dev:
echo "Connecting to $DATABASE_URL"
set dotenv-load 让 just 自动读 .env。
分组
[group('test')]
test-unit:
pytest tests/unit
[group('test')]
test-e2e:
playwright test
[group('deploy')]
deploy-staging:
./deploy.sh staging
just --list --groups
# test:
# test-unit
# test-e2e
# deploy:
# deploy-staging
private recipes
[private]
_setup:
pip install -r requirements.txt
dev: _setup
flask run
_ 开头 = private(不出现在 just --list),但能被依赖。
嵌套 justfile
monorepo 里每个子目录一个 justfile:
myapp/
├── justfile # 顶层(全局 recipe)
├── backend/
│ └── justfile # backend 特定
└── frontend/
└── justfile # frontend 特定
顶层调用子项目:
test-all:
just backend/test
just frontend/test
或者用 just --justfile 指定:
just --justfile backend/justfile test
just -f backend/justfile test # 简写
tab 补全
# bash
just --completions bash > /usr/local/etc/bash_completion.d/just
# zsh
just --completions zsh > ~/.zsh/completions/_just
# fish
just --completions fish > ~/.config/fish/completions/just.fish
之后 tab 补全所有 recipe 名 + 参数。
与 CI
GitHub Actions:
- uses: extractions/setup-just@v2
- run: just ci
效果
- 新人 clone 仓库 →
just --list一眼看到所有可用命令 - README 不再充满"how to run tests / lint / deploy",一句"see justfile"
- Makefile 时代的 tab/space 翻车问题归零
- 跨平台一致,Windows 同事不再单独写 .ps1 脚本
踩过的坑
-
recipe 名带
_、-:just 都支持,但 shell tab 补全有时不识别。
recipe 名优先短 + 不带_。 -
不在 git 根:默认 just 在当前目录找 justfile。子目录里跑根的
recipe 需要cd上去或just -f ../justfile recipe。just也支持
.justfile(隐藏)让 ls 不见。 -
shell 退出码处理:单条 recipe 里某命令失败默认整个 recipe 停。
要继续:-前缀(同 make):
just deploy: -kill -9 $(pidof oldservice) systemctl start newservice -
变量
$varvs{{var}}:$var是 shell 变量(运行时展开),
{{var}}是 just 变量(justfile 解析时展开)。混了会报错。 -
CI 装 just 加二进制 cache:每次 CI build 都装一次浪费时间,
extractions/setup-justaction 自带 cache。
登录后参与评论。