Back to Blog
#Git#DevOps#VersionControl#GitHub#SoftwareDevelopment#Programming#BeginnerGuide#Collaboration#CLI#Engineering

Part 2: Branching, Stash, Merge & Team Collaboration

A Practical Tutorial for Beginners to Advanced Users

Iftekhar Ahmed Eather10 min read
Part 2: Branching, Stash, Merge & Team Collaboration

In Part 1, we learned the basic Git workflow:

Edit
  ↓
git status
  ↓
git add
  ↓
git commit
  ↓
git push

That workflow is enough when you're working alone.

But real software development is rarely a one-person job.

A team may have several developers working on different features at the same time. Someone may be fixing a production bug while another developer is building a new feature.

This is where Git branches become extremely important.

In Part 2, we'll learn how to work with branches, temporarily store unfinished work, synchronize with remote repositories, and combine changes safely.


1. Why Do We Need Branches?

Imagine your team is working on a web application.

The current production version is:

main
  │
  A
  │
  B
  │
  C

Now three developers start different tasks:

              feature/login
             /
main ── A ── B
             \
              feature/payment

Instead of everyone changing main directly, each developer can work independently.

For example:

main
 │
 ├── feature/login
 │
 ├── feature/payment
 │
 └── bugfix/database

This reduces the risk of unfinished work affecting the main codebase.


2. What Is a Branch?

A branch is essentially a separate line of development.

Suppose we have:

A ─── B ─── C

Create a feature branch:

A ─── B ─── C
             \
              D ─── E

D and E are commits made on the feature branch.

The main branch can continue independently.

This gives developers a safe place to experiment, develop, and test changes.


3. Check Your Current Branch

Use:

git branch

Example:

  feature/login
* master

The * indicates your current branch.

You can also see local and remote branches:

git branch -a

Example:

* master
  feature/login
  remotes/origin/master
  remotes/origin/feature/login

This distinction becomes important when working with GitHub.


4. Create a New Branch

The modern command for creating and switching to a branch is:

git switch -c feature/login

The -c means:

Create a new branch.

You can verify:

git branch

You might now see:

* feature/login
  master

You're now working on feature/login.


5. Switch Between Branches

To move to an existing branch:

git switch master

Then:

git switch feature/login

This is a very common operation.

For example:

Currently:
feature/login

Production issue arrives.

↓ 

git switch master

Fix production issue.

↓

git switch feature/login

Continue feature development.

But what happens if you have unfinished changes?

That's where git stash becomes useful.


6. git stash — Temporarily Store Your Work

Imagine you're working on a new feature.

You've modified several files, but your work isn't ready to commit.

Suddenly your manager says:

"There's a production issue. Please investigate it immediately."

You don't want to commit unfinished work like:

temporary changes
WIP
test
fix later

Instead:

git stash

Git temporarily stores your uncommitted changes.

Your working directory becomes clean.

Now you can switch branches:

git switch master

Work on the urgent issue.

When you're ready to return:

git switch feature/login

Check your saved work:

git stash list

Example:

stash@{0}: WIP on feature/login

Restore it:

git stash pop

Your unfinished changes return.


7. The Stash Workflow

The whole process looks like this:

Working on feature
       │
       │ unfinished changes
       ↓
   git stash
       │
       ↓
Working directory becomes clean
       │
       ↓
Switch to another branch
       │
       ↓
Fix urgent issue
       │
       ↓
Return to feature branch
       │
       ↓
git stash pop
       │
       ↓
Continue your work

This is especially useful for developers and DevOps engineers who frequently need to switch between tasks.


8. git fetch — See What's Happening on the Remote

Your local repository and GitHub repository can change independently.

For example:

Your computer:

A ─── B


GitHub:

A ─── B ─── C

Your local repository doesn't automatically have commit C.

Run:

git fetch origin

Git downloads information about the remote changes.

Importantly, fetch does not automatically change your current working branch.

This makes it useful when you want to inspect remote changes before deciding what to do.


9. git pull — Bring Remote Changes Into Your Work

If you're ready to update your current branch:

git pull

Conceptually:

git pull
   =
fetch + integrate

For example:

GitHub
   │
   │ git pull
   ↓
Your local branch

A common workflow is:

git pull

# make changes

git add .
git commit -m "update configuration"

git push

10. git push for a New Branch

When you create a branch locally:

git switch -c feature/login

the branch doesn't automatically exist on GitHub.

Push it:

git push -u origin feature/login

The -u establishes an upstream relationship.

After that, you can usually just use:

git push

and Git knows where the branch should be pushed.


11. Local Branch vs Remote Branch

This is an important concept.

You might have:

Local:

feature/login

and:

Remote:

origin/feature/login

They are related, but they aren't the same thing.

Think of it as:

Your Computer
     │
     │
feature/login
     │
     │ git push
     ↓
GitHub
     │
origin/feature/login

This is why:

git branch

and:

git branch -a

can show different information.


12. Merging a Branch

Suppose you've finished your feature.

Your history looks like:

             D ─── E
            /
A ─── B ─── C

You want to bring the feature into master.

First switch to master:

git switch master

Then:

git merge feature/login

Git combines the feature branch with master.

The result may look like:

A ─── B ─── C ─── D ─── E

or Git may create a merge commit depending on the branch history and merge strategy.


13. Why Do We Merge Into the Target Branch?

