---
title: Git Workflow
tags: [development]
---

# Git Workflow

How code moves from a developer's laptop to production.

---

## 1. Repositories & branches

Both repos are hosted on the self-hosted Gitea instance at **`git.manko.yoga`** (SSH on **port 222**, HTTPS on 443).

| Repo | Path | Branches |
|------|------|----------|
| Backend | `ssh://git@git.manko.yoga:222/nick/backend.git` | `main`, `development`, `feature/*`, `fix/*` |
| Frontend | `ssh://git@git.manko.yoga:222/nick/frontend.git` | `main`, `development`, `feature/*`, `fix/*` |

### Branch roles

| Branch | Role | Auto-deploy |
|--------|------|-------------|
| `main` (or `master`) | **Production.** Always deployable. | Yes — Gitea Actions builds + pushes `:latest`, Watchtower then pulls it. See [[CI-CD Pipeline]] and [[Deployment]]. |
| `development` | **Active dev.** Integration branch where features land before promotion. | Yes — builds + pushes `:dev` tag (not consumed by prod Watchtower). |
| `feature/<short-slug>` | One change in flight. Branched from `development`. | No |
| `fix/<short-slug>` | A bug fix. Branched from `development` (or `main` for a hotfix). | No |
| `hotfix/<slug>` | Urgent production fix branched from `main`. | No until merged |

```
main         ─●────────●───────────────●───────►  (prod, tagged v2.6.x)
                                                        ▲ release merge
development  ─●────●────●───●───●────●────●────●──►     │
                  ▲    ▲    ▲    ▲    ▲                 │
                  │    │    │    │    │                 │
feature/*       branches off development                │
hotfix/*    ─────────────────────────────●──────────────┘
```

---

## 2. Day-to-day developer flow

```bash
# 1. Sync development
git checkout development
git pull --rebase

# 2. Create a branch
git checkout -b feature/add-seller-payouts

# 3. Hack
# ...

# 4. Verify locally
npm run lint && npm run typecheck && npm run test
# or for frontend
yarn lint && yarn test

# 5. Commit (Conventional Commits — see Coding Standards)
git commit -m "feat(payment): add seller payout history view"

# 6. Push & open PR
git push -u origin feature/add-seller-payouts
```

Open the PR in Gitea against `development`. CI will run on the PR if you have workflows enabled.

> [!tip] Use the `.gitmessage` template (`git config commit.template .gitmessage`) — it pre-fills the conventional-commit format with hints.

---

## 3. Commit message convention

Enforced on the frontend by `frontend/.commitlintrc.json` (and followed by convention on backend). See [[Coding Standards#commit-conventions]] for the full rules and examples.

Quick reference:

```
type(scope): subject

feat: add user authentication
fix(payment): handle missing tx hash
docs: clarify env vars table
chore: bump dependencies
feat!: redesign API endpoints      # breaking change
```

Append `[skip-version]` to skip the auto-version bump when releasing.

---

## 4. PR review process

1. Open the PR with a description that covers **what**, **why**, and **how to test**.
2. Link to the related ticket / issue.
3. CI must be green (build, lint, tests where wired up).
4. **At least one reviewer** approves.
5. Squash-merge into `development` with a clean conventional-commit message.
6. Delete the source branch.

Reviewers check against [[Coding Standards#pr-review-checklist]].

> [!warning] Do **not** force-push to a PR branch after review starts — it invalidates review history. Use additional commits and let the squash-merge tidy up.

---

## 5. Releasing to production

The release path is `development → main → registry → production`.

```bash
# On a clean development that's ready to ship:
git checkout development
git pull --rebase

# Run AI-assisted version bump (chooses major/minor/patch from commit messages)
npm run smart-release
# This: bumps package.json, commits "chore: bump version to vX.Y.Z",
# creates a `vX.Y.Z` tag, and pushes commits + tags.

# Promote to main
git checkout main
git pull --rebase
git merge --ff-only development      # fast-forward only — no merge commit
git push
```

What happens next:

- Pushing to `main` triggers the `docker-build-no-cache.yml` workflow on the backend (and `deploy.yml` on the frontend) — see [[CI-CD Pipeline]].
- That workflow builds the image and pushes both `:<version>` and `:latest` to `git.manko.yoga/manawenuz/escrow-backend`.
- **Watchtower** on the production host (see [[Deployment]]) polls the registry every interval, detects the new `:latest`, and rolls the production container.

### Manual builds

If you want to push a specific version without going through main, use:

```bash
# Backend
npm run release:patch                 # commits + tags + pushes; CI handles the rest
./scripts/build-and-push.sh           # build locally and push dev tag

# Frontend
./scripts/deploy.sh                   # local build + push :latest
```

See [[Scripts]] for details.

---

## 6. Versioning

Semantic versioning, automated where possible.

- `package.json` `version` is the source of truth.
- The AI version scripts (`backend/scripts/ai-enhanced.sh`, `frontend/scripts/ai-enhanced.sh`) classify the last commit:
  - `feat:` → minor
  - `fix:` → patch
  - `feat!:` or `BREAKING CHANGE:` → major
  - `docs:`/`chore:`/`[skip-version]` → skip
- `auto-version.sh` applies the bump, commits, tags `v<version>`, and (with the npm wrappers) pushes.

Confidence levels (`high`/`medium`/`low`/`very-low`) gate the action — low confidence asks for a manual decision rather than auto-applying.

The CI workflows tag built images with both the `package.json` version and the moving tag (`:latest` for main, `:dev` for development).

---

## 7. Hotfix flow

```bash
# Branch from main
git checkout main && git pull --rebase
git checkout -b hotfix/critical-payment-bug

# Fix, test, commit
git commit -m "fix(payment): correct rounding on payout amount"

# Push + PR into main
git push -u origin hotfix/critical-payment-bug
# (open PR targeted at main; merge after review)

# After merge, port the fix back to development:
git checkout development && git pull --rebase
git merge --no-ff main
git push
```

Bump the patch version on `main` before merging so the new image gets a real tag, not just `:latest`.

---

## 8. SSH access on port 222

Gitea SSH listens on **222**, not 22, so the URL is always `ssh://git@git.manko.yoga:222/...`. Add this once to `~/.ssh/config`:

```ssh
Host git.manko.yoga
  HostName git.manko.yoga
  Port 222
  User git
  IdentityFile ~/.ssh/id_ed25519
```

Then `git clone git@git.manko.yoga:nick/backend.git` "just works" without the explicit `:222`.

Container registry uses standard ports — `git.manko.yoga/manawenuz/escrow-backend:latest` over HTTPS — authenticated by a personal access token (`GITEATOKEN` secret in CI).

---

## 9. Rules of thumb

> [!tip] Keep PRs small. Anything > 500 LOC of net change is a candidate for splitting.

> [!warning] Never commit `.env*` files containing real secrets. The repos do already have committed `.env.development` / `.env.production` with **public** values — if you add a real secret, treat it as leaked and rotate.

> [!warning] Never force-push `main` or `development`. If you absolutely must rewrite history, coordinate with the team and re-tag the affected versions.
