Logo

Cheatsheets

Una colección de comandos que vale la pena tener cerca cuando toca construir, mantener o rescatar un sistema.

01 / build & ship

Development

Comandos de trabajo diario para código, datos y contenedores.

Development Cheatsheet

Common commands for Rust, Node/pnpm, Python, databases, Docker and Git.


Git, SSH and Repository Access

SSH keys (ed25519 is the current default; use one key per machine):

ssh-keygen -t ed25519 -C "you@example.com"      # generate a key (~/.ssh/id_ed25519)
cat ~/.ssh/id_ed25519.pub                       # copy this into GitHub/GitLab > SSH keys
ssh-add ~/.ssh/id_ed25519                       # load it into the agent
ssh-add -l                                      # list loaded keys

Verify the host key and that authentication actually works:

ssh -T git@github.com                 # "Hi <user>! You've successfully authenticated"
ssh -T git@gitlab.com                 # "Welcome to GitLab, @<user>!"
ssh -T -p 443 git@ssh.github.com      # GitHub over port 443 (when 22 is blocked)
ssh -vT git@github.com                # verbose, to debug which key is offered

Check that a repository is reachable, and whether you have push rights, without changing anything:

git ls-remote origin                  # server-side refs: proves fetch+auth and the URL
git ls-remote --heads origin          # branches only
git ls-remote git@github.com:user/repo.git   # check a URL before adding it
git fetch --dry-run                   # fetch without updating local refs
git push --dry-run origin main        # talks to the server: fails if you lack push access

Remotes and identity:

git remote -v                                     # current fetch/push URLs
git remote show origin                            # branches, tracking, push permissions
git remote set-url origin git@github.com:user/repo.git   # switch HTTPS <-> SSH
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global credential.helper manager     # cache HTTPS credentials (Windows)

CLI auth for the hosting platforms:

gh auth login                 # GitHub CLI (HTTPS or SSH)
gh auth status                # which account/token is active
gh repo view user/repo        # confirms read access
glab auth login               # GitLab CLI
glab auth status

HTTPS needs a token (GitHub: fine-grained PAT with contents:write; GitLab: PAT with write_repository); SSH needs your public key registered. Both git ls-remote (read) and git push --dry-run (write) returning success is the full access check.

Common failure: Permission denied (publickey) means the key is missing or not registered; Repository not found over HTTPS usually means the token lacks scope or the URL/user is wrong.

Normalize text files to LF so Windows checkouts stop rewriting them. Add to .gitattributes:

* text=auto eol=lf
git config core.autocrlf false
git config core.safecrlf false
git add --renormalize .      # stage existing files with the new line endings
git status
git add .gitattributes
git commit -m "chore: standardize line endings"

Git LFS for large binary files:

sudo apt-get install git-lfs
git lfs install
git lfs pull                # download images stored in LFS
git lfs ls-files            # list tracked files

Rust (cargo)

Day-to-day basics for a Rust/Axum backend and working with crates.

cargo build                  # compile in debug
cargo build --release        # compile optimized
cargo run                    # compile and run
cargo run --release -- arg1  # pass arguments to the binary after --
cargo check                  # type-check without producing a binary (fast)
cargo test                   # run all tests
cargo test name -- --nocapture   # a single test, showing println!
cargo clippy                 # linter
cargo clippy -- -D warnings  # fail on warnings (useful in CI)
cargo fmt                    # format code
cargo fmt --check            # only verify formatting (CI)

Dependencies and maintenance:

cargo add axum tokio -F tokio/full   # add a dependency (with features)
cargo remove name                    # remove a dependency
cargo update                         # update Cargo.lock
cargo tree                           # dependency tree
cargo tree -d                        # duplicates only
cargo clean                          # delete target/
cargo doc --open                     # build and open documentation
cargo install cargo-watch            # install tools
cargo watch -x run                   # rebuild and restart on save
cargo audit                          # known vulnerabilities (needs cargo-audit)
cargo expand                         # expanded macros (needs cargo-expand)

Publishing to crates.io:

cargo login                  # crates.io token (once)
cargo package --list         # which files will be included
cargo publish --dry-run      # simulate publishing
cargo publish                # publish (irreversible; versions can only be yanked)
cargo yank --version 0.1.1   # stop new projects from depending on a version