This is an easy mistake for beginners.

If you want:

feature/login
        ↓
      master

you must first switch to:

master

Then run:

git merge feature/login

In other words:

The branch you are currently on is the branch receiving the changes.

So:

git switch master
git merge feature/login

means:

"Merge feature/login into master."


14. What Is a Merge Conflict?

Sometimes Git cannot automatically combine two branches.

For example, master contains:

server_port=8080

and the feature branch contains:

server_port=9090

Both branches changed the same line.

Git doesn't know which value is correct.

So:

git merge feature/login

may produce a conflict.

Git might put something like this into the file:

<<<<<<< HEAD
server_port=8080
=======
server_port=9090
>>>>>>> feature/login

This is Git saying:

Your current branch
        ↓
<<<<<<< HEAD

server_port=8080

=======

Incoming branch
        ↓
server_port=9090

>>>>>>> feature/login

Git needs a human to decide the correct result.

We'll cover conflict resolution in detail in Part 3.


15. git merge --squash

Sometimes a feature branch has many small commits:

add login
fix login
fix validation
fix typo
fix validation again
final fix

You may not want all of these development commits appearing individually in your main branch.

You can use:

git merge --squash feature/login

This collects the changes from the feature branch without creating the normal merge commit.

Then you create one clean commit:

git commit -m "add login functionality"

The result is a cleaner history.

Conceptually:

Before:

A
 \
  B
  C
  D
  E
  F


After squash:

A ─── G

where G represents the complete feature.


16. Why Squash Can Be Useful

During development, it's normal to create messy commits:

test
fix
oops
fix again
update
final
really final

That's okay.

Your feature branch is your workspace.

But the main branch may benefit from a cleaner history:

add authentication
add payment processing
fix database connection
improve monitoring

This makes the project history easier to understand.


17. A Realistic Team Workflow

Let's imagine you're working on a DevOps project.

The main branch contains the stable infrastructure configuration.

You receive a task:

Add system optimization configuration.

Start from the latest master:

git switch master
git pull

Create your feature branch:

git switch -c feature/system-optimization

Create your file:

kernel_tuning.txt

Check:

git status

Stage:

git add kernel_tuning.txt

Commit:

git commit -m "add kernel tuning notes"

Push:

git push -u origin feature/system-optimization

Now the branch exists on GitHub.

After review, you can merge it into master.


18. What GUI Users Are Actually Doing

Suppose you're using GitHub Desktop.

You click:

Create Branch

Equivalent concept:

git switch -c feature/system-optimization

You click:

Commit

Equivalent:

git add .
git commit -m "add kernel tuning notes"

You click:

Push

Equivalent:

git push

You click:

Merge

Equivalent concept:

git merge feature/system-optimization

Understanding these commands makes Git GUI tools much less mysterious.


19. A Simple Branching Strategy

For a small or medium-sized team, you might see something like:

main
 │
 ├── feature/login
 ├── feature/payment
 ├── feature/monitoring
 └── bugfix/database

The important principle is:

Keep the main branch stable and use branches for isolated work.

Teams may use different Git strategies—GitHub Flow, Git Flow, trunk-based development, etc.—depending on their environment.

The commands remain largely the same.


20. The Commands You Should Practice

For this part, don't just read the commands.

Create a small practice repository and run:

git branch
git branch -a
git switch -c feature/test
git switch master
git stash
git stash list
git stash pop
git fetch
git pull
git push -u origin feature/test
git merge feature/test

And finally:

git merge --squash feature/test

Don't worry if some of these commands don't make complete sense yet.

The goal is to become familiar with the workflow.


21. Part 2 Cheat Sheet

Command

Purpose

git branch

List local branches

git branch -a

List local and remote branches

git switch branch

Switch branches

git switch -c branch

Create and switch to a branch

git stash

Temporarily save unfinished changes

git stash list

View saved stashes

git stash pop

Restore a stash

git fetch

Download remote information

git pull

Fetch and integrate remote changes

git push

Send commits to remote

git push -u origin branch

Push a new branch and set upstream

git merge branch

Merge another branch

git merge --squash branch

Combine branch changes for one clean commit


Final Thoughts

Branches are one of the reasons Git became so powerful for team development.

Instead of everyone working directly on the same codebase:

Everyone → main

we can work independently:

              feature/login
             /
main ────────┼── feature/payment
             \
              bugfix/database

Each person can develop, test, review, and eventually integrate their work.

And when you need to temporarily stop one task and work on another:

git stash

becomes your safety net.

The most important workflow to remember from this part is:

git pull
    ↓
git switch -c feature/my-task
    ↓
Make changes
    ↓
git status
    ↓
git add
    ↓
git commit
    ↓
git push -u origin feature/my-task
    ↓
Code Review
    ↓
Merge

Once you understand this workflow, you're no longer just using Git to save files.

You're using Git to collaborate safely with a team.


Coming Next: Part 3 — When Git Goes Wrong

Everything is easy when Git works perfectly.

But sooner or later, you'll see:

CONFLICT

or accidentally reset the wrong commit, lose track of a branch, or find yourself wondering:

"Where did my commit go?"

Don't panic.

In Part 3, we'll learn the Git commands that every developer and DevOps engineer should know for troubleshooting and recovery:

git merge conflicts → git log --graphgit log -pgit showgit blamegit resetgit reflog

That's where Git gets really interesting.