DEV Community

Cover image for Git 3-3 - Workflows
Facundo Botta
Facundo Botta

Posted on • Edited on

Git 3-3 - Workflows

Hi there! It's taken me a while, but I'm finally back to wrap up this 3-part series on Git and GitHub. I hope you’ve found it helpful so far!

In this final part, instead of continuing with commands and terminal examples, I want to talk about Git workflows. Knowing a handful of useful commands is enough to get started, and we can always refer to the docs or ask the ever-present friend we all share: ChatGPT. 😄

But when working on a team, understanding some basic collaboration strategies and branching models is very helpful.

What is a Git workflow?

A Git workflow is a branching strategy or structure that development teams agree to follow when working on a project. It ensures smoother collaboration, clearer versioning, more efficient debugging, and a generally more organized development process.

There are several popular Git workflows out there. Personally, I’ve worked with Git Flow and GitHub Flow, but I also want to touch on Trunk-Based Development and Ship/Show/Ask, which are more modern and increasingly common.

Git Flow

Git Flow is one of the earliest formal Git workflows, proposed by Vincent Driessen in this influential blog post from 2010. At the time, teams were transitioning from centralized version control systems to Git, and needed a more structured way to handle parallel feature development, releases, and hotfixes.

Git Flow became widely adopted, especially in enterprise environments and teams building software with scheduled release cycles (e.g., desktop apps, backend APIs, mobile apps). While it can be overkill for continuous deployment setups, it remains valuable for structured, long-lived projects where stability and versioning are priorities.

The strategy is based on two main branches:

  • main (or master)
  • development (or dev)