With SQLx (for PostgreSQL):

cargo install sqlx-cli
sqlx migrate add name        # create a migration
sqlx migrate run             # apply it
cargo sqlx prepare           # generate cache for offline builds

Node / pnpm

Use when working with frontend projects using PNPM as package manager.

pnpm install                 # install dependencies (whole workspace)
pnpm install --frozen-lockfile   # require the lockfile to match (CI)
pnpm add zod                 # add a dependency
pnpm add -D vitest           # add as a devDependency
pnpm add -w typescript       # add at the workspace root
pnpm remove zod              # remove a dependency
pnpm update --latest         # update to the latest versions
pnpm dev                     # run the "dev" script
pnpm build                   # run the "build" script
pnpm run <script>            # any package.json script
pnpm dlx <package>           # run a package without installing it (like npx)
pnpm outdated                # outdated dependencies
pnpm why <package>           # why a package is installed
pnpm store prune             # clean the global store

Change into different workspaces (monorepos):

pnpm -r build                       # run build in every package
pnpm -r --parallel dev              # run dev everywhere in parallel
pnpm --filter admin dev             # only the "admin" package
pnpm --filter public build          # only the "public" package
pnpm --filter admin... build        # admin and its internal dependencies
pnpm --filter ...shared build       # shared and everything that depends on it
pnpm --filter admin add zod         # add a dependency to one package
pnpm -F admin exec <command>        # run a binary inside a package

Vite, SvelteKit and tests:

pnpm vite                    # dev server
pnpm vite build              # production build
pnpm vite preview            # serve the build locally
pnpm svelte-kit sync         # generate SvelteKit types
pnpm svelte-check            # type and a11y checks for .svelte files
pnpm svelte-check --watch
pnpm vitest                  # tests in watch mode
pnpm vitest run              # single pass (CI)
pnpm vitest run src/tests/search.test.ts   # one file
pnpm vitest -t "multiartist" # filter by test name
pnpm vitest run --coverage   # coverage

Python

For FastAPI services, scripts and CLI tools.

Virtual environments with venv and pip:

python -m venv .venv                 # create the environment
source .venv/bin/activate            # activate (Linux/macOS)
.venv\Scripts\Activate.ps1           # activate (PowerShell on Windows)
deactivate                           # leave the environment
pip install -r requirements.txt      # install dependencies
pip install --upgrade pip
pip freeze > requirements.txt        # pin versions
pip list --outdated                  # outdated packages
pip show <package>                   # package info
pip install torch --index-url https://download.pytorch.org/whl/cpu   # CPU-only PyTorch (small Docker image)

With uv (faster, replaces venv + pip):

uv venv                      # create .venv
uv pip install -r requirements.txt
uv init                      # new project with pyproject.toml
uv add fastapi uvicorn       # add dependencies to the project
uv sync                      # install according to uv.lock
uv run python tagger.py      # run inside the environment
uv run pytest
uv python install 3.12       # install a Python version

FastAPI with uvicorn:

uvicorn main:app --reload                       # development with auto-reload
uvicorn main:app --host 0.0.0.0 --port 8000     # reachable from the network/container
uvicorn main:app --workers 2                    # multiple processes (simple production)
fastapi dev main.py                             # FastAPI CLI alternative

Tests and code quality:

pytest                       # run all tests
pytest -v                    # verbose
pytest -x                    # stop at the first failure
pytest -k "genre"            # filter by name
pytest tests/test_db.py::test_insert   # a specific test
pytest -s                    # show print()
pytest --lf                  # only the ones that failed last time
pytest --cov=. --cov-report=term-missing   # coverage (pytest-cov)
ruff check .                 # linter
ruff format .                # formatter
python -m pip install -e .   # install the project in editable mode

Databases

SQLite for local/self-hosted services; PostgreSQL for the main backend.

sqlite3 (dot-commands are typed inside the sqlite3 shell):

