BACKEND2026-04-03📖 5 min read

A Complete Guide to Fetching and Working with Git Remote Branches

A Complete Guide to Fetching and Working with Git Remote Branches

A step-by-step guide for engineers on how to fetch a remote branch with git fetch, create a local branch with checkout, configure tracking, and start working.

髙木 晃宏

代表 / エンジニア

👨‍💼

If you work with Git in a team, you've probably run into this scenario more than once: a teammate creates a new branch, and you need to pull it down locally and start working on it. Once you've done it a few times, it feels routine — but if you don't have a solid understanding of how fetch, checkout, and tracking relate to each other, you can easily end up working on the wrong branch or running into errors when pushing or pulling. This article breaks down the full workflow in a clear, systematic way.

What Is a Remote Branch, Anyway?

Before diving into the steps, let's take a moment to clarify what a "remote branch" actually is. Git is a distributed version control system, which means each developer's local environment and the remote repository (GitHub, GitLab, etc.) exist as completely independent repositories.

A remote branch is simply a branch that exists on the remote repository. On your local machine, Git maintains something called a "remote-tracking branch" to represent the state of the remote — these appear as origin/main or origin/feature/user-auth.

This distinction matters more than it might seem. For example, origin/feature/user-auth is not the remote branch itself — it's a snapshot of what that branch looked like the last time you ran git fetch. In other words, if you haven't fetched recently, your remote-tracking branches are out of date.

# Check your remote repository configuration git remote -v

Example output:

origin git@github.com:your-org/your-repo.git (fetch) origin git@github.com:your-org/your-repo.git (push)

If you have multiple remotes configured, you might also see entries like upstream or fork. Most team projects stick to a single origin, but if you're contributing to open source, working with multiple remotes becomes common.

Understanding git fetch: How to Pull Down Remote Branch Info

The first step to working with a teammate's branch is git fetch. The key thing to understand here is that fetch only downloads information from the remote — it doesn't touch your working directory at all.

# Fetch all updates from the remote git fetch origin # Fetch a specific branch only git fetch origin feature/user-auth

After running fetch, Git creates or updates a remote-tracking branch like origin/feature/user-auth locally. At this stage, you've only "learned about" the remote branch — it doesn't yet exist as a local working branch.

When I first started using Git, I didn't really understand the difference between git pull and git fetch, so I'd just pull everything without thinking. But pull actually runs fetch and merge (or rebase) in one shot. To avoid unintentional merges, I'd recommend building the habit of fetching first, reviewing what changed, and then deciding how to proceed.

fetch vs. pull: A Concrete Comparison

Let's look at a concrete scenario to make the difference tangible.

Say you're working on your local main branch, and in the meantime someone pushes new commits to the remote main.

# With fetch: only downloads remote info git fetch origin # Your local main is untouched # Only origin/main gets updated git log --oneline main..origin/main # See commits on remote that aren't local yet

The git log main..origin/main command is incredibly useful. After fetching, you can safely inspect what changed on the remote before integrating anything. To see the actual diff, use git diff main..origin/main.

# With pull: fetches and integrates in one step git pull origin main # fetch + merge (or rebase) runs all at once # If there's a conflict, you need to resolve it immediately

Pull is convenient, but it gives you no opportunity to review what's coming in. For small teams or low-traffic branches, pull is usually fine. But on larger projects or important branches, the two-step approach — fetch, then inspect, then merge — is much safer.

Listing Remote Branches

To see what remote branches are available, these commands come in handy:

# List remote branches git branch -r # List both local and remote branches git branch -a

Example output:

origin/main origin/develop origin/feature/user-auth origin/feature/payment-api origin/fix/login-error

On projects with many branches, piping through grep helps narrow things down:

# Show only feature branches git branch -r | grep feature/ # Filter by a teammate's name (if their name appears in branch names) git branch -r | grep tanaka

If you've fetched but still can't see a branch, try git fetch --prune. Stale references to deleted remote branches can clutter your list and make it hard to find what you're looking for.

# Remove local references to branches deleted on the remote git fetch --prune origin # Or configure this to happen automatically on every fetch git config --global fetch.prune true

Once you set fetch.prune true, you'll wonder how you lived without it. Branches come and go constantly in team development, and stale references pile up fast. I once accidentally checked out a branch that had long been deleted on the remote and wasted time working from outdated code — this setting prevents exactly that.

Creating and Switching to a Local Branch with checkout

Once you've fetched the remote branch info, the next step is creating a local branch and switching to it. You can use either git checkout or git switch.

# Create a local branch with the same name as the remote and switch to it git checkout feature/user-auth

This command has a handy automatic behavior built in. If there's no local branch named feature/user-auth but exactly one remote branch called origin/feature/user-auth exists, Git will automatically create a local branch based on that remote-tracking branch. This behavior is known as "DWIM mode" (Do What I Mean).

