The fast answer for git checkout remote branch: run git fetch, then git checkout -b feature origin/feature (or just git checkout feature if the name is unambiguous), then confirm with git branch -vv. That three-step path — fetch, checkout, verify — covers the vast majority of real-world checkouts. This guide covers what checkout actually does under the hood, the exact commands for checking out a new branch from a remote in every situation (single remote, multiple remotes, forks), when to reach for git switch instead, and the parts most tutorials skip entirely: authentication failures during checkout, checking out branches inside CI/CD without ending up stuck in detached HEAD, and git worktree as an alternative to checkout when you need two branches open at once. If you haven't cloned the remote git repository yet, start there — everything below assumes a local clone with at least one remote already configured.

What Git Checkout Actually Does

What is git checkout? It's the command that changes what your working directory and HEAD point to — swap in a different branch, a specific commit, a tag, or even a single file's contents from somewhere else. Three targets, one command, which is exactly why "what does git checkout do" has more than one right answer depending on what you hand it.

# Switch to an existing local branch
git checkout main

# Create a new branch and switch to it in one step
git checkout -b feature-x

# Detach HEAD at a specific commit — no branch involved
git checkout a1b2c3d

# Restore one file's contents from another branch, leave HEAD alone
git checkout main -- src/api/retry.ts

Read that as a compact set of examples, one line per target type: switch to a branch that already exists, create a new branch and land on it in a single step, detach at a bare commit, or pull one file back. Only the first two are branch operations at all — and only the first two are what most people mean when they ask how to check out a branch in git.

What does checkout mean in git, mechanically: it rewrites your working directory's files to match the target, and it moves HEAD to point at that target — either a branch (refs/heads/<name>) or, when there's no branch involved, directly at a commit. git checkout main is a request to see what main looks like right now; it doesn't create anything, copy anything to a server, or touch history. Uncommitted changes that would be silently overwritten by the swap block the checkout instead of getting lost — one of the errors covered in the troubleshooting section below. So what does git checkout do, in one line: it points HEAD at a new target and makes the files on disk agree with it.

git checkout -b meaning, specifically: -b is "branch" — create a new branch pointing at your current commit (or an explicit starting point you name after it), then check it out. The general shape is git checkout -b <branchname> <start-point>, and it collapses the older git branch, git checkout two-step — create, then switch — into one command. git checkout -b hotfix creates hotfix from wherever HEAD currently sits; git checkout -b hotfix origin/hotfix creates it from the tip of a remote-tracking branch instead, which is the exact form that matters for checking out a new branch from a remote — covered in full in the next two sections.

What a Remote Branch Really Is

"Remote branch" gets used loosely for two different things, and the mix-up is where most remote-branch checkout confusion starts. A branch that lives on the server — GitHub, GitLab, wherever origin points — is one thing. A remote-tracking branch, something like origin/main in your own local clone, is a different thing: a local bookmark recording where that server branch pointed the last time you fetched.

# See your configured remotes
git remote -v

# See the remote-tracking branches your clone currently knows about
git branch -r
Server branch, remote-tracking ref, and local branch are three different things origin (server) lives on GitHub, not here remote-tracking ref refs/remotes/origin/ local branch refs/heads/ feature the branch itself on the server origin/feature read-only bookmark — can't commit onto it feature real, committable local branch fetch checkout -b git checkout -b feature origin/feature turns the read-only bookmark into a real branch origin/feature updates only on fetch — it can lag behind the server between fetches
The branch on the server, the local remote-tracking ref origin/feature, and a real local branch are three different objects. Fetch updates the middle one; checkout -b creates the local branch from it.

origin/main is not a branch you can commit onto — it's read-only from your side, overwritten wholesale on the next fetch to match whatever the server reports. Checking it out directly, bare, with no -b, puts you in detached HEAD rather than on a branch, because there's no local branch object backing it. That distinction — remote-tracking ref versus local branch — is the entire reason git checkout -b feature origin/feature exists as a separate form: it takes the read-only bookmark and turns it into a real, committable local branch. Like remote-tracking refs, these bookmarks go stale the moment someone renames a remote, which is one reason to know how to change a remote's URL cleanly instead of half-reconfiguring it.

Checkout a Remote Branch: The Three-Command Path

How to check out a remote branch, the reliable version, is three commands: refresh your view of the server, create the local tracking branch, confirm it's wired up correctly. That's the whole routine for checking out a remote branch locally — nothing else is required, and every common failure below traces back to skipping one of the three.