Alongside them, there are support branches like:

  • hotfix/*
  • release/*
  • feature/*

Note: The branch names are just conventions, you and your team can use whatever naming style suits you.

main branch

This branch contains the code that is currently in production. Ideally, it should always be stable, clean, and free of debug logs or experimental features. All merges into main should be reviewed, tested, and approved, ideally backed by automated tests.

We do not work directly on main; instead, it only receives thoroughly tested changes from release or hotfix branches.

development branch

This branch contains the code in pre-production, features that are being actively developed but not yet ready for deployment. Developers merge their completed features here for testing, code review, and integration. Once stable, changes from development are moved into release, and eventually into main.

hot-fix branches

Sometimes bugs appear in production, and the development branch isn't in a deployable state, maybe it contains half-finished features. In those cases, we create a hotfix branch from main, apply the fix, test it, and then merge it back into both main and development. This avoids introducing the bug again during the next release cycle.

release branches

These branches are used to prepare a new version of the application before pushing it to production. Think of them as a staging area to finalize bug fixes, polish features, or update documentation.

When everything is ready, the release branch is merged into main and tagged with the version number. It is also merged back into development to ensure it stays up-to-date.

So where do we actually do the work?

Developers don’t work directly on main or development. Instead, they create temporary branches for each task, feature, or bug:

  • feature/ for new features
  • fix/ for bug fixes
  • refactor/ for code improvements

These branches are created from development, and when finished, they’re merged back into it.

Example

# Make sure your main and development branches are up to date
git fetch origin
git switch development
git pull origin development

# Create a new branch for your feature
git switch -c feature/contact-form

# Work locally, commit changes
git add .
git commit -m "Add contact form to homepage"

# Push your feature branch
git push origin feature/contact-form
Enter fullscreen mode Exit fullscreen mode

Then, from GitHub (or GitLab), you’ll open a Pull Request (or Merge Request) targeting the development branch. The team lead or reviewer will evaluate your changes and decide whether to approve them.

When to Use Git Flow

Git Flow works best when:

  • Your team releases software in fixed versions or sprints.
  • You need to manage parallel development, hotfixes, and releases.
  • You want to enforce a clean separation between stable and experimental code.

It may be too rigid for teams practicing continuous deployment or working on fast-moving web applications, but for many software projects, Git Flow provides clarity and discipline.

GitHub Flow

GitHub Flow is designed to be lightweight and fast-paced. It focuses on just one main branch (main), and uses temporal branches to introduce new work. There’s no development, release, or hotfixbranches, just your feature branches and main.

It was popularized by GitHub around 2011 as an alternative to more heavyweight workflows like Git Flow. It aligns well with continuous deployment practices, where the codebase is always in a deployable state and new features are delivered to users as soon as they’re ready.

It’s especially popular in:

  • SaaS applications
  • Web apps with daily deployments
  • Startups or small teams prioritizing speed and flexibility

Example

# Make sure you're up to date with the main branch
git fetch origin
git switch main
git pull origin main

# Create your feature branch
git switch -c feature/new-navbar

# Work on your changes
git add .
git commit -m "Add new responsive navbar"

# Push to GitHub
git push origin feature/new-navbar
Enter fullscreen mode Exit fullscreen mode

When to Use GitHub Flow

GitHub Flow is ideal if:

  • You deploy frequently, even multiple times a day
  • You have automated testing and CI/CD pipelines
  • You value simplicity and speed over structured release cycles

It might not be suitable if:

  • Your project requires strict versioning
  • You need parallel hotfix and release management
  • You're working with large teams and long-running features

Trunk-Based Development

Trunk-Based Development (TBD) is a modern Git workflow used by high-performing engineering teams, especially those practicing continuous integration and continuous delivery (CI/CD).

In this model, all developers commit to a single shared branch, usually called main or trunk. Feature branches either don’t exist or live very briefly (e.g., for hours, not days). The goal is to reduce integration overhead and release changes quickly and safely.

TBD has been around for over a decade but gained traction thanks to Google, Facebook, and other companies that needed to ship code rapidly without drowning in long-lived branches.

It’s often paired with practices like:

  • Feature flags
  • Canary releases
  • Automated testing
  • Code reviews on small commits

Core Concepts

  • Only one long-lived branch: main (or trunk)
  • Developers push directly to main or short-lived branches merged quickly
  • CI runs on every commit to ensure stability
  • Use feature toggles to hide incomplete work from users

But... It seems the same as GitHub Flow 😄

Yes, they are very similar, but there are some key differences:

Development Worflow

  • In GitHub Flow, you create pull requests from your feature branches into main. Once the pull request is approved, the deployment process starts.

  • In Trunk-Based Development, changes are pushed directly to main, often multiple times per day. Every new commit can trigger a deployment pipeline, which is strongly backed by automated testing and CI/CD tools.

    Handling New features

  • In GitHub Flow, new features can live in their own branches until they're complete and ready for production.

  • In TBD, new features live inside main from the start. They're controlled using feature flags or feature toggles, which allow developers to merge incomplete work without exposing it to users.

if (isFeatureEnabled("newCheckout")) {
  renderNewCheckout()
} else {
  renderOldCheckout()
}
Enter fullscreen mode Exit fullscreen mode

Feature flags allow us to gradually test new features, experiment with multiple versions at the same time, or roll out functionality to a specific group of users, such as in canary releases.

When to Use

Use TBD when:

  • You practice continuous integration/deployment
  • You want to reduce merge conflicts and simplify code integration
  • Your team ships often and values small, incremental changes\

It may not be ideal if:

  • You lack automated tests or CI pipelines
  • Your team isn’t disciplined about pushing only tested code
  • You release on a strict versioning schedule

Ship / Show / Ask

Ship/Show/Ask (SSA) is less of a branching strategy and more of a philosophy for how developers collaborate and share their work. Unlike Git Flow or Trunk-Based Development, SSA doesn’t prescribe a specific structure—it’s about how and when you involve others in your development process.

This model has been promoted by companies like GitHub and others that favor developer autonomy, asynchronous workflows, and decentralized decision-making.

SSA defines three modes of contributing code, each reflecting a different level of collaboration:

1. Ship

Ship means you make the change, push it, and deploy it without asking for permission. This is best for small, low-risk, or well-understood changes—like fixing typos, updating comments, or making trivial bug fixes.

It relies on strong developer judgment and confidence in the CI/test suite to catch issues.

2. Show

Show means you share your work before merging or deploying it, but you’re not necessarily asking for approval. It’s useful for mid-sized tasks, experimental ideas, or when you want early feedback. You might open a Pull Request with a title like [WIP] Refactor login logic and invite comments.

It’s collaborative, but informal.

3. Ask

Ask is the most formal mode. You request a review and wait for approval before merging. This is appropriate for high-risk, complex, or sensitive changes; basically, anything that should be reviewed before going to production.

What about branches?

SSA doesn’t enforce a particular branching model. In practice, it often looks like GitHub Flow: one long-lived branch (main or trunk) with short-lived feature branches. The key difference is how you handle the social process of merging, not the structure itself.

When to Use Ship/Show/Ask

SSA works well when:

  • Your team is experienced and trusts each other
  • You value asynchronous, low-friction collaboration
  • You have strong CI/CD and automated tests in place
  • You want to balance autonomy with communication

It might not be ideal if:

  • Your team needs more structure or clarity
  • Newer team members could benefit from stricter review processes
  • Your organization requires tighter control over what reaches production

Conclusion

As we’ve seen, there are several Git workflow options, and the “right” one really depends on your team and project context. Choosing the right strategy can make a big difference in how smoothly your team works and how cleanly your project evolves.

Even if you stick to just one workflow most of the time, I believe it’s important to be familiar with the others—you never know when a different model might come in handy. In the world of open source and cross-team collaboration, it's common to encounter these patterns, and recognizing them can make it much easier to jump in and contribute.

I hope you’ve enjoyed this mini three-part series on Git and GitHub as much as I enjoyed writing it. If you have any questions or suggestions, feel free to drop a comment!

Top comments (0)