On success, you'll see output like this:

branch 'feature/user-auth' set up to track 'origin/feature/user-auth'. Switched to a new branch 'feature/user-auth'

When you see this message, both the local branch creation and tracking setup have been handled automatically.

That said, in environments with multiple remotes configured, DWIM mode may not resolve correctly. In those cases, be explicit:

# Explicitly specify the remote-tracking branch git checkout -b feature/user-auth origin/feature/user-auth

You can also use git switch, introduced in Git 2.23. The motivation was to split checkout's dual responsibilities — branch switching and file restoration — into separate, focused commands.

# The switch equivalent git switch feature/user-auth # Explicit version git switch -c feature/user-auth origin/feature/user-auth

When to Use checkout vs. switch

Which command to use is ultimately a team decision, but I've noticed more new projects adopting switch. Neither is strictly better, so the most important thing is to pick one and stay consistent across the team.

Here's a quick breakdown of the difference:

# checkout does double duty: branch switching AND file restoration git checkout feature/user-auth # Switch branch git checkout -- index.html # Discard changes to a file (restore) # switch + restore separates these responsibilities git switch feature/user-auth # Switch branch git restore index.html # Discard changes to a file (restore)

When a filename and branch name collide, git checkout can behave unexpectedly. For instance, if a file named main exists in your repo, git checkout main becomes ambiguous. git switch and git restore eliminate this ambiguity entirely.

Common Errors and How to Fix Them

Here are the errors you're most likely to encounter when creating a local branch:

Error 1: A local branch with that name already exists

fatal: a branch named 'feature/user-auth' already exists

In this case, just switch to the existing branch:

git switch feature/user-auth # If you want to pull in the latest from remote: git pull

Error 2: You have uncommitted changes

error: Your local changes to the following files would be overwritten by checkout: src/auth.ts Please commit your changes or stash them before you switch branches.

Use git stash to temporarily shelve your work:

# Stash current changes git stash # Switch to the target branch git switch feature/user-auth # When done, go back to your original branch and restore the stash git switch - git stash pop

git stash is a lifesaver when you need to quickly peek at another branch. Just don't let stashes pile up — run git stash list occasionally so you don't lose track of what you've stashed.

Understanding and Configuring Branch Tracking

The link between a local branch and its corresponding remote branch is called "tracking" (or upstream tracking). When you create a local branch using checkout or switch as shown above, tracking is configured automatically. But if you create a branch manually, or if the tracking association gets broken, you'll need to set it explicitly.

# Set the upstream for an existing local branch git branch --set-upstream-to=origin/feature/user-auth feature/user-auth # Shorthand git branch -u origin/feature/user-auth

To verify that tracking is configured correctly:

# Show tracking info for all branches git branch -vv

Example output:

main a1b2c3d [origin/main] Latest commit message * feature/user-auth e4f5g6h [origin/feature/user-auth] Implement authentication

If you see [origin/feature/user-auth] next to the branch name, tracking is set up. With tracking in place, git pull and git push work without any extra arguments — a small thing that adds up to a significant quality-of-life improvement day to day.

I used to overlook tracking entirely when I was starting out. Once I understood it, I never had to type out the remote branch name on every push again, and my workflow became noticeably smoother.

The Error You Get Without Tracking

The importance of tracking becomes crystal clear the first time you hit this error:

git push
fatal: The current branch feature/user-auth has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin feature/user-auth

Helpfully, the error message tells you exactly how to fix it. Running the suggested command sets up tracking and pushes at the same time:

# Push and configure tracking in one step git push -u origin feature/user-auth

On my team, we have a rule: always use -u on the first push of a new branch. That one extra flag makes every subsequent push and pull frictionless.

Inspecting Tracking Details

If you need more detail than git branch -vv provides:

# Show tracking status with ahead/behind info git status -sb

Example output:

## feature/user-auth...origin/feature/user-auth [ahead 2, behind 1] M src/auth.ts

This tells you your local branch is 2 commits ahead of the remote (ahead 2) and the remote has 1 commit your local branch doesn't have yet (behind 1). This is useful context to have before pushing or pulling.

A Practical Workflow You Can Use Every Day

Bringing everything together, here's the full workflow for pulling down a remote branch and getting to work:

# 1. Fetch the latest from remote and clean up stale references git fetch --prune origin # 2. Confirm the target branch exists git branch -r | grep feature/user-auth # 3. Create and switch to the local branch git switch feature/user-auth # 4. Verify tracking is configured correctly git branch -vv # 5. Do your work, commit, and push git add . git commit -m "Fix authentication logic" git push

Once this flow becomes second nature, you'll rarely get tripped up by remote branch operations in team development.