sqlite3 app.db                       # open (or create) the database
sqlite3 app.db "SELECT COUNT(*) FROM tracks;"   # direct query
sqlite3 app.db < migrations/v3.sql              # run a script
sqlite3 -header -column app.db "SELECT * FROM albums LIMIT 5;"
sqlite3 app.db ".backup backup.db"              # consistent backup
sqlite3 app.db ".dump" > dump.sql               # export as SQL
.tables                      -- list tables
.schema tracks               -- schema of a table
.headers on
.mode column                 -- readable output (also: csv, json)
.read migrations/v3.sql      -- run a file
.quit
PRAGMA foreign_keys = ON;    -- enable foreign keys (per connection)
PRAGMA journal_mode = WAL;   -- better read/write concurrency
PRAGMA integrity_check;      -- verify the database
PRAGMA user_version;         -- schema version
VACUUM;                      -- compact the file
EXPLAIN QUERY PLAN SELECT ...;   -- check whether indexes are used

psql and PostgreSQL:

psql -h localhost -U user -d dbname            # connect
psql "postgresql://user:password@host:5432/db"  # with a connection URL
psql -d db -f schema.sql                       # run a file
psql -d db -c "SELECT now();"                  # a single command
\l             -- list databases
\c dbname      -- switch database
\dt            -- list tables
\d products    -- describe a table
\di            -- indexes
\du            -- roles/users
\x             -- expanded output (toggle)
\timing        -- show the duration of each query
\copy products TO 'products.csv' CSV HEADER   -- client-side export
\q             -- quit

Backups with pg_dump and restore:

pg_dump -U user -d db > backup.sql                   # plain SQL
pg_dump -U user -Fc -d db -f backup.dump             # custom format (compressed)
pg_dump -U user -d db --schema-only > schema.sql     # schema only
pg_dump -U user -d db -t products > products.sql     # one table
pg_dumpall -U postgres > everything.sql              # all databases + roles
psql -d db < backup.sql                              # restore plain SQL
pg_restore -U user -d db --clean backup.dump         # restore custom format

Docker

For building and shipping services:

docker build -t myapp:latest .                  # build the image
docker build -t myapp:cpu -f Dockerfile.cpu .
docker build --no-cache -t myapp .              # without cache
docker run --rm -p 8000:8000 myapp              # run and map a port
docker run -d --name app -p 8000:8000 --env-file .env myapp   # in the background
docker run --rm -it myapp bash                  # shell inside the image
docker run -v ${PWD}/data:/data myapp           # mount a folder
docker ps                                       # running containers
docker ps -a                                    # all, including stopped
docker logs -f app                              # follow logs
docker logs --tail 100 app
docker exec -it app bash                        # enter a running container
docker stop app && docker rm app                # stop and remove

Image size and analysis (useful when shrinking images):

docker image ls                      # list images with their size
docker image ls myapp                # only one repository
docker history myapp                 # size of each layer
docker image inspect myapp --format '{{.Size}}'
docker image rm myapp:old            # delete an image
docker image prune                   # delete untagged images
docker system df                     # Docker disk usage
docker system prune -a --volumes     # aggressive cleanup (careful)

Docker Compose:

docker compose up                    # start the services
docker compose up -d --build         # in the background, rebuilding
docker compose down                  # stop and remove
docker compose down -v               # also delete volumes (deletes data)
docker compose ps
docker compose logs -f api           # logs of one service
docker compose exec api bash         # shell in a service
docker compose restart api
docker compose pull                  # update images
docker compose config                # validate and print the final config

Registries and moving images between machines:

gcloud auth configure-docker us-central1-docker.pkg.dev
docker tag myapp us-central1-docker.pkg.dev/PROJECT/REPO/myapp:v1
docker push us-central1-docker.pkg.dev/PROJECT/REPO/myapp:v1
docker pull nginx:alpine
docker save -o myapp.tar myapp       # export an image to a file
docker load -i myapp.tar             # import it

Cloudflared

Credentials and configuration:

cat /root/.cloudflared/<tunnel-uuid>.json    # tunnel credentials
cat /etc/cloudflared/config.yml              # config file

Ingress rules and DNS records:

cloudflared tunnel ingress validate
cloudflared tunnel ingress rule https://www.website.com
cloudflared tunnel route dns --overwrite-dns <tunnel-uuid> www.website.com

Restart the service:

systemctl restart cloudflared
journalctl -u cloudflared -n 20 --no-pager

Nginx

cat /etc/nginx/sites-available/app1        # edit a site config
nginx -t && systemctl restart nginx        # validate and restart