- name
- commit-changes
- description
- Guide for committing changes in the torrust-tracker project. Covers conventional commit format, pre-commit verification checklist, GPG signing, and commit quality guidelines. Use when committing code, running pre-commit checks, or following project commit standards. Triggers on "commit", "commit changes", "how to commit", "pre-commit", "commit message", "commit format", or "conventional commits".
- metadata
- {"author":"torrust","version":"1.0"}
# Committing Changes
This skill guides you through the complete commit process for the Torrust Tracker project.
## Quick Reference
```bash
# One-time setup: install the pre-commit Git hook
./contrib/dev-tools/git/install-git-hooks.sh
# Stage changes
git add <files>
# Commit with conventional format and GPG signature (MANDATORY)
# The pre-commit hook runs ./contrib/dev-tools/git/hooks/pre-commit.sh automatically
git commit -S -m "<type>[(<scope>)]: <description>"
```
## Conventional Commit Format
We follow [Conventional Commits](https://www.conventionalcommits.org/) specification.
### Commit Message Structure
```text
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
Scope should reflect the affected package or area (e.g., `tracker-core`, `udp-protocol`, `ci`, `docs`).
### Commit Types
| Type | Description | Example |
| ---------- | ------------------------------------- | ------------------------------------------------------------ |
| `feat` | New feature or enhancement | `feat(tracker-core): add peer expiry grace period` |
| `fix` | Bug fix | `fix(udp-protocol): resolve endianness in announce response` |
| `docs` | Documentation changes | `docs(agents): add root AGENTS.md` |
| `style` | Code style changes (formatting, etc.) | `style: apply rustfmt to all source files` |
| `refactor` | Code refactoring | `refactor(tracker-core): extract peer list to own module` |
| `test` | Adding or updating tests | `test(http-tracker-core): add announce response tests` |
| `chore` | Maintenance tasks | `chore: update dependencies` |
| `ci` | CI/CD related changes | `ci: add workflow for container publishing` |
| `perf` | Performance improvements | `perf(torrent-repository): switch to dashmap` |
## GPG Commit Signing (MANDATORY)
**All commits must be GPG signed.** Use the `-S` flag:
```bash
git commit -S -m "your commit message"
```
### Restricted Agent Sandboxes
Some agent sandboxes cannot write hook logs to `/tmp` and can invoke Git hooks
with a `PATH` that does not resolve the Rust toolchain. Preserve GPG signing and
explicitly restore Cargo's conventional installation directory while writing
hook logs inside the workspace:
```bash
PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" \
TORRUST_GIT_HOOKS_LOG_DIR=.tmp \
git commit -S -m "<type>(<scope>): <description>"
```
The repository hook also tries to restore Cargo. First validate with the same
`PATH` and `TORRUST_GIT_HOOKS_LOG_DIR` variables by running the pre-commit script
directly. If Git still launches the hook without usable Cargo in the restricted
agent sandbox, rerun the signed `git commit` outside that sandbox; do not bypass
the hook or signing. This workaround keeps hook logs in the git-ignored workspace
`.tmp/` directory and does not alter the checks or replace normal developer setup.
### One Signed Commit per Step
Run each signed commit as its own step, and check its result (the exit status, and
`git log -1 --format=%G?`) before staging or committing anything else. Never chain a commit with
a later `git add` or `git commit` in one command using `;` or newlines: if the signature fails, its
changes stay staged and the next commit sweeps them in. In issue #2505 a commit failed with a GPG
timeout, and the next commit, issued in the same command, swept the staged rename into an unrelated
docs commit.
### GPG Timeout Handling
If the GPG passphrase prompt times out (`gpg: signing failed: Timeout`), the agent **must**:
1. **Stop the failed attempt immediately.** Do not use `--no-gpg-sign` or skip signing.
2. **Notify the user** that the passphrase prompt timed out and offer these choices:
- retry the same signed commit manually; or
- have the agent retry the same `git commit -S` command while the user enters the passphrase
directly in the terminal prompt.
1. **Wait for the user's choice.** Do not retry automatically. If the user requests an
agent-assisted retry, invoke only the same signed commit command and allow the user to provide
the passphrase; never receive, request, or handle the passphrase in chat.
This rule is absolute. Never bypass GPG signing for any reason.
## Pre-commit Verification (MANDATORY)
### Git Hook
The repository ships a `pre-commit` Git hook that runs `./contrib/dev-tools/git/hooks/pre-commit.sh`
automatically on every `git commit`. Install it once after cloning:
```bash
./contrib/dev-tools/git/install-git-hooks.sh
```
Once installed, the hook fires on every commit and you do not need to run the script manually.
### Automated Checks
If the hook is not installed, run the script explicitly before committing.
**It must exit with code `0`.**
> **⏱️ Expected runtime: ~1 minute** on a modern developer machine with warm caches.
> AI agents should set a command timeout of **at least 3 minutes** before invoking this script.
> AI agents should also set `TORRUST_GIT_HOOKS_LOG_DIR=.tmp` so per-step log files
> are written inside the workspace (git-ignored) instead of `/tmp`.
```bash
TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh
```
The script runs:
1. `cargo machete` — unused dependency check
2. `linter all` — all linters (markdown, lychee local links, YAML, TOML, clippy, rustfmt, shellcheck, cspell)
3. `cargo test --doc --workspace` — documentation tests
For AI execution, prefer structured output first:
```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=json
```
If it fails and deeper diagnostics are needed, retry with:
```bash
./contrib/dev-tools/git/hooks/pre-commit.sh --format=text --verbosity=verbose
```
When the hook is not installed, this script is the only gate, so make the commit depend on the
script's own exit status. Never pipe its output into another command (for example a JSON parser)
whose exit status replaces the script's: a failed check would then no longer block the commit.
```bash
TORRUST_GIT_HOOKS_LOG_DIR=.tmp ./contrib/dev-tools/git/hooks/pre-commit.sh --format=json \
> .tmp/pre-commit.json && git commit -S -m "<type>(<scope>): <description>"
```
### Manual Checks (Cannot Be Automated)
Verify these by hand before committing:
- **Self-review the diff**: read through `git diff --staged` and check for obvious mistakes,
debug artifacts, or unintended changes
- **Documentation updated**: if public API or behaviour changed, doc comments and any relevant
`docs/` pages reflect the change
- **`AGENTS.md` updated**: if architecture, package structure, or key workflows changed, the
relevant `AGENTS.md` file is updated
- **New technical terms added to `project-words.txt`**: run
`./contrib/dev-tools/git/format-project-words.sh` after adding jargon or identifiers that cspell
does not know. The pre-commit hook does this automatically, aborting for deliberate restaging if
it changes the dictionary.
### Debugging a Failing Run
```bash
linter markdown # Markdown
linter yaml # YAML
linter toml # TOML
linter clippy # Rust code analysis
linter rustfmt # Rust formatting
linter shellcheck # Shell scripts
linter cspell # Spell checking
```
Fix Rust formatting automatically:
```bash
cargo fmt
```
## Hashtag Usage Warning
**Only use `#` when intentionally referencing a GitHub issue.**
GitHub auto-links `#NUMBER` to issues. Avoid accidental references:
- ✅ `feat(tracker-core): add feature (see #42)` — intentional reference
- ❌ `fix: make feature #1 priority` — accidentally links to issue #1
Use ordered Markdown lists or plain numbers instead of `#N` step labels.
## Commit Quality Guidelines
### Good Commits (✅)
- **Atomic**: Each commit represents one logical change
- **Descriptive**: Clear, concise description of what changed
- **Tested**: All tests pass
- **Linted**: All linters pass
- **Conventional**: Follows conventional commit format
- **Signed**: GPG signature present
### Commits to Avoid (❌)
- Too large: multiple unrelated changes in one commit
- Vague messages like "fix stuff" or "WIP"
- Missing scope when a package is clearly affected
- Unsigned commits
GitHub에서 보기