# 1. Refresh remote-tracking refs
git fetch origin

# 2. Create a local branch tracking the remote one, and switch to it
git checkout -b feature origin/feature

# 3. Confirm the tracking relationship
git branch -vv
The three-command path 1 git fetch origin refreshes remote-tracking refs — read-only, safe anytime 2 git checkout -b feature origin/feature creates the local branch and switches to it 3 git branch -vv confirms the tracking relationship is wired up Skip step 1 and step 2 fails: "pathspec did not match any file(s) known to git"
Fetch refreshes remote-tracking refs, checkout -b creates and switches to a local tracking branch, and branch -vv confirms it. Skipping fetch is the most common cause of "pathspec did not match."

Step 1 matters more than it looks: if the branch was pushed after your last fetch, your local origin/feature ref doesn't exist yet, and step 2 fails with "pathspec did not match" — git fetch is what makes the branch visible locally in the first place, and it's a read-only, side-effect-free network call, safe to run at any time.

Most of the time, there's a shortcut for step 2. Git's DWIM behavior — "do what I mean," in place since Git 1.8.4 (August 2013) — auto-creates the tracking branch for you when the name is unambiguous:

# Shortcut form — DWIM auto-creates a tracking branch from origin/feature
git checkout feature

git checkout feature works exactly like git checkout -b feature origin/feature under two conditions: no local branch named feature already exists, and exactly one remote carries a branch with that name. Both conditions hold for the common single-remote clone, which is why so many people never learn the longer explicit form — until a second remote enters the picture and DWIM stops guessing, covered in its own section below.

There's also an explicit long form that names the tracking relationship instead of relying on the shortcut, functionally identical to -b with a remote-tracking start point:

git checkout --track origin/feature

--track is worth reaching for when you want it unmistakably clear in a script or a teammate's terminal history that you're deliberately setting up tracking, not just checking out a branch that happens to already have one. All three forms — DWIM, -b, and --track — land in the identical end state: a local branch named feature whose upstream is origin/feature. Generalize the middle one to git checkout -b <branchname> origin/<branchname> and you have the whole remote-branch checkout routine in a single reusable line.

git switch vs git checkout

git switch landed in Git 2.23, released August 2019, specifically to split branch-switching away from everything else git checkout does. git checkout overloads one command across branches, commits, and files, which is exactly the kind of ambiguity that produces the "pathspec did not match" and accidental-detached-HEAD mistakes covered later in this guide. git switch narrows the surface: it only switches branches, so there's less to get wrong.

# git switch equivalents of the checkout commands above
git switch feature                       # git switch to remote branch via DWIM, same rule as checkout
git switch -c feature origin/feature     # explicit tracking branch (-c, not -b)
git switch --track origin/feature        # same as checkout --track
git switch main                          # git switch to another branch you already have locally

The remote case carries over unchanged: git switch feature switches to a remote branch whenever feature exists only on the server, because git switch inherits the identical DWIM rule. When the name is ambiguous, or you just want it spelled out, git switch -c feature origin/feature is the explicit form that never has to guess. Switching to another branch that already exists locally needs no flag at all — git switch <branchname> and you're there.

The flag renames from -b to -c ("create") on purpose — different enough from checkout -b that muscle memory doesn't silently carry over a habit from the older command. If you learned git on the git branch, git checkout two-step, git switch -c is that same pair collapsed into one command. git switch was marked experimental at launch and shed that label as of Git 2.36 (April 2022), so on any git from the last several years it's a fully supported, stable command, not a preview feature.

git switch doesn't replace git checkout outright — it replaces the branch-switching half of it. Detaching HEAD at an arbitrary commit and restoring a single file's contents from another branch both stay on git checkout (or move to its 2019 companion command, git restore, for the file-restore case) — git switch has no equivalent for either. For plain "get me onto this branch" work, git switch is the better default on any modern git; for anything involving commits or files directly, git checkout is still the tool.

When DWIM Fails: Multiple Remotes, origin vs upstream

DWIM's "exactly one remote has this branch" condition breaks the moment a second remote enters the picture — the classic case being a fork, where origin points at your fork and a second remote, conventionally named upstream, points at the original project.

# Add the original project as a second remote, commonly named upstream
git remote add upstream git@github.com:original-owner/project.git

