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.
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.
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
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.
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 tag —
git 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 describefails — with no tags reachable from the single commit you have, it exits withfatal: No names found, cannot describe anything.git blamestops 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 logshows 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.
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.
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.