Skip to content

Modern Git Workflows

9 min read

Learn how modern engineering teams structure branches, integrate changes, rewrite local history safely, handle conflicts, and use advanced Git features to work faster with repositories of every size.

Knowing Git commands is the first stage of learning Git. It is not the same skill as designing a Git workflow that a team can actually operate. This pillar is about the second skill.

Start with Git Branches See the four clusters

Pillar 1 taught what Git is and how it works: commits are immutable snapshots, branches are movable references, the index is where you assemble the next commit. That model makes Git’s behaviour predictable.

It does not tell you whether a branch should exist. Or how long it should live. Or whether the change on it should reach main as a merge commit, a squashed commit, or a replayed series of commits. Those are engineering decisions, and Git deliberately takes no position on them.

That neutrality is a feature. Git is a toolkit, not a methodology. But it means every team has to decide:

  • When to create a branch, and what belongs on it
  • How long branches live, and what happens as they age
  • How changes reach the main branch, and what history that leaves behind
  • When to merge and when to rebase, and what each choice costs
  • How collaboration changes the calculation — a solo repository and a forty-person one need different answers
  • How CI/CD constrains branching, because automated gates change what a branch means
  • How repository scale changes local workflow, because a 40 GB monorepo does not behave like a small service

Get these wrong and the symptoms are familiar: week-old branches that take a day to integrate, a history nobody can read, conflicts that recur every time someone syncs, and a main branch that is broken often enough that people stop trusting it.

What a workflow decision actually looks like

Section titled “What a workflow decision actually looks like”

Here is the same work integrated three ways. The code is identical in all three; only the resulting history differs.

Merge: both histories preserved, integration recorded

A trunk lane labelled main with commits A, B, C and a merge commit M. A branch lane leaves main after commit B with commits D and E, then merges back into main at commit M. The merge commit has two parents.

ABCMDEmainfeatureM has two parents: C and E. Nothing is rewritten.
Rebase then fast-forward: linear history, new commit IDs

A single lane labelled main with commits A, B, C, then D-prime and E-prime. The primed commits are the rebased versions of D and E, drawn in the accent colour to show they are new objects with new IDs.

ABCD'E'main, featureD' and E' are new commits with new IDs. The originals D and E still exist until garbage collection.
Squash: one commit, branch detail discarded

A single lane labelled main with commits A, B, C and S. Commit S is a single squashed commit containing all the work that was previously on branch commits D and E.

ABCSmainS contains D and E's combined changes as one commit. The individual steps are not in main's history.

None of these is correct in the abstract. The merge preserves an audit trail and shows when integration happened. The rebase gives a linear history that git bisect and git log read cleanly. The squash gives one commit per unit of review, which suits some teams and loses useful detail for others.

Choosing between them means knowing what your team needs from its history — which is what this pillar teaches.

This pillar is organised into four clusters, in a deliberate order. Branching decides how work diverges. Merging decides how it comes back together. Rebasing covers reshaping history before it is shared. Productivity covers the Git features that make all of it faster at real repository scale.

  1. Branching

    Designing how development work diverges.

    8 lessons85+ min

  2. Merging

    Safely integrating independent changes.

    7 lessons70+ min

  3. Rebasing

    Reshaping and maintaining commit history.

    7 lessons70+ min

  4. Modern Git Productivity

    Advanced features for faster, more efficient repository work.

    11 lessons110+ min

Where work diverges, and for how long. This cluster starts with what a branch actually is as a Git data structure, then works through the strategies teams build on top: feature branches, GitHub Flow, Git Flow, trunk-based development, short-lived branches and release branches. It ends with a decision guide that compares them against team size, release model, CI maturity and regulatory constraints.

The recurring theme is divergence. A branch that lives for an hour is nearly free to integrate. A branch that lives for a month accumulates every change that landed on main in the meantime, and someone eventually has to reconcile all of it.

How independent histories are integrated. This cluster covers the mechanics of git merge — the merge base, fast-forward versus three-way, what a merge commit is and why it has two parents — then moves to policy: squash merging, rebase-and-merge, and how a hosting platform’s merge button differs from the underlying Git command.

It includes the pillar’s most practical tutorial: resolving merge conflicts, worked through in a disposable repository you build yourself.

Reshaping history. Rebase replays commits onto a new base, producing new commits with new IDs — which is the single most important thing to understand about it, and the reason rebasing shared branches causes problems.

This cluster covers the mechanism, interactive rebase for cleaning up a branch, the narrow operations people actually search for (reordering, squashing, editing), a balanced rebase-versus-merge comparison, and an honest treatment of when rebasing is the wrong tool.

Git contains capabilities that many developers never encounter in beginner tutorials. Worktrees let one repository have several checked-out directories at once. Sparse checkout controls which paths populate your working tree. Partial clone defers downloading objects until they are needed. Shallow clone truncates history.

Those four are routinely confused with one another, and this cluster is precise about what each one actually does. It also covers hooks, aliases, maintenance, configuration, credential handling and commit signing — the operational layer that determines whether Git is pleasant or painful to work with day to day.

