Most tutorials for git clone specific branch tell you to run git clone -b <branch> <url> and call it done. That command checks out the branch you asked for — but it does not clone only that branch. Every other branch and its full commit history still land on disk; -b only changes what gets checked into your working tree afterward. The command that actually narrows what's downloaded is --single-branch, and almost nothing that ranks for this search says so. This guide covers what each flag combination really downloads, why --single-branch quietly rewrites your fetch config, and the shallow-clone form CI pipelines default to. If you need the broader story on cloning — verifying the remote URL, choosing HTTPS vs SSH before you've picked a branch at all — cloning a remote Git repository covers that ground; this one stays narrowly on branch selection.

Quick Answer: The git clone specific branch Command

To clone only one branch — not just check it out, actually limit what's downloaded — combine -b with --single-branch:

# Clone one branch only: that branch's history, nothing else
git clone -b <branch> --single-branch <url>

# Leaner still: one branch, one commit — the shape most CI pipelines use
git clone -b <branch> --single-branch --depth 1 <url>

git clone -b <branch> <url> by itself checks out <branch> but still downloads every branch on the remote and its complete history — the exact misconception this guide exists to correct. If you just want the right command and nothing else, the two lines above are it. If you want to know why so many tutorials get this wrong, keep reading.

The phrasing varies — "clone branch git", "clone different branch git", "command clone", "cloning commands" — but every one of those searches lands on the same handful of flags. What separates the results isn't how the question is worded, it's whether --single-branch is in the command or not.

What Does git Clone Do?

What does cloning a repository do, mechanically? A plain git clone <url> does four things, in order: it downloads every commit, tree, and blob object reachable from every branch and tag on the remote into .git/objects; it creates a remote-tracking branch for each remote branch — origin/main, origin/develop, origin/staging, one per branch that existed on the remote at clone time; it configures a remote named origin pointing at the URL you cloned, along with a fetch refspec that keeps every branch in sync on future fetches; and it checks out exactly one branch — normally the remote's default branch, what HEAD points to on the remote — into your working tree. This behavior is documented in full in Git's official git clone reference.

git clone Downloads Everything, Checks Out One Branch origin (remote repository) main develop staging git clone <url> .git/objects full history: main, develop, and staging -- all three 3 remote-tracking branches origin/main origin/develop origin/staging one ref per remote branch Working tree main checked out develop and staging exist only as remote-tracking refs no files on disk for either Downloaded: every branch's full history. Checked out: exactly one.
git clone downloads full history for every branch on the remote and creates a remote-tracking branch for each one, but checks out only a single branch into the working tree.

That's the part worth sitting with: "checked out" and "downloaded" are two different verbs describing two different things, and git clone's default behavior conflates them because by default they happen to produce the same visible result — one branch in your working tree, full history underneath it. Once you start passing flags that change what gets checked out without changing what gets downloaded, the two verbs stop agreeing, and that gap is exactly where the -b misconception below comes from.

Every branch that existed on the remote at clone time gets a remote-tracking branch whether you asked for it or not, which is why git branch -a right after a default clone lists branches you never mentioned. You can move between them with a normal checkout — see checking out a remote branch for the exact commands — because the data for all of them is already sitting in your local .git/objects.

git clone -b: Cloning a Different Branch

To clone a different branch, git needs the name up front. -b <branch>, or its long form --branch <branch>, tells git clone which ref to check out into the working tree instead of the remote's default. It's the standard answer whether you searched for git cloning specific branch, git clone particular branch, or clone branch git, and as far as it goes, it's correct — it just doesn't go as far as most people assume. The git clone branch command in its shortest complete form is one flag long:

git clone -b develop https://github.com/owner/repo.git

After that command, develop is what's in your working tree and what git status reports as your current branch. The flag also accepts a tag name, not just a branch — git clone -b v2.1.0 <url> checks out that tag directly, landing you in a detached HEAD state rather than on a named branch, since a tag is a fixed point rather than something you commit onto. Repository size and clone time are unaffected either way: -b only decides the checkout target, and the next section proves it.

One phrasing worth untangling here: there is no separate git clone remote branch syntax. At clone time every branch is a remote branch, because nothing exists locally yet — -b names a ref that lives on the remote, and Git creates the matching local branch for you as part of the clone. The local-versus-remote distinction only starts to matter afterward, once a branch can exist on one side without existing on the other.

The Misconception: -b Does Not Clone Only One Branch

This is the correction the rest of this guide builds on. -b <branch> selects which branch gets checked out. It does not restrict what gets downloaded. Run a -b-only clone against any multi-branch repository and then list every branch you have locally:

$ git clone -b develop https://github.com/owner/repo.git
Cloning into 'repo'...
remote: Enumerating objects: 41213, done.
remote: Total 41213 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (41213/41213), 38.4 MiB | 9.2 MiB/s, done.

$ cd repo
$ git branch -a
* develop
  remotes/origin/develop
  remotes/origin/main
  remotes/origin/staging
  remotes/origin/feature/checkout-redesign
  remotes/origin/hotfix/rate-limit

Every remote branch is there — main, staging, two feature branches you never mentioned — as a remote-tracking branch, with full history for each already on disk. The 38.4 MiB in that transfer is the whole repository, not the slice belonging to develop. Checking out main after this clone is instant, because the objects are already local; that's the tell that nothing was actually restricted. If disk usage or clone bandwidth was the reason you reached for -b, it did nothing for you — -b alone is a checkout convenience, not a download filter.

-b Changes the Checkout, Not the Download git clone <url> git clone -b develop <url> .git/objects main + develop + staging full history, all three identical download size = .git/objects main + develop + staging full history, all three identical download size checked out: main checked out: develop develop, staging = refs only main, staging = refs only Same .git/objects either way -- -b only changes which branch lands in your working tree.
A plain clone and a -b develop clone download the identical .git/objects history for every branch. The only difference is which branch -b checks out into the working tree.

This is also the part of "what does git clone do" that most competing guides skip entirely, because presenting -b as the whole answer to cloning a specific branch reads cleanly and is wrong only in a way that doesn't show up until someone checks disk usage or wonders why git fetch still sees branches they thought were excluded. If you want an actual download restriction, the next section is the flag that provides one.

git clone --single-branch: Cloning Only One Branch

--single-branch is what makes "git clone single branch" true in the literal sense, and it's the only flag that makes git clone only one branch's objects instead of all of them. Combined with -b, it restricts the clone to one branch's history — objects for other branches are never requested from the remote in the first place, not fetched-then-hidden.

git clone -b develop --single-branch https://github.com/owner/repo.git

Run git branch -a after this version and only develop and remotes/origin/develop show up — no main, no staging, no untouched feature branches. The mechanism is a narrower fetch refspec written into .git/config at clone time — the same source:destination ref-mapping syntax explained in the Git Book's refspec chapter. A default clone writes a refspec that tracks every branch:

[remote "origin"]
    url = https://github.com/owner/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*

A --single-branch clone writes a refspec scoped to just the one branch instead:

[remote "origin"]
    url = https://github.com/owner/repo.git
    fetch = +refs/heads/develop:refs/remotes/origin/develop