git remote -v
# origin    git@github.com:you/project.git (fetch)
# origin    git@github.com:you/project.git (push)
# upstream  git@github.com:original-owner/project.git (fetch)
# upstream  git@github.com:original-owner/project.git (push)
Two remotes, same branch name: origin vs upstream origin (your fork) you@github.com/you/project upstream (original project) the repo you forked from fetch / push fetch only your local clone origin/fix upstream/fix both remote-tracking refs exist side by side git checkout fix ambiguous — two remotes match checkout -b fix upstream/fix explicit — always resolves
origin and upstream are two separate remotes, each contributing its own remote-tracking ref for a branch named fix. Plain git checkout fix can't pick between them; naming the remote explicitly always resolves.

origin and upstream are just names — nothing in git treats either word specially — but the convention is strong enough that most fork-based workflows assume it: origin is wherever you can push, upstream is the source of truth you pull updates from. With both remotes carrying a branch called fix, plain git checkout fix can't guess which one you mean and either errors out or checks out whichever remote git resolves first — don't rely on the tiebreak. Name the remote explicitly:

git fetch upstream
git checkout -b fix upstream/fix
# or, staying on git switch:
git switch -c fix upstream/fix

git checkout -b fix upstream/fix checks out a branch from the upstream remote by name: the remote is spelled out, so DWIM never gets a vote. Nothing is special about the word upstream itself — git checkout -b fix origin/fix is the identical command aimed at the other remote.

The same explicit-remote pattern applies to any checkout involving more than one remote — anytime there's more than one remote in play, name it, rather than trusting DWIM to pick the right one. Writing out <remote>/<branch> turns a guess into a deterministic checkout, which is what you want in a script, a CI job, or a contribution workflow you repeat every week.

Checking Out a Specific Commit, Tag, or Single File

What does checkout mean in git once branches are out of the picture? The same thing mechanically — move HEAD, sync the working directory — just aimed at a target that isn't a branch.

A branch, a commit, a tag, a single file — one command, git checkout, covers all four targets, and only the first involves a branch at all. The branch case is the one covered above; here are the other three.

# A tag — puts you in detached HEAD, same as a bare commit
git checkout v2.4.1

# A commit by hash — also detached HEAD
git checkout a1b2c3d

# One file's contents from another branch, HEAD untouched
git checkout develop -- path/to/file.ts

Checking out a tag or a raw commit hash detaches HEAD — there's no branch to update as you move, just a direct pointer at that one commit. That's expected, not an error: it's the normal way to inspect history at a fixed point, build a specific release, or bisect a regression. Committing while detached still works, but nothing points at those new commits once you check out something else, and git eventually garbage-collects them — create a branch first with git checkout -b rescue-branch if you want to keep the work, which overlaps with the recovery steps in resetting a branch to a specific commit.

The file-restore form — git checkout develop -- path/to/file.ts — is different in kind: it's a git checkout from another branch that never puts you on that branch. The -- tells git everything after it is a path, not a branch name, so this overwrites only that one file with its version from develop, leaving HEAD and every other file untouched. On Git 2.23+, git restore --source develop path/to/file.ts does the identical job with a name that doesn't imply "switch branches" at all — one more piece of the overload git switch and git restore were built to split apart.

Troubleshooting: The Six Errors You'll Actually Hit

Six failure modes cover nearly every remote-branch checkout problem in practice. Each one has a specific, mechanical cause — none of them need guesswork once you know what to check.

1. "error: pathspec '...' did not match any file(s) known to git." The branch doesn't exist under that name in any local or remote-tracking ref git currently knows about — almost always because it was created on the server after your last fetch. Run git fetch and retry; if it still fails, double-check the exact spelling with git branch -a or git ls-remote --heads origin.

git fetch origin
git checkout feature-x

2. "error: Your local changes to the following files would be overwritten by checkout." Git refuses to silently discard uncommitted work that conflicts with the target branch. Commit the changes, or shelve them temporarily with git stash, then check out and — if you stashed — git stash pop once you're on the new branch.

3. Authentication and SSH failures during fetch or checkout. "Permission denied (publickey)" or "fatal: could not read Username" happen at the network step — fetch or the implicit fetch inside some checkout workflows — not the checkout logic itself. Verify the remote URL protocol matches your configured credentials: git remote -v shows whether you're on an SSH URL (git@github.com:...) or HTTPS (https://github.com/...). For SSH, confirm the agent has your key loaded with ssh -T git@github.com; for HTTPS, confirm a credential helper is configured and the token hasn't expired. This is entirely separate from whether the branch exists — a correctly spelled branch name still fails here if the transport layer can't authenticate.

