# GitHub Flow: Simple Branching for Teams That Ship Constantly

After GitFlow, GitHub Flow feels almost suspiciously simple. There's one rule that holds everything together:

> **Anything on** `main` **is deployable.**

That's it. No `develop`, no release branches, no hotfix ceremony. GitHub's own engineers popularised it, and Scott Chacon wrote the canonical description back in 2011. It fits web apps and SaaS products that deploy often, and it's what most small and mid-sized teams end up using anyway, whether they call it that or not.

## The six steps

1. **Branch off** `main` with a descriptive name.
2. **Commit** your changes, early and often.
3. **Open a pull request**, even a draft one, to start the conversation.
4. **Review and discuss.** CI runs here too.
5. **Deploy** from the branch (optionally, to staging or a preview) to verify it works.
6. **Merge to** `main`, which then goes to production.

![](https://cdn.hashnode.com/uploads/covers/6a11b66c1a3cf7bffc297b8a/1259ce63-8fbe-419a-82b2-2a03dfacd7a4.svg align="center")

## What it looks like in git

```mermaid
gitGraph
  commit id: "v1"
  branch feature/search
  checkout feature/search
  commit id: "add index"
  commit id: "add UI"
  checkout main
  branch fix/cart-bug
  checkout fix/cart-bug
  commit id: "fix total"
  checkout main
  merge fix/cart-bug
  checkout feature/search
  commit id: "address review"
  checkout main
  merge feature/search
  commit id: "deploy"
```

Branches are short, merges are frequent, and `main` keeps moving forward in a straight-ish line.

## A realistic day-to-day example

```bash
# 1. Start from fresh main
git checkout main
git pull origin main

# 2. Branch
git checkout -b feature/add-order-export

# 3. Work and commit
git add .
git commit -m "Add CSV export for orders"
git push -u origin feature/add-order-export
```

Then open the PR using the GitHub CLI (or the web UI):

```bash
gh pr create --title "Add CSV export for orders" \
             --body "Adds export button on the orders page. Closes #214." \
             --draft
```

When ready for review, mark it ready and let CI and teammates do their thing:

```bash
gh pr ready
```

After approval, merge it. I'm a fan of squash merges for this workflow because each PR becomes one clean commit on `main`:

```bash
gh pr merge --squash --delete-branch
```

## The thing that makes GitHub Flow actually work

The workflow itself is trivial. What makes it *safe* is everything around it:

### 1\. Reliable automated tests

If `main` must always be deployable, you need CI that you trust. A flaky test suite quietly turns GitHub Flow into "main is probably okay." Fix flaky tests like they're production bugs.

### 2\. Branch protection rules

At minimum:

- Require PR before merging
- Require status checks to pass
- Require at least one approval
- Dismiss stale approvals when new commits are pushed
- Block force-pushes to `main`

### 3\. Fast, ideally automatic deploys

When merging to `main` triggers a deploy, the loop is tight and bugs get found quickly. Example GitHub Actions pipeline:

```yaml
name: CI/CD

on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm test

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/deploy.sh
```

### 4\. A rollback plan

You will ship a bad change eventually. Make sure reverting is one command and one redeploy:

```bash
git revert <merge-commit-sha>
git push origin main
```

### 5\. Feature flags for bigger work

Because every merge goes live, half-finished features need to be hidden. Wrap them in a flag so you can merge daily without exposing unfinished UI.

## Pros

- **Very easy to learn.** New joiners get it in ten minutes.
- **Fast feedback.** Short branches mean smaller diffs and easier reviews.
- **Fits CI/CD naturally.** Merge equals deploy.
- **Pull requests become the unit of collaboration.** Discussion, review, and history all live in one place.
- **Minimal overhead.** No back-merging, no release branch babysitting.

## Cons

- **No built-in answer for multiple versions.** If you need to support v1 and v2 simultaneously, you'll end up inventing release branches.
- **Needs strong automation.** Weak testing makes `main` unstable.
- **Not great for scheduled or gated releases.** If compliance requires a sign-off phase before production, this model has no slot for it.
- **Staging environments are awkward.** Most teams solve this with preview deployments per PR, which is great but takes setup.
- **Long-running features are painful** unless you use flags.

## Best practices

- **Keep PRs small.** Under ~400 lines changed is a good target. Reviewers actually read those.
- **Write meaningful PR descriptions.** What changed, why, how to test, and screenshots for UI work.
- **Use draft PRs early.** Getting feedback before the code is polished saves rework.
- **Name branches clearly.** `feature/`, `fix/`, `chore/`, `docs/` prefixes keep the branch list readable.
- **Delete branches after merging.** Auto-delete is a repo setting, so just turn it on.
- **Use** `CODEOWNERS` to route reviews to the right people automatically.
- **Prefer squash merge** for a clean linear `main`, unless you really want the individual commits preserved.
- **Rebase or merge** `main` **into your branch** if it falls behind, before asking for final review.

## Is it right for you?

Pick GitHub Flow if you:

- Run a web app or API with a single production version
- Can deploy anytime without a formal release process
- Have decent automated test coverage
- Want the least process that still gives you code review

If you need release trains or parallel version support, look at GitLab Flow or GitFlow. If you want even less ceremony and have a mature CI setup, Trunk-Based Development is the next step.

---

Found this useful? You can support my writing by buying me a coffee: [**buymeacoffee.com/vatul16**](https://buymeacoffee.com/vatul16) ☕

Thanks for reading!