Same Clone, Different Fetch Refspec Full clone --single-branch clone [remote "origin"] url = .../owner/repo.git fetch = +refs/heads/*: refs/remotes/origin/* wildcard -- tracks every branch and every future push to any of them [remote "origin"] url = .../owner/repo.git fetch = +refs/heads/develop: refs/remotes/origin/develop scoped -- tracks develop only no other branch is ever requested git fetch afterward only ever asks the remote for what this refspec names.
A full clone's fetch refspec uses a wildcard covering every branch. A --single-branch clone rewrites that refspec to name just one branch, which is why later fetches never surface the others.

That rewritten refspec is exactly why a later git fetch in a --single-branch clone never surfaces other branches — Git isn't hiding them, it was never told to ask the remote for them. That's the same refspec mechanism covered in the git fetch vs pull guide: fetch only ever updates what the refspec names, and here the refspec names one branch. Needing another branch later doesn't mean re-cloning — it means widening the refspec, either permanently or for one fetch:

# Add another branch to the refspec, permanently
git remote set-branches --add origin main
git fetch origin

# Or fetch a branch ad hoc, ignoring the narrowed refspec for one call
git fetch origin main:refs/remotes/origin/main

git config remote.origin.fetch shows the current refspec directly if you'd rather confirm what's configured than infer it from behavior — useful before filing a bug report about a branch that "disappeared" after cloning.

Widening is the right call when you need the other branch's whole history — bringing main back so you can merge master into your branch is the usual reason, and that merge needs origin/main to exist locally before it can run. If all you actually need is one commit off that branch rather than the branch itself, fetching it and cherry-picking a single commit stays lighter than tracking a second branch permanently.

Shallow + Single Branch: The CI Clone

--depth 1 adds a second restriction on top of --single-branch: instead of the full history of one branch, you get exactly one commit — the tip. This is the default shape most CI systems clone in, because a build usually only needs the current state of the code, not the history behind it.

git clone -b main --single-branch --depth 1 https://github.com/owner/repo.git

The flags interact in a way worth being precise about. --depth implies --single-branch automatically — you don't need to write both, though doing so makes the intent explicit and self-documenting in a script. Pass --no-single-branch alongside --depth if you actually want a shallow clone across every branch instead of just one; that combination fetches one commit of history per branch, for every branch, which is rare but occasionally useful for shallow multi-branch mirrors.

Full History vs. --depth 1 Full clone v1.0.0 HEAD --depth 1 commits never downloaded HEAD only commit you have git merge-base, git describe, and git blame history all need commits that a shallow clone never downloaded.
A full clone keeps every commit and any tags reachable from them. A --depth 1 clone has only the tip commit -- everything behind the break was never downloaded, which is why merge-base, describe, and blame all come up short.

A one-commit clone breaks anything that needs history it doesn't have, and the failures are specific enough to recognize:

  • No merge base against another branch or taggit merge-base, and anything built on it like an interactive rebase to squash commits onto a ref outside the shallow window, has nothing to compute from.
  • git describe fails — with no tags reachable from the single commit you have, it exits with fatal: No names found, cannot describe anything.
  • git blame stops at the boundary — every line in the file attributes to the one commit you have, even lines that were actually last touched years earlier, because that earlier history was never downloaded.
  • git log shows exactly one entry — there's nothing behind it to show.

If a build script hits one of these and needs full history after the fact, converting a shallow clone into a complete one doesn't require re-cloning:

# Fetch the rest of that branch's history
git fetch --unshallow

# Or fetch other branches too, if --single-branch also narrowed things
git remote set-branches --add origin '*'
git fetch --unshallow

git fetch --unshallow downloads everything the shallow clone skipped for the branches your refspec currently tracks, turning the repository into a normal, fully historied one. It's a one-time cost — worth paying deliberately in a debugging session, not something to default to in a CI job that only needed the current commit in the first place.

Comparing the Four Clone Commands

Laid out together, these four cloning commands make the difference between "checks out a branch" and "downloads only a branch" easier to see as a straight comparison than as prose:

Command Branches Downloaded History Depth Disk / Bandwidth Fetch Sees Other Branches? Best For
git clone <url> All branches Full history, every branch Largest — entire repository Yes Development work, needing to move between branches freely
git clone -b <branch> <url> All branches (only checkout differs) Full history, every branch Same as a plain clone Yes Starting work on a non-default branch, when you may need others later
git clone -b <branch> --single-branch <url> One branch only Full history of that one branch Smaller — proportional to that branch's history No — refspec is narrowed Focused work on one long-lived branch, saving bandwidth on a large repo
git clone -b <branch> --single-branch --depth 1 <url> One branch only One commit Smallest — no history at all No — refspec is narrowed CI builds, deployments, anything that only needs current code

Read top to bottom, each row adds one more restriction on top of the last: -b adds a checkout target, --single-branch adds a download restriction, --depth 1 adds a history restriction. None of the first three rows actually shrinks what lands on disk versus a plain clone — only --single-branch, in row three and four, does.

git clone Into the Current Directory

A trailing dot is the whole trick: git clone <url> . clones into the directory you're already standing in instead of creating a new subfolder named after the repository — useful when a CI runner or deployment script has already created and cd'd into the target directory before your clone step runs. Branch flags combine with it exactly as they do anywhere else, so a git clone into the current directory can still be narrowed to one branch:

git clone -b main --single-branch https://github.com/owner/repo.git .

The one hard requirement for a git clone into the current directory is that the directory be empty. A non-empty target fails with fatal: destination path '.' already exists and is not an empty directory, the same error covered in the errors section below, just with . in place of a named folder.

When the directory already has files you need to keep — a pre-populated config, a mounted volume, anything that can't simply be emptied first — skip git clone entirely and assemble the same result manually:

git init
git remote add origin https://github.com/owner/repo.git
git fetch origin main
git checkout -b main --track origin/main

That sequence produces the same end state as git clone -b main <url> . would — a repository with origin configured and main checked out — but never requires the directory to start empty, since git init and git fetch don't share that restriction.

Cloning Under a Different Name

Add a target directory name after the URL to git clone under a different name than the repository's own — useful when checking out two branches of the same project side by side, or when the upstream repo name collides with something already on disk.

# Clones into ./my-folder instead of ./repo
git clone https://github.com/owner/repo.git my-folder

# Combine with branch selection the same way
git clone -b develop --single-branch https://github.com/owner/repo.git repo-develop

A git clone under a different name only affects the local folder — it has no effect on origin, which still points at the real upstream URL regardless of what you named the directory locally.

git clone with SSH, Username, and Tokens

Three ways to authenticate a clone come up constantly, and mixing them up is how people end up with a saved token they didn't mean to save.

SSH uses the git@host:owner/repo.git form and authenticates with a key pair instead of a password on every call:

git clone -b main --single-branch git@github.com:owner/repo.git

This is the git clone ssh command in its complete form — no username needed in the URL itself, since git is a fixed service account and your identity comes from whichever private key is loaded in your SSH agent.

HTTPS with a username embeds the account name directly in the URL, prompting for a password or token on first use:

git clone -b main --single-branch https://username@github.com/owner/repo.git

This answers "git clone as user" and "git clone with username" for accounts where SSH keys aren't set up — the username in the URL just pre-fills who you're authenticating as, so Git doesn't have to guess or fall back to whatever's cached.

Personal access tokens replace the password on that prompt on platforms that no longer accept account passwords for Git operations. The tempting shortcut is embedding the token directly in the URL —

# Don't do this
git clone -b main --single-branch https://username:ghp_xxxxxxxxxxxx@github.com/owner/repo.git

— and it works, which is exactly the problem. That token lands in plaintext in .git/config the moment the clone succeeds, and in your shell history the moment you press enter. Anyone who reads either later has it. Use a credential helper instead, so the token is entered once and stored somewhere the OS actually protects:

# macOS
git config --global credential.helper osxkeychain

# Windows
git config --global credential.helper manager

# Linux, cached in memory for a set duration
git config --global credential.helper cache

On GitHub specifically, gh auth login sets up token-based HTTPS authentication without you ever typing or pasting the token into a URL or a config file yourself — it's the more current answer to "what does git clone do" once tokens are involved, and it also configures your Git username and email for commits in the same flow if they aren't set already.

GitHub: Clone a Branch From the Web UI

Trying to github clone a branch through the web UI has one gotcha worth flagging directly: the branch dropdown on a repository page and the green Code button's clone URL are not connected.

The Branch Dropdown and Code Button Aren't Connected Branch: develop Code not connected Download ZIP develop.zip -- matches dropdown github.com/owner/repo.git same URL, every branch git clone <that URL> clones main (default) -- not develop -b develop must still be added yourself
Switching GitHub's branch dropdown only changes what Download ZIP gives you. The Code button's clone URL is repository-level and identical no matter which branch is selected -- a plain git clone of it always checks out the default branch.

Switching the branch dropdown changes what Download ZIP gives you — that button downloads a zip of whichever branch is currently selected in the dropdown, tree and all, no history. But the clone URL under the Code button — HTTPS, SSH, or GitHub CLI — is repository-level, not branch-level. It's the exact same string no matter which branch the dropdown shows. Copy it, run git clone with nothing else added, and you get the repository's default branch, not whatever the dropdown happened to display. So when people ask how to github clone a branch, the honest answer is that the web UI never puts a branch into the clone URL for you — getting the branch you actually wanted still means adding -b <branch> yourself:

git clone -b develop --single-branch https://github.com/owner/repo.git

If you already cloned the wrong branch through the plain URL and don't want to re-clone, switching branches in an existing clone gets you there without a second download — assuming it wasn't a --single-branch clone that excluded the one you need, in which case widening the refspec from the section above comes first. If you cloned via HTTPS off that same Code button and later want SSH instead, or vice versa, changing the remote URL covers switching the transport without a fresh clone.

Verifying You Cloned the Right Branch

Four commands confirm you landed on the branch you meant to, and what state it's actually in:

# Which branch is currently checked out
git branch --show-current

# Full picture: branch, tracking status, clean or dirty
git status

# The single most recent commit on this branch
git log --oneline -1

# The exact commit SHA HEAD points to
git rev-parse HEAD

git branch --show-current prints just the branch name with no extra formatting, which makes it the one to script against. git status gives the fuller picture — branch name, whether it's ahead or behind its upstream, and whether the working tree is clean. For a broader listing of every branch a clone actually pulled down, not just the current one, listing branches and checking the current one covers the rest of that workflow, including the difference between local and remote-tracking branches in the output.

To confirm your local branch matches the remote exactly rather than just having the right name, compare SHAs directly instead of trusting the branch label alone:

# Local HEAD's SHA
git rev-parse HEAD

# What the remote actually has for that branch, without fetching
git ls-remote https://github.com/owner/repo.git refs/heads/develop

If those two SHAs match, the clone is exactly current. If they don't, something has been pushed to the remote since your clone ran — expected on an old clone, worth investigating on a fresh one. Sending your own commits the other way works normally from a branch-scoped clone, since the narrowed refspec governs fetching rather than pushing — pushing a branch to origin names the remote and the branch explicitly, which is exactly the shape a single-branch clone leaves you in.

Common git clone Errors and Fixes

Four errors account for most git clone problems, and each has a specific, mechanical cause:

fatal: destination path 'repo' already exists and is not an empty directory

A folder with that name already has content in it. Clone under a different name (see the section above), remove or empty the existing folder if it's safe to, or clone into a fresh path and move things afterward.

fatal: Remote branch develop not found in upstream origin

The particular branch you named doesn't exist on the remote — a typo, a branch that was renamed or deleted, or a private branch your credentials can't see. List what's actually there before retrying:

git ls-remote --heads https://github.com/owner/repo.git
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

The SSH key being offered isn't registered with the account that owns or can access the repo, or no key is loaded in the agent at all. Confirm what's loaded with ssh-add -l, and verify the connection independently of any specific clone with:

ssh -T git@github.com
warning: --depth is ignored in local clones; use file:// instead.

--depth only shrinks a transfer over a real protocol — HTTPS or SSH. Cloning from a plain filesystem path (no file:// prefix) uses a local optimization that hard-links objects instead of transferring them, so Git ignores the depth request and clones full history anyway. Prefixing the source with file:// forces the network-style code path and makes --depth take effect, at the cost of losing the hard-link speedup.

Once the right branch is actually on disk, the next problem is usually a human one rather than a Git one: comparing what changed in a config file, a lockfile, or a schema between that branch and another copy you have — a different branch, a teammate's version, last week's snapshot. Git can tell you a file changed; reading the change is a separate step, and it's the one a dedicated diff tool is actually built for. Diff Checker runs entirely in the browser, doesn't call any Git commands, and doesn't need either file to be part of a repository at all — paste both versions, or open two files with its picker, and get a color-coded, word-level diff instead of scrolling two terminal windows side by side.

diffchecker.pro Your branch (main) Teammate's branch (develop) - + No git command runs -- paste any two versions and get a color-coded diff instantly.
Diff Checker compares two pasted or opened files directly in the browser, color-coding what changed line by line -- no git command runs and neither file needs to be part of a repository.

Frequently Asked Questions

What does cloning a repository do?

Cloning a repository copies the remote's entire object database — every commit, tree, and blob reachable from any branch or tag — into a local .git directory, configures a remote named origin, creates one remote-tracking branch per remote branch, and checks a single branch out into your working tree. Only that last step is selective; everything before it is a full copy. That's why cloning a large repository costs the same bandwidth whether or not you named a branch with -b.

How do I clone a specific branch in Git?

The complete git clone specific branch command is git clone -b <branch> --single-branch <url>. -b picks which branch gets checked out; --single-branch is the half that limits what's downloaded, and the git clone branch command without it still pulls every branch on the remote onto your disk. There is no separate git clone remote branch syntax — at clone time every branch you can name is a remote branch, since nothing exists locally yet.

What is the difference between -b and --single-branch?

-b <branch> changes only which branch Git checks out into your working tree after the clone finishes; every other branch and its full history still lands in .git/objects. --single-branch changes what Git asks the remote for at all, by writing a narrowed fetch refspec — +refs/heads/develop:refs/remotes/origin/develop instead of the usual wildcard — into .git/config. Use -b alone when you may want other branches later; add --single-branch when you actually want to git clone only one branch and keep the bandwidth.

Can I clone only one branch to save space?

Yes. git clone -b <branch> --single-branch <url> is what makes git clone single branch literally true, downloading that branch's objects and nothing else. Adding --depth 1 shrinks it further to a single commit — the shape most CI pipelines use — at the cost of breaking git describe, git blame history, and any merge-base calculation. Neither restriction is permanent: git remote set-branches --add origin <branch> widens the refspec and git fetch --unshallow restores the history.

How do I clone a Git repository with a username or over SSH?

The git clone ssh command uses the git@host:owner/repo.git form — for example git clone -b main git@github.com:owner/repo.git — and takes your identity from whichever key is loaded in your SSH agent, so no username belongs in the URL at all. Over HTTPS, git clone with username means putting the account in front of the host, https://username@github.com/owner/repo.git, which pre-fills who Git authenticates as and prompts for a password or token. Don't embed the token itself: a git clone as user with an inline token writes that token in plaintext into .git/config and your shell history, so use a credential helper instead.