> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Git Conventions

> Learn how Tuturuuu uses Conventional Commits and Branch naming to improve development workflow.

<Info>
  **Prerequisite**: You should be familiar with basic Git operations and
  understand the [Monorepo Architecture](/build/development-tools/monorepo-architecture) of our
  codebase.
</Info>

## Overview

Tuturuuu follows standardized conventions for Git commits and branch naming to improve collaboration, automate releases, and maintain a clean, navigable repository history. We use two main specifications:

1. [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for structured commit messages
2. [Conventional Branch](https://conventional-branch.github.io/) for consistent branch naming

These conventions help automate our CI/CD workflows, generate changelogs, and make our development process more efficient.

## Conventional Commits

### What are Conventional Commits?

Conventional Commits is a specification for adding human and machine-readable meaning to commit messages. It provides a set of rules for creating an explicit commit history, making it easier to write automated tools on top of.

The basic structure of a conventional commit is:

```
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
```

### Types

Tuturuuu uses the following commit types:

| Type       | Description                                     | Example                                          |
| ---------- | ----------------------------------------------- | ------------------------------------------------ |
| `feat`     | New feature or enhancement                      | `feat: add dark mode support`                    |
| `fix`      | Bug fix                                         | `fix: prevent crash when user data is undefined` |
| `docs`     | Documentation changes                           | `docs: update installation instructions`         |
| `style`    | Code style changes (formatting, no code change) | `style: format code with prettier`               |
| `refactor` | Code refactoring                                | `refactor: simplify authentication logic`        |
| `perf`     | Performance improvements                        | `perf: optimize database queries`                |
| `test`     | Add or fix tests                                | `test: add unit tests for auth middleware`       |
| `build`    | Changes affecting build system or dependencies  | `build: update dependency to fix security issue` |
| `ci`       | Changes to CI configuration files and scripts   | `ci: simplify workflow branch filters`           |
| `chore`    | Routine tasks, maintenance                      | `chore: update package.json metadata`            |

### Scopes

Scopes provide additional context about which part of the codebase is affected. In our monorepo structure, we often use package or app names as scopes:

```
feat(web): add new dashboard layout
fix(ui): correct button alignment in mobile view
chore(types): update supabase database types
```

### Breaking Changes

Breaking changes must be indicated by adding a `!` after the type/scope or by using a `BREAKING CHANGE:` footer:

```
feat(api)!: require authentication for all endpoints

BREAKING CHANGE: All API endpoints now require authentication tokens.
```

### Examples

Here are some examples of conventional commits used in our codebase:

```
feat(web): add new calendar integration
fix(supabase): correct permission issue in auth policy
docs(readme): update development setup instructions
style: apply consistent formatting with prettier
refactor(utils): simplify date formatting functions
perf(queries): optimize workspace user loading
test(auth): add tests for token verification
build(deps): update Next.js to v14
ci(vercel): add automatic preview deployments
chore(release): publish packages
```

## Conventional Branches

### What are Conventional Branches?

Conventional Branch refers to a structured naming convention for Git branches that makes it easier to identify branches by type and purpose.

The basic structure is:

```
<type>/<description>
```

### Branch Types

Tuturuuu uses the following branch types:

| Type         | Description                            | Example                         |
| ------------ | -------------------------------------- | ------------------------------- |
| `main`       | Main development branch                | `main`                          |
| `feature`    | For new features                       | `feature/user-dashboard`        |
| `feat`       | Short feature prefix also accepted     | `feat/invite-link-permissions`  |
| `fix`        | Short bug-fix prefix also accepted     | `fix/invite-membership-check`   |
| `bugfix`     | For bug fixes                          | `bugfix/login-error`            |
| `hotfix`     | For urgent fixes                       | `hotfix/security-vulnerability` |
| `release`    | For preparing releases                 | `release/v1.2.0`                |
| `chore`      | For maintenance tasks                  | `chore/update-dependencies`     |
| `docs`       | For documentation-only work            | `docs/git-conventions-refresh`  |
| `style`      | For formatting or stylistic cleanups   | `style/biome-pass`              |
| `refactor`   | For internal code restructuring        | `refactor/task-query-shell`     |
| `perf`       | For performance-focused changes        | `perf/workspace-user-search`    |
| `dependabot` | Automated dependency update branches   | `dependabot/npm_and_yarn/next`  |
| `claude`     | AI-assisted scratch or experimental PR | `claude/rate-limit-audit`       |

Release Please bot branches are also accepted with the
`release-please--branches--` prefix. Do not create human-authored branches with
that prefix.

### Naming Rules

1. Use lowercase alphanumeric characters and hyphens
2. Keep names concise but descriptive
3. Include ticket/issue numbers when applicable
4. Avoid special characters (except hyphens)

### Examples

```
feature/workspace-sharing
feat/public-course-sharing
fix/file-upload-error
bugfix/auth-vulnerability
release/v2.5.0
chore/update-react-18
docs/git-conventions-refresh
feature/issue-123-user-profile
```

### Merge Commit Exception

Authored commits should follow Conventional Commits. The common exception is a
Git-generated merge commit when syncing a long-lived branch, for example:

```bash theme={null}
Merge branch 'main' into feat/studying-platform
```

Keep that merge summary when the goal is to preserve the branch's merge history.
Use a conventional commit message again for the next authored commit after the
merge.

## How These Conventions Improve Our Workflow

### 1. Automated Changelog Generation

Our conventional commits are used to automatically generate changelogs for releases. Different commit types are categorized accordingly:

```markdown theme={null}
# Changelog

## Features

- add dark mode support (#123)
- add calendar integration (#124)

## Bug Fixes

- prevent crash when user data is undefined (#125)

## Documentation

- update installation instructions (#126)
```

### 2. Semantic Versioning

Conventional commits help determine the next semantic version for packages:

* `fix:` commits trigger a PATCH increment (1.0.0 → 1.0.1)
* `feat:` commits trigger a MINOR increment (1.0.0 → 1.1.0)
* Commits with `BREAKING CHANGE` trigger a MAJOR increment (1.0.0 → 2.0.0)

### 3. Automated Release PRs And Package Publishing

Release Please reads Conventional Commits from `production`, updates
`release-please-config.json` packages through `.release-please-manifest.json`,
and opens one combined release PR with package versions and changelogs. Package
publish workflows do not generate versions; they publish only after a
release-please version bump lands on `production`. Local manifests keep
Tuturuuu workspace dependencies as `workspace:*`; npm release workflows rewrite
the checked-out package manifest with
`scripts/ci/prepare-npm-package-manifest.js` immediately before `npm pack` so
published artifacts contain installable npm version ranges. Package-included
`file:` tarball dependencies, such as `@tuturuuu/ui`'s vendored SheetJS tarball,
stay local in the packed manifest and must not be rewritten to mutable external
tarball URLs. Before any build or
pack work starts, package workflows run
`scripts/ci/package-release-readiness.js gate-package-release packages/<name>`.
The gate checks publishable Tuturuuu workspace dependency versions on npm once,
dispatches missing dependency workflows, and exits green without occupying a
runner while dependencies are pending. If the related dependency workflow for
the same production SHA failed, completed successfully without npm visibility,
or cannot be inspected, the gate fails immediately. Publish jobs still wait for
their own version to become visible after `npm publish`, then a separate
non-OIDC job dispatches direct dependent package workflows. Workflow-published
package manifests must carry
provenance-compatible `repository` metadata for `tutur3u/platform`; otherwise
npm rejects trusted publishes with `E422`. For example,
`release-types-package.yaml` triggers from production changes to
`packages/types/package.json`:

When bringing the generated release PR branch back to `main`, run
`bun git-release-please` from a clean `main` checkout. The helper fetches the
latest `release-please--branches--production` branch, merges it without
committing, syncs `platform-version.txt` into the platform badge constant and
test expectation, runs `bun ff`, stages the resolved merge, then runs `bun check`
directly before the merge commit lands. When the staged release merge includes
`apps/mobile` paths, the helper also runs `bun check:mobile`. If you are already
inside a manual merge, run
`bun release:sync-platform-version` to resolve the recurring
`TUTURUUU_PLATFORM_VERSION` conflict before staging the merge.

```yaml theme={null}
on:
  push:
    branches: [production]
    paths:
      - "packages/types/package.json"
  # ...

jobs:
  check-version-bump:
    if: github.ref == 'refs/heads/production' && needs.check-ci.outputs.should_run == 'true'
    # ...
```

### 4. Better Code Reviews

With conventional commits and branches, it's easier to understand the purpose of a pull request at a glance:

* A PR from `feature/user-dashboard` with commits like `feat: add user stats widget` clearly indicates a new feature
* A PR from `bugfix/auth-issue` with commits like `fix: prevent token expiration error` indicates a bug fix

### 5. Simplifying Navigation

Conventional branch names make it easier to navigate the repository history and find specific changes. For example:

```bash theme={null}
# Find all feature branches
git branch --list "feature/*"

# Find branches related to authentication
git branch --list "*auth*"
```

## Tools and Enforcement

We use a dedicated CI/CD check to enforce our Git conventions:

### Branch Naming Check

We use a GitHub Action workflow to verify that branch names follow our convention:

```yaml theme={null}
name: Branch Name Check

on:
  push:
    branches-ignore:
      - main
      - production

jobs:
  check-branch-name:
    name: Check branch name
    runs-on: ubuntu-latest
    steps:
      - name: Check branch name
        run: |
          BRANCH_NAME=${GITHUB_REF#refs/heads/}
          if ! [[ $BRANCH_NAME =~ ^(feature|feat|fix|bugfix|hotfix|release|chore|docs|style|refactor|perf|dependabot|claude)/.+|^release-please--branches--.+ ]]; then
            echo "❌ Branch name '$BRANCH_NAME' doesn't follow the conventional branch format."
            echo "Branch name should be in format: type/description"
            echo "Allowed types: feature, feat, fix, bugfix, hotfix, release, chore, docs, style, refactor, perf, dependabot, claude"
            echo "Release Please bot branches are also allowed with the release-please--branches-- prefix."
            exit 1
          else
            echo "✅ Branch name follows convention: $BRANCH_NAME"
          fi
```

## Best Practices

### Writing Good Commit Messages

1. Use the imperative mood ("add" not "added" or "adds")
2. Keep the description in lowercase to match the repository's observed convention
   (for example, `feat(backend): migrate nova team read`)
3. Do not end the description with a period
4. Keep the description under 72 characters
5. Use the body to explain the what and why, not the how

Example of a well-formatted commit:

```
feat(auth): add multi-factor authentication support

Implement TOTP-based multi-factor authentication to improve security.
The implementation follows the RFC 6238 standard.

Closes #123
```

### Coordinating Commits In Shared Checkouts

When multiple agents or humans may commit in the same checkout, use the commit
window before changing the staged set. The lock is advisory and lives under the
ignored `tmp/agent-coordination/` directory, so it protects the Git index and
commit operation without becoming part of a commit. Claims default to 10
minutes and may only be 5-10 minutes, so claim only when ready to stage,
inspect, and commit.

This coordination is **per-checkout** and **harness-agnostic**. The commit
window and the `tmp/agent-coordination/` notes both live in the working
directory, so they coordinate every agent or human sharing one checkout —
parallel Codex or Claude Code sessions, background tasks, and same-directory
subagents — regardless of which tool they run under. A separate `git worktree`
has its own lock file, its own notes, and its own Git index, so the window does
not span worktrees; separate worktrees stay isolated by being on different
branches and integrate through the shared remote instead. In a hot shared
checkout, commit your owned paths promptly in small scoped commits: a large
unstaged set can be discarded by a concurrent rebase, `reset --hard`,
`checkout`, or `stash` from any agent or human. (`bun git-sync` is isolated and
safe; manual destructive Git is not.)

```bash theme={null}
bun git-commit-window status
bun git-commit-window claim --owner "<agent/task>" --scope "type(scope): subject"
git add path/to/file-a path/to/file-b
git diff --cached --stat
git diff --cached --name-only
git commit -m "type(scope): subject"
bun git-commit-window release --token <token>
```

If another agent owns the window and it is appropriate to wait, use `wait`. The
command sleeps until the active lock is released or expires, then claims the
window before reporting that it is safe to proceed. The waiting period can be
longer than the claim TTL, but the claimed window remains capped at 10 minutes:

```bash theme={null}
bun git-commit-window wait --owner "<agent/task>" --scope "type(scope): subject"
```

Use `--allow-staged` only after inspecting existing staged files. The commit
window does not grant ownership of files or permission to stage unrelated paths.
Existing staged files are owned by the staging agent or coordinator until
explicitly reassigned. If a file appears as `MM`, both its staged and unstaged
diffs need owner review before commit.

Let commit hooks run by default. This is a proof-gated no-verify path: use
`git commit --no-verify` only when the current agent can prove its exact staged
paths would pass the checks normally covered by `bun check`. The proof packet
should include reviewed
`git status --short`, `git diff --cached --stat`, and
`git diff --cached --name-only` output; the touched files or narrow path group;
the separated checks that covered each affected `bun check` component; any
skipped components with path-based rationale; unrelated dirty files excluded
from the claim; and `bun check:mobile` coverage when `apps/mobile` is touched.
If ownership is unclear, proof is incomplete, or the check mapping is uncertain,
do not bypass the hook.

Commit hooks and repo checks can read the whole worktree, including files owned
by other agents. If they fail on unrelated dirty files, release the commit
window and report the blocker instead of formatting, fixing, staging, or
committing those files for convenience. Only the staged-set owner may use the
proof-gated no-verify path, and only with exact-path evidence for the staged
files.

### Branch Management

1. Create branches from the latest `main` branch
2. Keep branches focused on a single task or issue
3. Regularly rebase long-lived branches on `main` to avoid merge conflicts
4. Delete branches after they've been merged

### Synchronizing Release Branches

Use the root command below when `production` should point at the same commit as
`main`:

```bash theme={null}
bun git-sync
```

The command fetches `origin`, creates a temporary detached worktree, refreshes
`main`, and fast-forwards `production` to the current `main` commit from that
temporary worktree before pushing those branches. It finishes by fetching again
and verifying that local and remote `main` and `production` both resolve to the
same commit. The checkout you started from is left untouched, so uncommitted
work on another branch can keep running while the release refs are synchronized.

If a branch that needs to move is already checked out in another worktree, Git
will refuse to force-update that branch. Switch that worktree away from the
branch or update it manually, then rerun `bun git-sync`.

`bun git-sync` does not create commits for you. Commit all intended changes on
`main` first; if `production` contains commits that are not already in `main`,
reconcile the branch manually before rerunning the command.

Use `--only-branch` to update one active sync branch while leaving the other
untouched:

```bash theme={null}
bun git-sync --only-branch production
```

`main` is still refreshed locally as the source commit, but only `production` is
fast-forwarded and pushed. Use `--only-branch main` when you only want to pull
and push `main`.

The retired `staging` branch is no longer a supported `--only-branch` target.
The Supabase staging environment still exists, but its workflow is driven from
`main`.

Use `--current-branch` or `-c` when `main` and `production` should move to the
latest commit on the branch you currently have checked out instead of latest
`origin/main`:

```bash theme={null}
bun git-sync --current-branch
bun git-sync -c
```

Current-branch mode still uses a temporary detached worktree, leaves the checkout
you started from untouched, and only moves the selected sync branches. It does
not push the source branch unless the source branch is itself one of the selected
sync branches, such as running from `main`.

Combine `-c` with `--only-branch` when only one long-lived branch should move to
the current checkout's commit:

```bash theme={null}
bun git-sync -c --only-branch production
```

Use `--no-push` for local-only synchronization:

```bash theme={null}
bun git-sync --no-push
bun git-sync --only-branch production --no-push
bun git-sync -c --no-push
```

With `--no-push`, the command fetches, pulls with `--ff-only`, and fast-forwards
the selected local branches, but it never pushes to `origin`. Final verification
checks local refs only.

### Pull Request Workflow

1. Create a branch with the appropriate type based on the work
2. Make commits using conventional commit messages
3. Push the branch and create a pull request
4. Use conventional commit style for the PR title
5. After approval and merge, delete the branch

## Conclusion

Following these Git conventions helps us maintain a clean, understandable repository history, automate release processes, and improve collaboration across the team. By standardizing both commit messages and branch names, we create a more efficient development workflow.

For more information, refer to the official documentation for [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) and [Conventional Branch](https://conventional-branch.github.io/).
