Need the #1 custom application developer in Brisbane?Click here →

Process

Git Workflow

10 min readLast reviewed: March 2026

Git is version control software that tracks every change to your code. It's how multiple developers work on the same project without overwriting each other's work. It's also how you can go back in time if something breaks. Every professional development team uses Git. Understanding the workflow—how code moves from a developer's machine into production—is essential.

What Git Is and Why It Matters

Git is a version control system. It records snapshots of your code at different points in time, who made changes, and why. If you deploy code and it breaks, you can revert to the last working version in seconds. If you want to know who changed a function and when, Git tells you. If two developers edit the same file, Git helps merge their changes without losing work.

Without version control, software development is chaos. People email code files back and forth. Someone overwrites someone else's work. The history of who changed what disappears. You deploy a broken version and can't recover it.

Git is the industry standard because it's fast, secure, and distributed. Every developer has a full copy of the entire history on their machine. You can work offline. You can collaborate across continents without a central server.

Repositories and Branches

A Git repository (or "repo") is a folder containing your project and its entire history. It lives on a server (like GitHub) so multiple people can access it.

A branch is a parallel version of the code. Imagine your codebase as a tree trunk (the main branch, usually called "main" or "master"). Branches split off like limbs, allowing developers to work independently. When the work is done and tested, the branch gets merged back into the trunk.

Example workflow:

  • Create a branch called "feature/user-login" from main
  • Developer builds the login feature on that branch
  • Other developers keep working on main, unaffected
  • When login is complete and tested, merge it back into main

Branches keep teams from stepping on each other. Developer A can be building the payment system. Developer B can be building the user dashboard. They work in parallel, then merge when both are done.

Branching Strategies

Different teams organize branches differently. Three popular strategies:

Common branching strategies
StrategyHow It WorksBest For
Feature BranchingEach feature gets its own branch. Developers commit to the branch, then open a pull request to merge into main when done.Most teams. Clear, simple, good for code review.
GitflowMultiple long-lived branches: main (production), develop (staging), feature branches off develop, release branches for final testing.Larger teams, complex releases, when staging needs to be kept separate from main.
Trunk-Based DevEveryone commits to main (or a very short-lived branch). Small commits, frequent deploys. Requires high test coverage and discipline.High-velocity teams, continuous deployment, startups moving fast.

Most custom software projects use Feature Branching: one branch per feature, reviewed and merged into main when complete. It's simple and gives you a clear gate (the code review) before code enters production.

Pull Requests: The Code Review Gate

A pull request (PR) is a proposal to merge code from one branch into another. It's the moment where other developers review the code before it goes into main.

The workflow looks like:

  1. Developer creates a feature branch and writes code
  2. When ready, they push the branch to GitHub and open a pull request
  3. Other developers review the code, ask questions, suggest improvements
  4. Developer makes requested changes and pushes them to the branch
  5. Once approved, the PR is merged into main

Pull requests are asynchronous code review. One developer doesn't need to interrupt another for approval—the reviewer checks when they have time, leaves comments, and the original developer responds.

Good pull requests are focused: one feature, not five. They're reviewed within hours, not days. They have a clear description so reviewers understand the context. They pass automated tests before being reviewed (more on that later).

Code Review Culture
Code review isn't about gatekeeping or making someone prove themselves. It's about making code better, catching bugs early, and sharing knowledge across the team. Good reviews are collaborative: "I suggest this because..." rather than "You did this wrong." A developer might propose a solution, the reviewer might suggest a different approach, and they talk through it. The code is better for it, and the whole team learns.

Commit Messages: Why They Matter

A commit message documents why a change was made. Months later, when you're debugging an issue and need to understand why a line of code exists, a good commit message saves you hours.

Bad commit message: "fix stuff"

Good commit message: "Fix race condition in user session cleanup. The cleanup task was running concurrently with the session validation, causing intermittent timeouts for users with many open tabs. Added a mutex lock to ensure serial access."

Most teams follow a simple commit message format:

  • First line (50 chars): A short summary of the change. "Add password reset flow" or "Fix bug in discount calculation"
  • Blank line
  • Body (wrap at 72 chars): More detail about what changed and why. What problem does this solve? What approach did you take?

Good commit messages are for your future self and your teammates. Take 30 seconds to write one that will save someone an hour of debugging later.

Branch Naming Conventions

Most teams name branches in a consistent way so you can glance at the branch name and understand what it's for:

  • feature/user-authentication — a new feature
  • bugfix/login-redirect-issue — fixing a bug
  • docs/api-endpoints — documentation changes
  • refactor/payment-module — code cleanup without behavior change
  • chore/upgrade-dependencies — maintenance tasks

Consistent names make it easier to find branches, understand what's being worked on, and automate workflows (e.g., "all feature/* branches require reviews before merging").

Merge vs Rebase: The Eternal Debate