One important caveat: if you're resuming work on a branch that hasn't been touched in a while, always run git pull before continuing to bring in any remote changes. If conflicts arise, it's safer to fetch first, understand the state of things, and then resolve.

Workflow for Resuming Work on an Abandoned Branch

Resuming work on a long-dormant branch is a common scenario. Here's how to approach it cleanly:

# 1. Check your current branch and status git status git branch -vv # 2. Fetch the latest from remote git fetch --prune origin # 3. Switch to the target branch git switch feature/user-auth # 4. Pull in the latest remote changes git pull # 5. Incorporate the latest from main (catches conflicts early) git merge origin/main

Step 5 is easy to skip, but it's important. A branch that's been idle for a while can drift significantly from main. It's far less painful to surface and resolve conflicts before you start new work than to discover them after.

If conflicts do come up, stay calm and work through them methodically:

# See which files have conflicts git status # After resolving conflicts in your editor: git add <resolved-file> git commit -m "Resolve merge conflicts with main"

Tips for Switching Between Branches Efficiently

In team development, you'll often jump between branches — checking a teammate's branch for review, then heading back to your own work. These tricks help:

# Switch back to the previous branch (like cd - in the shell) git switch - # Review recent branch-switch history git reflog | grep "checkout:"

git switch - is surprisingly handy. The entire "check a review branch, then get back to my own branch" cycle becomes a single command.

Troubleshooting: Common Problems and Solutions

Even with a solid understanding of the workflow, you'll still run into issues in real-world team development. Here are problems I've actually encountered, along with their fixes.

"Invalid reference" — Branch Not Found

You're sure you fetched, but Git says the branch doesn't exist.

git switch feature/payment # error: invalid reference: feature/payment

First, double-check the branch name. Typos are a surprisingly common culprit.

# Search by partial name git branch -r | grep payment # Maybe it's actually this: # origin/feature/payment-api

The -api suffix strikes again. Also worth checking: did your teammate actually push the branch yet? If not, no amount of fetching will help — just ask them.

Deleted Remote Branch Still Showing Locally

When a branch gets merged and deleted on the remote, your local remote-tracking reference doesn't disappear automatically.

# Remove stale references git fetch --prune origin # List local branches that have been merged into main git branch --merged main # Delete them after confirming git branch -d feature/old-feature

git branch --merged main lists branches that are safe to delete. Just scan the list before running the delete to make sure nothing unexpected is in there.

Accidentally Ended Up in Detached HEAD State

Checking out a remote-tracking branch directly puts you in "detached HEAD" state:

# Don't do this — it creates a detached HEAD git checkout origin/feature/user-auth
You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch.

Any commits you make in this state don't belong to any branch. If this happens, here's how to recover:

# Create a local branch to escape detached HEAD git switch -c feature/user-auth # Works even if you've already made commits in detached HEAD git switch -c feature/user-auth

I fell into this trap early on by accidentally including origin/ in my checkout command. My commits seemed to vanish, which was alarming — but everything was recoverable via git reflog. Git is designed to be resilient; almost nothing is truly lost. Stay calm and investigate.

Git Config Tips for a Smoother Daily Experience

A few configuration settings I actually use that make these operations more pleasant:

# Automatically prune stale remote refs on every fetch git config --global fetch.prune true # Push to a remote branch with the same name as the current local branch git config --global push.default current # Use rebase instead of merge when pulling (keeps history linear) git config --global pull.rebase true # Sort branch list by most recently used git config --global branch.sort -committerdate

push.default current is especially useful. With this set, you can push a new branch with just git push -u origin instead of typing the full git push -u origin feature/user-auth.

And branch.sort -committerdate sorts git branch output by most recently used. On projects with dozens of branches, this alone makes it much easier to find what you're looking for.

Conclusion: Mastering the Basics Elevates the Whole Team

Fetch, checkout, and tracking are the fundamentals of Git branch management. Looking back, I realize I used them for a long time without truly understanding them — and that vague understanding was the root cause of a lot of small frustrations.

When you understand each piece clearly: fetch safely downloads remote state, checkout/switch creates and switches local branches, and tracking wires local and remote branches together so push/pull just works — things click into place.

Start by building the core three-step loop into your daily habit: git fetch --prune origingit switch <branch>git branch -vv to confirm. Once that rhythm feels natural, remote branch operations will stop tripping you up.

When something goes wrong, remember that Git keeps a detailed history of everything in git reflog. Take a breath, check your state with git status and git branch -vv, and work through it step by step. Most problems have a clean solution.

Building this shared understanding across your team is what turns Git from a source of friction into a genuinely smooth foundation for collaborative development.

At aduce, we offer IT advisory services to help teams optimize their development processes — including Git workflows and team collaboration practices. If you're looking to improve your development workflow or level up your team's technical capabilities, feel free to reach out via our contact page.