4. "fatal: A branch named '...' already exists." You ran -b or -c against a name that's already taken locally, often from an earlier, now-stale checkout of the same feature. Either check out the existing branch directly (git checkout feature, no -b — that flag is only for names that don't exist yet), or delete the stale local branch first — see deleting a local branch — before recreating it from the current remote tip.

5. Unexpected detached HEAD. Checking out a remote-tracking ref directly (git checkout origin/feature, no -b), a tag, or a bare commit hash all land you in detached HEAD by design, not by accident — but it's an easy state to end up in without meaning to, especially by pasting a hash from a log. git status reports "HEAD detached at ..." when this happens; get back onto a branch with plain git checkout main, or preserve any new commits first with git checkout -b rescue-branch.

6. Stale remote-tracking refs. git branch -a or plain checkout can't see a branch that's brand new on the server, or keeps offering one that was deleted there weeks ago — both are the same root cause, a remote-tracking ref that's out of sync with the server. git fetch --prune refreshes and cleans it in one call; see listing branches and checking the current one for the full mechanics of how remote-tracking refs go stale.

Checkout in CI/CD and Automation

Checking out a remote branch inside CI is the same question with different defaults. Most CI systems optimize for speed over having a full, branch-aware clone, so checking out a branch on a GitHub Actions runner has a different failure profile than the identical command in your terminal.

GitHub Actions' actions/checkout defaults to fetch-depth: 1 — a shallow clone containing just the one commit being built — and checks that commit out directly, which leaves the runner in detached HEAD by design. That's normal for a build-and-test job that never needs to commit anything. It becomes a real problem the moment a later step tries to push, tag, or otherwise act like it's on a branch and the job fails with detached-HEAD-shaped errors that look confusing outside the CI context. Two fixes, depending on what the job actually needs:

# Full history instead of a shallow, single-commit clone
- uses: actions/checkout@v4
  with:
    fetch-depth: 0

# Or, from inside a job script: fetch and check out a specific branch by name
git fetch origin main:main
git checkout main
Choosing checkout depth in CI What does the job actually need to do? Just build & test fetch-depth: 1 shallow clone, one commit detached HEAD expected — not an error Push, tag, or merge base fetch-depth: 0 full history clone git checkout main real branch, push/tag work actions/checkout defaults to fetch-depth: 1 — shallow and detached by design
A build-and-test job is fine with fetch-depth: 1 and a detached HEAD. A job that pushes, tags, or needs a merge base wants fetch-depth: 0 and an explicit checkout of the real branch.

git fetch origin main:main is the direct-checkout shortcut for automation: it fetches main from origin and writes it straight into a local branch also named main in a single command, no separate checkout -b step needed. It's useful specifically in scripts where you already know the exact branch name and don't want the extra round trip of fetching everything first.

The general rule for CI: if a job only builds and tests, shallow + detached HEAD is fine and faster. If a job needs to push, tag, compute a merge base, or otherwise reason about branch history, use fetch-depth: 0 (or a comparable full-history flag on other CI platforms) and an explicit checkout of the actual branch.

git worktree: Checking Out Two Branches at Once

Regular checkout has a hard constraint most tutorials leave out: one branch checked out at a time per clone. Need to look at a hotfix branch without losing the half-finished state of your current feature work — untracked files, an in-progress rebase, a build sitting mid-compile — and git stash plus checkout plus stash pop is real friction for something you're about to do again next week.

# Add a second working directory, checking out an existing branch into it
git worktree add ../hotfix hotfix

# Or create a new branch as part of adding the worktree
git worktree add -b hotfix-2 ../hotfix-2 origin/main
One .git database, two working directories at once Main clone branch: feature-x untracked files, in-progress rebase — left untouched ../hotfix (worktree) branch: hotfix added with git worktree add checked out at the same time shared .git object database same commits, same objects, same refs Neither working directory blocks, stashes, or interferes with the other
git worktree add ../hotfix hotfix creates a second, fully independent working directory sharing the same .git object database as the main clone — both branches stay checked out simultaneously.

git worktree add ../hotfix hotfix creates a second, fully independent working directory at ../hotfix with the hotfix branch checked out into it — separate files on disk, separate HEAD, but sharing the same underlying .git object database as your original clone. Nothing about your original working directory changes; you just cd into the new folder to work on the second branch, and both stay checked out simultaneously. It's git's actual answer to "checkout two branches at once" — something plain checkout or switch genuinely cannot do, since both operate on a single working directory by design.