When you're ready to combine two branches (say, feature/login and main), Git offers two approaches: merge and rebase. Both end up with the same code, but they handle the history differently.

Merge creates a new commit that combines two branches. The history shows both branches and where they came together. It's safe—if something goes wrong, it's obvious what happened.

Rebase replays one branch's commits on top of the other. The history is a straight line. It looks clean, but if you don't understand what you're doing, you can accidentally rewrite shared history.

In plain terms: Merge is safer. Use it. Rebase is for teams that really know Git. The debate goes on endlessly among developers, but most teams default to merge for safety.

Never Force Push to Main
Force pushing rewrites Git history. It's useful for fixing your own local branches, but force pushing to main (or any shared branch) can destroy other people's work. It's one of the worst things you can do on a team. Protect main with rules that prevent force pushes.

Protecting the Main Branch

Main is where production-ready code lives. You can't just push anything to main. Most teams set up rules:

  • Code must be reviewed by at least 2 developers before merging
  • Automated tests must pass before merging
  • No one can force-push to main
  • All conversations in the PR must be resolved
  • Branches must be up-to-date with main before merging (no old code sneaking in)

These rules prevent bad code from reaching production. They slow down merges slightly, but they save enormous pain from deployments that break production. A few hours of delay in a merge is worth avoiding a 3am wake-up call to fix a critical bug.

Handling Merge Conflicts

A merge conflict happens when two developers edit the same lines of code. Git doesn't know which version is correct, so it asks the developer to decide.

Example: Developer A changes line 42 of auth.js to add error logging. Developer B changes the same line to add a new parameter. When you try to merge, Git says "I don't know which is right—you pick."

Merge conflicts are manual work. The developer resolves them by:

  1. Opening the conflicted file (Git marks the conflicts with <<< and >>>)
  2. Deciding which code to keep or combining both
  3. Removing the conflict markers
  4. Testing to make sure the merge works

Conflicts are annoying but rare if teams coordinate well. Keep pull requests small and review them quickly so branches don't diverge too far.

Git Tags for Releases

When you deploy code to production, it's useful to mark that point in history so you can find it later. That's what tags are for.

Example: You deploy version 1.2.0 to production on March 15. You create a tag "v1.2.0" at that commit. Later, if you need to debug what was deployed on March 15, you look at the tag.

Most teams use semantic versioning: MAJOR.MINOR.PATCH. 1.2.0 means major version 1 (the product), minor version 2 (new features added), patch version 0 (no bug fixes yet). When you add a feature, increment minor. When you fix a bug, increment patch. When you make a breaking change, increment major.

Monorepo vs Polyrepo

As projects grow, you need to decide: one big repository or multiple smaller ones?

Repository structure approaches
ApproachHow It WorksProsCons
PolyrepoSeparate repos for frontend, backend, mobileTeams can work independently, easier to onboardCoordinating changes is harder, duplicate tooling
MonorepoEverything in one repo: frontend, backend, shared codeCoordinated changes, shared code is obvious, atomic commitsHuge clones, tooling is more complex, harder to scale

For small teams, polyrepo is simpler. For teams that need tight coordination or share a lot of code, monorepo works. There's no universal right answer.

Git Workflow and CI/CD

Git integrates with CI/CD (continuous integration/continuous deployment) systems. When you push code to a branch or open a pull request, automated tests run. When code is merged to main, it's automatically deployed to staging or production.

This is where Git becomes powerful. You don't manually run tests and deploy—the system does it. A developer pushes code, tests run automatically, code is deployed. If tests fail, the PR is blocked. If they pass, the code flows to production with no manual steps.

For Non-Developers: What to Expect

If you're a business owner or product manager, here's what Git workflow means for you:

  • Pull requests take time to review. Code doesn't merge instantly. It sits in review for hours or a day. This is good—it prevents bugs. Don't push for faster merges without code review.
  • Features go into staging before production. The Git workflow usually has a staging branch where code is tested before it reaches main. This catches issues before users see them.
  • You can see who changed what and when. If there's a bug, you can ask Git "who changed this code?" It tells you the person and the date. Accountability is built in.
  • Rollbacks are fast. If you deploy code and it breaks, you can revert to the last known good version in minutes, not hours.
Branch Names Tell a Story
When you look at the branch list on GitHub, you can see what the team is working on without asking. feature/dark-mode, bugfix/email-validation, docs/api-guide—it's like a transparent todo list of active work.

The Flow

A healthy Git workflow looks like this:

  1. Developer checks out a feature branch from main
  2. They write code, commit frequently with clear messages
  3. They push to GitHub and open a pull request with a description
  4. Automated tests run; other developers review
  5. Feedback is incorporated; code is updated
  6. Pull request is approved and merged to main
  7. Tests run again on main; code is deployed to staging
  8. QA or the Product Owner verifies on staging
  9. When ready, it's deployed to production

The next section covers Documentation—how to ensure that future developers (and future you) understand the code.