Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

DEV Community

Cover image for Commit to Code: Branching, Merging, Squashing & Rebasing
Shane Dsouza
Shane Dsouza

Posted on

Commit to Code: Branching, Merging, Squashing & Rebasing

📚 Git & GitHub Series

➡️ You're reading Part 4

⬅️ Part 3: Creating Commits & Exploring the .git Folder


Understanding Branching with an Analogy

Think of a branch in Git as a railway track.

Each commit is like a rail car placed on that track, and the branch name (e.g., main) is the track's label.

Now let’s imagine two developers, Developer A and Developer B, working on their respective features.


Why Not Work on the Same Branch?

If both developers work directly on the same branch (main), over time the commit history gets polluted.

Now imagine if we need to revert Developer A’s changes, doing so would also affect Developer B’s work.

This is why we avoid working directly on main and instead create branches.


How Branching Helps

Branching Overview

At the beginning, the HEAD (which points to the latest commit) is on the last commit of the main branch.

  • Developer A needs to work on a new feature.
  • They create a new branch from main using:
git checkout -b feat/a
Enter fullscreen mode Exit fullscreen mode
  • Developer A commits code into feat/a, creating 3 commits.

Meanwhile, other contributors may add commits to the main branch, moving its HEAD forward.

When Developer A completes their work:

  • The feat/a branch is merged back into main.
  • The merge can happen in one of two ways:
  • As individual commits
  • As a single commit using squash:
git merge --squash feat/a
Enter fullscreen mode Exit fullscreen mode

Real-World Git Rules (In Companies)

Branching overview in companies

Different organizations follow different Git workflows, but a common approach includes:

  • The main branch is treated as the Single Source of Truth.
  • Developers never push directly to main.
  • Instead, they follow a similar process to this:
  • Create a feature branch (e.g., feat/login).
  • Push it to the remote repository.
  • Open a Pull Request (PR) to merge into main.
  • The PR is reviewed, discussed, and approved.
  • After approval, it gets merged into main.

This keeps the main branch clean, stable, and production-ready.


Branch Naming Conventions in Companies

To maintain clarity and consistency across teams, branches are often named following specific patterns:

git branch "feat/whatsapp-integration" #New feature
git branch "bug/login-not-working" #Fixing a bug 
git branch "wip/wontBeFinishedSoon" #Work in progress
git branch "junk/experimenting" #Temporary or experimental work
Enter fullscreen mode Exit fullscreen mode

đź’ˇ Best Practices for Branch Naming:

  • Always use lowercase letters and hyphens - to separate words.
  • Start the branch name with a category prefix (feat/, bug/, wip/, chore/, junk/).
  • Keep branch names short but descriptive.
  • Avoid using spaces or special characters other than - and /.

A consistent naming convention makes it easier to automate workflows, review pull requests, and manage releases.


Let's Perform Branching & Merging in Git

Follow along with this hands-on example to understand branching, committing, and merging.

Step 1: Check Which Branch You’re On

To see your current branch:

git branch
Enter fullscreen mode Exit fullscreen mode

You’ll likely see main (or master).
If you’re not on main, switch to it:

git checkout main
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a New File and Commit

Create a file named feat-a.html and add some text inside the <body>.

Then stage and commit the file:

git add feat-a.html
git commit -m "Working on feat/a"
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a Branch from main and Switch to It

Let’s say you want to start working on Feature B:

git checkout -b feat/b
Enter fullscreen mode Exit fullscreen mode

This:

  • Creates a new branch feat/b
  • Checks out into it (i.e., switches to it)
  • Sets HEAD at the last commit from main

Image description

Step 4: Make Changes and Commit in the New Branch

Create a file called feat-b.html, add some content in it, and make two commits:

git add feat-b.html
git commit -m "Added feature b file"
Enter fullscreen mode Exit fullscreen mode

Make another small change, then:

git commit -am "Updated feature b file"
Enter fullscreen mode Exit fullscreen mode

Step 5: View the Commit History

You can view commit history in two ways:

git log
Enter fullscreen mode Exit fullscreen mode

Or a simplified version:

git log --oneline
Enter fullscreen mode Exit fullscreen mode

Image description

Step 6: Merge feat/b into main

Now that your work is done in feat/b, let’s merge it back to main:

git checkout main
git merge feat/b
Enter fullscreen mode Exit fullscreen mode

Image description

Your changes from feat/b are now part of the main branch.

Step 7: Create a New Branch and Switch in One Command

Create branch in one command

This is a shortcut to create and move into a branch:

git checkout -b feat/c
Enter fullscreen mode Exit fullscreen mode

Make some changes in feat/c, then:

git add feat-c.html
git commit -m "Added feature c"
Enter fullscreen mode Exit fullscreen mode

Then merge into main:

git checkout main
git merge feat/c
Enter fullscreen mode Exit fullscreen mode

Step 8: View Your Updated Commit History

After the merges:

git log --oneline
Enter fullscreen mode Exit fullscreen mode