The trade-off is disk space and a bit of extra bookkeeping — each worktree is a full checked-out copy of the files, and you have to remember to git worktree remove ../hotfix when you're done, or it lingers. For a one-off "let me just peek at that branch," ordinary checkout is still simpler; for recurring parallel work on two or more branches, worktrees remove the stash-checkout-stash-pop cycle entirely.

Checking Out Branches in VS Code, JetBrains, and GitHub CLI

None of this requires a terminal. VS Code's status bar shows the current branch name at the bottom left — clicking it opens a branch picker listing local and remote branches together, and selecting a remote one performs the fetch-and-track sequence from earlier automatically, no manual -b or --track needed — the shortest way to check out a branch from GitHub if you'd rather not type anything. JetBrains IDEs (IntelliJ, WebStorm, PyCharm) expose the same operation through the Git widget in the bottom-right corner — "Checkout" on a remote branch in the branch list creates the local tracking branch in one click. GitHub Desktop's branch dropdown does the equivalent for anyone who wants checkout without any command line at all.

For pull requests specifically, the GitHub CLI collapses fetch, remote lookup, and checkout of a PR's branch into one command:

# Check out the branch behind pull request #42, fetching and tracking it automatically
gh pr checkout 42

gh pr checkout 42 is the fastest path when the thing you actually have is a PR number, not a branch name — it resolves the PR to its source branch, fetches it (including from a fork, if the PR came from one), and checks it out with tracking already configured, skipping the "what's this branch even called" step entirely.

Mechanically, checking out a remote branch through GitHub's tooling is no different from any other remote: the GUI or gh still fetches, still creates a local branch, still sets the upstream. Only the interface changes — which is why the terminal commands above stay worth knowing even if you check out a branch from GitHub through a picker every day. When a GUI misbehaves, the fix is almost always one of the six terminal-level errors above.

After Checkout: Comparing What Actually Changed

Checking out a branch answers "what does this look like." The next question is usually "what's actually different from what I had," and for a single file that's often easier to read visually than as raw terminal +/- output.

# Pull one file's content off each branch into temp files
git show main:src/api/retry.ts > /tmp/a.txt
git show feature:src/api/retry.ts > /tmp/b.txt
Comparing one file across two branches main feature git show main:file git show feature:file /tmp/a.txt /tmp/b.txt Diff Checker — side by side added lines removed lines No repo access needed — just paste both versions in, nothing gets uploaded
Pulling one file's content off two branches with git show, into temp files, then pasting both into Diff Checker's two-pane view for a readable, syntax-highlighted comparison.

Paste both versions into Diff Checker, a free Chrome extension — no repository access, no branch awareness, just a two-pane text comparison. Its Monaco-based editor (the same engine behind VS Code) lines the two versions up with word-level highlighting and syntax highlighting across 17 languages, toggles between side-by-side and unified view, and can collapse unchanged regions with "Show Diff Only" so a long file doesn't bury the one function that actually changed between branches. Everything runs client-side in the browser — nothing gets uploaded anywhere. It's a genuinely useful complement to git diff main...feature, not a replacement for it: reach for the terminal diff to see everything that changed across a whole branch, and reach for the visual pane when one specific file's change needs a closer, more readable look. The same pattern is covered in more depth in the git diff between two files guide, and for comparisons done inside an editor instead of a browser tab, comparing two files in VS Code covers the built-in diff viewer.

The same two-pane check is useful right after a cherry-pick onto the branch you just checked out, confirming the picked commit landed exactly as expected, and after an amended commit where you want to eyeball the final diff against the original before pushing.

Quick Reference: Every Checkout Command

Every git checkout example from this guide, side by side — every way to check out a branch covered above, plus the specific-commit, tag, and single-file forms. If you just need the one command for the common case, it's the git checkout -b feature origin/feature row.