Rather than a command reference, treat this pillar as a set of answers to engineering questions:

QuestionWhere it is answered
Should this branch exist at all?Short-Lived Branches
How long should a branch live?Short-Lived Branches
Which branching model fits my team?Choosing a Branching Strategy
Merge or rebase this branch?Rebase vs Merge
Preserve the commits or squash them?Squash Merging
Why did this merge conflict, and how do I fix it?Resolving Merge Conflicts
Is it safe to rebase this branch?When Not to Rebase
I need two branches checked out at onceMultiple Branches, One Clone
The repository is too big to clone comfortablyPartial Clone
I only need one directory out of a monorepoSparse Checkout
Should this check be a hook or a CI job?Git Hooks
Where should this configuration live?Git Configuration
How should credentials be stored?Credential Managers
Should we require signed commits?Signed Commits

Four clusters, 33 lessons. Not everyone should read all of it in order.

If you are new to workflow decisions, read it in sequence. The clusters build: branching decides how work diverges, merging decides how it returns, rebasing covers reshaping before it is shared, and productivity covers the features that make all of it fast.

If you are choosing a branching strategy for a team, read Cluster 1 and then go straight to Choosing a Branching Strategy, which is the decision guide the rest of that cluster feeds.

If your team is arguing about merge versus rebase, read Git Merge Explained, Git Rebase Explained and then Rebase vs Merge. Those three settle most of it.

If you have a specific problem, use the decision table above. Every lesson is written to stand alone as a reference, with links back to whatever model it assumes rather than a re-explanation.

If you are already comfortable with Git, Cluster 4 is where the material most people have not encountered lives — worktrees, sparse checkout, partial clone, maintenance and signing.

Most Git material answers how. This pillar spends most of its effort on whether and when, because that is where the difficulty actually lies once you know the commands.

Concretely, that means:

Trade-offs rather than recommendations. Git Flow is not presented as outdated, nor trunk-based development as obviously correct. Each is given the conditions under which it fits and the conditions under which it does not.

Precision about Git versus the platform. A pull request is not a Git feature. GitHub’s “Rebase and merge” is not git rebase. The lessons say which layer each thing belongs to, because the distinction determines what happens when something goes wrong.

Honest treatment of destructive operations. Every lesson introducing one states what it changes, whether history is rewritten, whether commit IDs change, whether shared work is affected, and how to recover.

Current behaviour, verified. Git changes. Cone mode became the default for sparse checkout; recursive became a synonym for ort; git sparse-checkout init was deprecated. Lessons covering things that can age are marked and record what they were checked against.

This pillar is careful about a distinction that most workflow material blurs.

Git provides branches, merges, rebases, worktrees, hooks and configuration. All of it runs on your machine, and all of it works with no network connection and no account anywhere.

A hosting platform provides pull requests, review requirements, branch protection rules, merge queues, status checks and the merge buttons in its web interface. None of that is Git. GitHub’s “Squash and merge” button is not git merge --squash; they produce comparable results by different routes, and the differences matter when you are debugging why a branch shows as unmerged.

Where a lesson describes platform behaviour, it says so explicitly. Lesson 2 of Pillar 1 covers the boundary in general terms; this pillar applies it to specific workflow decisions.

This pillar assumes the Git model from Pillar 1. Specifically:

  • Commits are immutable snapshots identified by a hash of their content, with parent links forming a graph. See Git Objects Explained.
  • A branch is a movable reference — a file containing one commit ID. See Understanding HEAD.
  • The working tree, index and repository are three distinct places. See How Git Actually Works.

If any of those feels vague, read the relevant lesson first. Workflow decisions are much harder to reason about without them, and this pillar links back rather than repeating the explanations.

You should also be comfortable creating a repository, committing and reading git log — covered in Your First Git Repository.

How these lessons handle dangerous commands

Section titled “How these lessons handle dangerous commands”

Pillar 2 contains substantially more destructive operations than Pillar 1: git reset, interactive rebase, force pushing, branch and worktree deletion, and history rewriting generally.

Every lesson that introduces one states four things explicitly:

  1. What the command does to the working tree, the index and the repository.
  2. Whether history changes, and whether commits receive new IDs.
  3. Whether shared work may be affected — the difference between a local mistake and one that creates work for your colleagues.
  4. How to recover, usually via the reflog, and where recovery is genuinely impossible.

Where a rewrite genuinely requires a force push, these lessons teach git push --force-with-lease rather than bare --force, and explain what the lease actually checks — including the cases where it does not protect you.

Every exercise uses a disposable repository you create for the purpose. Nothing in this pillar asks you to practise on work you care about.

Before starting Cluster 1, set up a scratch repository you can experiment in throughout this pillar:

Terminal window
mkdir ~/git-workflows-lab
cd ~/git-workflows-lab
git init
printf 'line one\nline two\nline three\n' > app.txt
git add app.txt
git commit -m "Initial commit"

Then confirm your Git version, because a few lessons note behaviour that differs between releases:

Terminal window
git --version

Keep this directory around. Several lessons build on a repository with a few commits in it, and practising in a throwaway repository is the habit this pillar wants you to form.