Commit History

You’ll see the new commits from feat/b and feat/c as part of the main branch history.


Delete Merged Branches (Recommended)

To keep your branch list clean, delete branches that have already been merged:

git branch -d feat/b
git branch -d feat/c
Enter fullscreen mode Exit fullscreen mode

This won’t delete any history, your changes are already part of the main branch.


What Is a Squash Merge?

Image description

Squashing is a hybrid merging approach where multiple commits are combined into a single commit at the time of merging a branch.

When you merge a feature branch into main using squash, Git adds all changes but keeps the main branch history clean.


Benefits of Squash Merging:

  1. Clean history – Only one commit added to main
  2. Removes noise – No clutter from WIP commits or small fixes

Disadvantages of Squash Merging:

  1. History is lost – You lose visibility into the original commit timeline
  2. Harder to debug – Can be challenging if something goes wrong and you need fine-grained history

Try It Yourself: Squash Example

  1. Create a new branch:
git checkout -b feat/d
Enter fullscreen mode Exit fullscreen mode
  1. Create a file feat-d.html, and make 4 commits with different content.
  2. View the commit log:
git log --oneline
Enter fullscreen mode Exit fullscreen mode

Image description

You’ll see 4 separate commits in feat/d.

Now Squash the Branch into Main

Switch to the main branch:

git checkout main
Enter fullscreen mode Exit fullscreen mode

Perform a squash merge:

git merge --squash feat/d
Enter fullscreen mode Exit fullscreen mode

Git will stage all changes from feat/d. Now create a single squashed commit:

git commit -m "Squashed: Feature D implementation"
Enter fullscreen mode Exit fullscreen mode

Check the updated commit log:

git log --oneline
Enter fullscreen mode Exit fullscreen mode

Image description

You’ll see just one new commit on main.
The 4 commits from feat/d are not shown separately.


Visual Breakdown

Let's break down how a branch is created and how merging works with and without squash.


Creating the Branch

Creating the branch


Regular Merge

Regular Merge


Squash Merge

Squash Merge


Real-World Scenario: GitHub Flow with Squash

GitHub Flow with Squash

Let’s say your branch is 3 commits ahead of main.


1. Create a Feature Branch

git checkout -b feat/z
Enter fullscreen mode Exit fullscreen mode

2. Make 3 Commits and Push

git push --set-upstream origin feat/z
Enter fullscreen mode Exit fullscreen mode

Once pushed, GitHub will show:

"3 commits ahead of main"

Ahead of main

3. Open a Pull Request

Suppose your organization has locked the main branch — you can't push directly.

So, you'll create a Pull Request by clicking "Compare & pull request" on GitHub.

Compare and PR

4. Choose Squash & Merge

To merge cleanly into main, select "Squash and Merge".

Squash Merge

This will:

  • Combine all 3 commits into one
  • Add a clean commit message to main
  • Automatically link the PR (e.g. #3)
  • Leave the feature branch (feat/z) visible until deleted

This keeps the main timeline clean while retaining traceability via the PR number.

5. Pull the Latest Changes to Your Local main

After merging the PR, update your local repo:

git checkout main 
git pull origin main
Enter fullscreen mode Exit fullscreen mode

Pull latest

By following this squash-based GitHub flow, your history stays clean, yet your collaboration remains fully traceable.


Git Rebase

Rebase is powerful, clean, and dangerous if misused.
It rewrites commit history by placing your branch commits on top of another branch (usually main).

Image description


When to Rebase?

  • You're working on a feature branch
  • main has moved ahead
  • You want your branch to reflect the latest changes before merging

Common Mistake

If you’re on feat/b, avoid this:

git merge main  # This works but pollutes the history
Enter fullscreen mode Exit fullscreen mode

Or:

git merge --squash main  # Uncommon usage, may not behave as expected
Enter fullscreen mode Exit fullscreen mode

Correct Way: Rebase

git checkout feat/b
git rebase main
Enter fullscreen mode Exit fullscreen mode

This replays your commits on top of the latest from main, keeping your history linear and clean.

Best Practice for Merging Into Main

To keep the main branch clean and organized:

git checkout main
git merge --squash feat/b
Enter fullscreen mode Exit fullscreen mode

This brings in all the changes from your feature branch as one commit and avoids clutter in the commit log.


Wrapping Up

In this article, you learned:

  • Why branching is essential for clean, collaborative development
  • How to create, switch, and merge branches safely
  • The difference between regular merges and squash merges
  • How teams manage contributions using Pull Requests
  • The role of squash merges — both in GitHub and locally
  • How git rebase can help you keep a linear commit history
  • Real-world branch naming conventions used in professional workflows

By applying these concepts, you’ll keep your repository organized, your main branch production-ready, and your team collaboration smooth.


📚 More from the Series


Enjoyed this post?

Found this helpful? Drop a comment, share it with your team, or follow along for the next deep dive.

shanedsouza.com

Top comments (0)