Introduction
git clone looks like one operation but actually composes several. Understanding the steps helps when troubleshooting partial clones, slow clones, or surprising defaults.
The sequence
- Create the target directory.
- Run
git initinside it. - Add
originas a remote with the source URL. - Configure default refspec
+refs/heads/*:refs/remotes/origin/*. - Run
git fetch originto download objects and refs. - Determine the default branch (the remote's
HEAD). - Create a local branch tracking it.
- Check out that branch into the working tree.
Watching it happen
GIT_TRACE=1 GIT_TRACE_PACKET=1 git clone https://github.com/example/widget.git 2>&1 | head -50
You will see capability negotiation, refs advertisement, want/have negotiation, and pack receive.
Wire protocol
Modern Git supports protocol v2 (git config protocol.version 2 or default in 2.26+). The server advertises only the requested refs rather than the full ref list, which dramatically improves clone times for repos with many refs.
Variants
git clone --bare # no working tree
git clone --mirror # bare + all refs, configured for mirroring
git clone --depth 1 # shallow
git clone --filter=blob:none # partial clone, skip blobs until needed
git clone --filter=tree:0 # even less data, on-demand trees
git clone --single-branch # only one branch's history
git clone --branch v1.2.3 # checkout a specific branch/tag
git clone --recurse-submodules # clone submodules too
git clone --no-checkout # skip working tree population
Partial clones
Partial clones (--filter) defer object download until objects are needed. They require server support (most modern hosts have it):
git clone --filter=blob:none https://github.com/example/big.git
cd big
git log --oneline # cheap; only commit and tree objects fetched
git show HEAD:src/main.c # this triggers a blob fetch
What goes where
After a successful clone:
.git/objects/pack/: the pack file received from the server..git/refs/remotes/origin/: every server branch as a remote-tracking ref..git/HEAD: symbolic ref to the new local branch..git/config:[remote "origin"]section with URL and refspec.
Server-side advertisement
The first thing the server sends in any clone is the ref advertisement. Under protocol v0/v1 this lists every ref, even if you only want one; on huge repos with millions of refs the advertisement alone could take seconds. Protocol v2 changes this: the client sends an ls-refs request specifying patterns, and the server only advertises matching refs:
git -c protocol.version=2 ls-remote origin 'refs/heads/main'
GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote origin 2>&1 | head
For day-to-day clones the speedup is invisible; for hosting servers it is dramatic.
Common mistakes
Cloning a huge repo on a flaky network and starting over from scratch; git clone in 2.30+ supports resumable cloning over the smart HTTP protocol, but only if the server supports it. Otherwise --depth 1 first, then git fetch --unshallow later. Cloning into ~/Dropbox or another sync folder; the sync client will fight Git for control of .git/index. Cloning a repo with submodules and forgetting --recurse-submodules, ending up with empty submodule directories. Finally, cloning over HTTPS without a credential helper and being prompted for credentials on every fetch; configure one once.