# Git-flow

A long-lived develop integration branch with feature, release, and hotfix branches. Model it as two Shelbi Workflows — features land on develop, releases ship develop to main.

**Git-flow** keeps two long-lived branches, `main` (released) and
`develop` (integration), and cuts three kinds of short branches off
them: `feature/*` off `develop`, `release/*` off `develop` toward `main`,
and `hotfix/*` off `main`. It trades the simplicity of trunk-based for an
explicit staging branch where work accumulates before a release.

Git-flow doesn't fit one board, because a feature and a release are
different lifecycles. Model it as **two Shelbi Workflows**: a `feature`
workflow whose tasks branch off and merge back into `develop`, and a
`release` workflow whose task PRs `develop` into `main`. Hotfixes reuse
the [feature-branch](/docs/guides/understanding-workflows/feature-branch) default with `main` as
their base.

## The board

Every card on the `feature` workflow cuts its branch off `develop` and
squash-merges back into `develop`. The **On Develop** column is "landed
on the integration branch," not "released." Shipping to `main` is a
separate `release` task.

## The statuses

Status identity lives once in the project's
[status catalog](/docs/guides/getting-started/workflows#schema),
`workflows/statuses.yaml`. Git-flow adds one status the shipped defaults
don't have: `on-develop`, the done-category landing for feature work
that's merged into `develop` but not yet released. It also adds `staging`
and `released` for the release workflow below. Declare them (`id` + `name` +
`category`) in the catalog first, then reference them by `id`:

```yaml
# workflows/statuses.yaml — git-flow statuses alongside the defaults.
statuses:
  # shipped defaults
  - { id: backlog,     name: Backlog,     category: backlog }
  - { id: todo,        name: Todo,        category: ready }
  - { id: in-progress, name: In Progress, category: active }
  - { id: review,      name: Review,      category: handoff }
  - { id: canceled,    name: Canceled,    category: archived }
  # git-flow additions
  - { id: on-develop,  name: On Develop,  category: done }
  - { id: staging,     name: Staging,     category: active }
  - { id: released,    name: Released,    category: done }
```

## The feature workflow

```yaml
# workflows/feature.yaml — reference-only; identity lives in statuses.yaml
name: feature
description: Git-flow feature — branch off develop, merge back into develop.

git:
  base_branch: develop                 # feature/* branches cut off develop
  merge_strategy: squash

statuses:
  - { id: backlog,     owner: user,  agent: orchestrator }
  - { id: todo,        owner: agent, agent: orchestrator }
  - { id: in-progress, owner: agent, agent: developer }
  - { id: review,      owner: user,  agent: orchestrator }
  - { id: on-develop,  owner: user }
  - { id: canceled,    owner: user }

initial_status: backlog

transitions:
  - from: in-progress
    to: review
    actions: [push_branch, open_pr]      # PR base is develop (the workflow base_branch)

  - from: review
    to: on-develop
    actions: [merge, delete_branch]      # squash into develop

  - from: in-progress
    to: canceled
    actions: [close_pr, delete_branch]
```

Setting `git.base_branch: develop` is the whole trick: branches are cut
from `develop` and the `open_pr` action targets `develop` because no
transition overrides it with a [`target:`](/docs/guides/getting-started/workflows#per-transition-target).

## The release workflow

A release task PRs the accumulated `develop` into `main`. Pre-fill its
`branch:` so the orchestrator operates on `develop`
[directly instead of cutting a new branch](/docs/guides/getting-started/workflows#the-branch-task-field):

```yaml
# workflows/release.yaml — reference-only; identity lives in statuses.yaml
name: release
description: Git-flow release — PR develop into main and tag.

git:
  base_branch: main
  merge_strategy: merge                # a true merge preserves develop's history

statuses:
  - { id: staging,  owner: agent, agent: developer }
  - { id: review,   owner: user,  agent: orchestrator }
  - { id: released, owner: user }

initial_status: staging

transitions:
  - from: staging
    to: review
    actions: [push_branch, open_pr]      # open PR: base main, head develop

  - from: review
    to: released
    actions: [merge]                     # merge develop into main; keep develop
```

```markdown
---
id: release-2025-07
title: Release 2025.07
workflow: release
branch: develop                        # operate on develop as-is; don't cut a branch
---
```

Note `merge_strategy: merge` (not `squash`) and the absence of
`delete_branch`: `develop` is long-lived, so the release preserves its
history and never deletes it.

## Orchestrator adjustments

Two routing rules keep the three lifecycles from colliding. Encode them in
the orchestrator prompt (see
[Author a custom workflow](/docs/guides/getting-started/custom-workflow#1-pin-certain-task-shapes-to-specific-workspaces)):

```markdown
## Routing rules — git-flow

- **Features** default to the `feature` workflow (base `develop`). Ordinary
  work goes here; do not route feature work at `main`.
- **Hotfixes** — titles prefixed `hotfix:` — use the `default` workflow
  (base `main`) so the fix branches off the released line. After a hotfix
  merges to `main`, open a follow-up task to merge `main` back into
  `develop` so the branches don't diverge.
- **Releases** are created by the user on the `release` workflow with
  `branch: develop` pre-filled. Never auto-promote a release — cutting one
  is a human decision about what's ready to ship.
```

The develop-back-merge after a hotfix is the one bit of bookkeeping
git-flow needs that a single workflow can't express. Surface it as a
follow-up task rather than trying to encode it as a transition.

## See also

- [Workflows: parameterization](/docs/guides/getting-started/workflows#parameterization)
  — `{{var}}` in `base_branch` if you run several concurrent integration
  branches instead of one `develop`.
- [Workflows: the `branch:` task field](/docs/guides/getting-started/workflows#the-branch-task-field)
  — how a release task operates on `develop` without cutting a new branch.
- [Feature-branch](/docs/guides/understanding-workflows/feature-branch) — the simpler model
  hotfixes fall back to.