Command What it does
git fetch origin Refreshes remote-tracking refs; required before checking out a newly created remote branch
git checkout feature DWIM: auto-creates a tracking branch if the name is unambiguous
git checkout -b feature origin/feature Explicit: creates a new local branch tracking a specific remote branch
git checkout --track origin/feature Same result as -b, spelled out explicitly as a tracking setup
git switch feature git 2.23+ equivalent of plain checkout for branch switching
git switch -c feature origin/feature git 2.23+ equivalent of checkout -b
git checkout origin/feature Detached HEAD at the remote-tracking ref's commit — no local branch created
git checkout -b fix upstream/fix Named-remote checkout when more than one remote has the same branch name
git checkout <commit-hash> Detached HEAD at a specific commit
git checkout develop -- path/to/file Restores one file from another branch — HEAD unchanged
git checkout -b rescue-branch Save commits made in detached HEAD before they become unreachable
git fetch origin main:main Fetch and write directly into a local branch in one step — useful in scripts
git worktree add ../hotfix hotfix Check out a second branch into its own working directory, in parallel
gh pr checkout 42 Fetch and check out a pull request's branch by PR number
git fetch --prune Clears stale remote-tracking refs for branches deleted on the server

For the git-scm project's own reference on every flag — and the canonical, source-level answer to what is git checkout — see the official git-checkout documentation and the git-switch documentation.

Frequently Asked Questions

What's the difference between checking out a remote branch directly and creating a tracking branch?

Running git checkout origin/feature by itself puts you in detached HEAD — you're looking at that commit with no local branch to commit onto. Creating a tracking branch with git checkout -b feature origin/feature (or letting DWIM do it automatically via git checkout feature) gives you a real local branch named "feature" that knows its upstream is origin/feature, so plain git pull and git push work without extra arguments. For anything beyond a quick look, you want the tracking branch.

Can I just run git checkout <branch-name> to get a remote branch?

Yes, if two conditions hold: no local branch of that name already exists, and exactly one remote has a branch with that name. Git's DWIM (do-what-I-mean) shortcut, in place since Git 1.8.4, then auto-creates a local tracking branch for you — git checkout feature behaves like git checkout -b feature origin/feature. With two remotes both carrying a "feature" branch, DWIM can't guess which one you mean and you have to spell it out with git checkout -b feature origin/feature or upstream/feature.

What does git checkout -b actually mean?

Short version of the git checkout -b meaning: "-b" tells git to create a new branch and check it out in one step, instead of switching to a branch that already exists. git checkout -b feature creates "feature" from your current HEAD; git checkout -b feature origin/feature creates it from the tip of the remote-tracking branch "origin/feature" and sets that as its upstream automatically. Without "-b", git checkout feature only works if the branch already exists (or DWIM creates it for you).

Should I use git switch instead of git checkout?

For moving between branches, yes, if your git is 2.23 (August 2019) or newer — git switch feature and git switch -c feature origin/feature are narrower, harder-to-misuse versions of the same operations, and Git 2.36 (April 2022) dropped the experimental warning. git checkout still has jobs git switch doesn't cover, like restoring a single file's contents from another branch or detaching HEAD at an arbitrary commit — those stay on git checkout or move to the companion command git restore.

Do I need to run git fetch before checking out a remote branch?

Yes, if the branch was created or updated on the server after your last fetch — your local remote-tracking refs (origin/*) only reflect what git last heard from the server, and git checkout reads those local refs, not the server directly. Run git fetch (or git fetch origin) first, or use git fetch --all to update every configured remote at once, then checkout will see the branch.

What if there's a conflict with a local branch of the same name?

DWIM steps aside entirely when the name is already taken locally: git checkout feature just switches to your local feature, ignoring origin/feature even if the remote one is newer or a completely unrelated line of work. Git only complains when you force the issue with -b, which fails with "fatal: A branch named 'feature' already exists." Three ways out, depending on what the local branch is worth: switch to it and run git pull if it really is the same work, rename it with git branch -m feature feature-old, or delete it with git branch -d feature (-D if it has unmerged commits) and recreate it from the remote tip. git branch -vv tells you which situation you're in — a local branch with no upstream listed is the sign that DWIM never ran.

What's the difference between origin and upstream?

Nothing in git treats either word specially — both are ordinary remote names, and the difference is pure convention. origin is the remote git clone created for you, the one you can push to; in a fork-based workflow that's your fork. upstream is a second remote you add by hand with git remote add upstream <url>, pointing at the original project you forked, which you fetch from but usually can't push to. Once both exist and both carry a branch called fix, plain git checkout fix is ambiguous, so name the remote: git checkout -b fix upstream/fix checks it out from upstream, and git checkout -b fix origin/fix checks it out from origin. Run git remote -v to see what you actually have configured; spelling the remote out makes it a deterministic checkout instead of a DWIM guess.