GIT-CLONE(1)

๐Ÿ’… git-clone(1) โ€” straight up out of the Git Manual ๐Ÿ’…

okay so bestie, you know how everyone's always like "just clone the repo" โ€” this is the page that tells you literally everything that command can do. it's giving main character energy, it's giving wow that's a lot of flags, and honestly? we're gonna get through it together ๐Ÿซถ


โœจ NAME โœจ

git-clone โ€” Clone a repository into a new directory ๐ŸŽ€


๐ŸŒˆ SYNOPSIS ๐ŸŒˆ

git clone [--template=<template-directory>]
          [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
          [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
          [--dissociate] [--separate-git-dir <git-dir>]
          [--depth <depth>] [--[no-]single-branch] [--[no-]tags]
          [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
          [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
          [--filter=<filter-spec> [--also-filter-submodules]] [--] <repository>
          [<directory>]

like, yes, that's the whole vibe up there. no cap, that's the real synopsis, don't @ me ๐Ÿ’€


๐Ÿ’– DESCRIPTION ๐Ÿ’–

So what does it actually do? Bestie. It clones a repository into a newly created directory โ€” like, it makes you a whole fresh baby copy ๐Ÿ“ โ€” and then it:

  • creates remote-tracking branches for each branch in the cloned repository (you can peek at them with git branch --remotes ๐Ÿ‘€)
  • creates and checks out an initial branch that is forked from the cloned repository's currently active branch

Basically it sets you up so you're already on the branch the repo had going, and all the other branches are chilling in the background waiting for you. Iconic behavior, honestly ๐Ÿ‘‘

Then, after the clone is done โ€” and this is the part that ate โ€” a plain git fetch with no arguments will update all the remote-tracking branches, and a plain git pull with no arguments will in addition merge the remote master branch into the current master branch, if any. (โš ๏ธ heads up: this is untrue when --single-branch is given โ€” see below, iykyk.)

And how does it pull off this default config? By creating references to the remote branch heads under refs/remotes/origin and by initializing the remote.origin.url and remote.origin.fetch configuration variables. That's the whole magic trick โœจ


๐Ÿฆ‹ OPTIONS ๐Ÿฆ‹

okay this is the long part, hydrate first ๐Ÿ’ง

  • -l, --local โ€” When the repository you're cloning from is on a local machine, this flag bypasses the normal "Git aware" transport mechanism and just clones the repository by making a copy of HEAD and everything under the objects and refs directories. The files under the .git/objects/ directory get hardlinked to save space when possible ๐ŸŽ€

If the repository is specified as a local path (e.g., /path/to/repo), this is the default, and --local is essentially a no-op. If the repository is specified as a URL, then this flag is ignored (and we never use the local optimizations, periodt). Specifying --no-local will override the default when /path/to/repo is given, using the regular Git transport instead.

If the repository's $GIT_DIR/objects has symbolic links or is a symbolic link, the clone will fail. This is a security measure to prevent the unintentional copying of files by dereferencing the symbolic links ๐Ÿ”’

This option does not work with repositories owned by other users for security reasons, and --no-local must be specified for the clone to succeed.

NOTE: this operation can race with concurrent modification to the source repository, similar to running cp -r <src> <dst> while modifying <src>. ๐Ÿ’€ so like, don't be doing that
  • --no-hardlinks โ€” Force the cloning process from a repository on a local filesystem to copy the files under the .git/objects directory instead of using hardlinks. This may be desirable if you're trying to make a back-up of your repository ๐ŸŒธ like, fair.
  • -s, --shared โ€” When the repository you're cloning is on the local machine, instead of using hard links, automatically setup .git/objects/info/alternates to share the objects with the source repository. The resulting repository starts out without any object of its own. ๐Ÿซถ
Note: this is a possibly dangerous operation โ€” do not use it unless you understand what it does. If you clone your repository using this option and then delete branches (or use any other Git command that makes any existing commit unreferenced) in the source repository, some objects may become unreferenced (or dangling). These objects may be removed by normal Git operations (such as git commit) which automatically call git maintenance run --auto. (See git-maintenance(1).) If these objects are removed and were referenced by the cloned repository, then the cloned repository will become corrupt. ๐Ÿ˜ญ like genuinely, be careful.

Note that running git repack without the --local option in a repository cloned with --shared will copy objects from the source repository into a pack in the cloned repository, removing the disk space savings of clone --shared. It is safe, however, to run git gc, which uses the --local option by default โœ…

If you want to break the dependency of a repository cloned with --shared on its source repository, you can simply run git repack -a to copy all objects from the source repository into a pack in the cloned repository. freedom ๐Ÿ’…

  • --reference=<repository>, --reference-if-able=<repository> โ€” If the reference <repository> is on the local machine, automatically setup .git/objects/info/alternates to obtain objects from the reference <repository>. Using an already existing repository as an alternate will require fewer objects to be copied from the repository being cloned, reducing network and local storage costs ๐Ÿ’– When using the --reference-if-able, a non existing directory is skipped with a warning instead of aborting the clone.
Note: see the NOTE for the --shared option, and also the --dissociate option. ๐Ÿ‘€
  • --dissociate โ€” Borrow the objects from reference repositories specified with the --reference options only to reduce network transfer, and stop borrowing from them after a clone is made by making necessary local copies of borrowed objects. This option can also be used when cloning locally from a repository that already borrows objects from another repository โ€” the new repository will borrow objects from the same repository, and this option can be used to stop the borrowing. cute, clean break ๐Ÿฆ‹
  • -q, --quiet โ€” Operate quietly ๐Ÿคซ Progress is not reported to the standard error stream.
  • -v, --verbose โ€” Run verbosely ๐Ÿ—ฃ๏ธ Does not affect the reporting of progress status to the standard error stream. (like, it's chatty but not that chatty)
  • --progress โ€” Report progress status on the standard error stream by default when attached to a terminal, unless --quiet is specified. This flag forces progress status even if the standard error stream is not directed to a terminal โœจ
  • --server-option=<option> โ€” Transmit the given string to the server when communicating using protocol version 2. The given string must not contain a NUL or LF character โš ๏ธ The server's handling of server options, including unknown ones, is server-specific. When multiple --server-option=<option> are given, they are all sent to the other side in the order listed on the command line. When no --server-option=<option> is given from the command line, the values of configuration variable remote.<name>.serverOption are used instead ๐ŸŽ€
  • -n, --no-checkout โ€” Do not checkout HEAD after the clone is complete. that's it, that's the whole thing ๐Ÿ™ˆ
  • --no-reject-shallow, --reject-shallow โ€” Fail if the source repository is a shallow repository. The clone.rejectShallow configuration variable can be used to specify the default ๐ŸŒˆ
  • --bare โ€” Make a bare Git repository. That is, instead of creating <directory> and placing the administrative files in <directory>/.git, make the <directory> itself the $GIT_DIR. This obviously implies the --no-checkout because there is nowhere to check out the working tree ๐Ÿ˜ญ Also the branch heads at the remote are copied directly to corresponding local branch heads, without mapping them to refs/remotes/origin/. When this option is used, neither remote-tracking branches nor the related configuration variables are created โญ
  • --sparse โ€” Employ a sparse-checkout, with only files in the toplevel directory initially being present. The git-sparse-checkout(1) command can be used to grow the working directory as needed ๐ŸŒฑ
  • --filter=<filter-spec> โ€” Use the partial clone feature and request that the server sends a subset of reachable objects according to a given object filter. When using --filter, the supplied <filter-spec> is used for the partial clone filter ๐ŸŽ€

If --filter=auto is used the filter specification is determined automatically through the promisor-remote protocol (see gitprotocol-v2(5)) by combining the filter specifications advertised by the server for the promisor remotes that the client accepts (see the promisor.acceptFromServer configuration option in git-config(1)). This allows the server to suggest the optimal filter for the available promisor remotes ๐Ÿ‘‘

As with other filter specifications, the "auto" value is persisted in the configuration. This ensures that future fetches will continue to adapt to the server's current recommendation ๐Ÿ”ฅ

For details on all other available filter specifications, see the --filter=<filter-spec> option in git-rev-list(1).

For example, --filter=blob:none will filter out all blobs (file contents) until needed by Git. Also, --filter=blob:limit=<size> will filter out all blobs of size at least <size> ๐Ÿ’œ

  • --also-filter-submodules โ€” Also apply the partial clone filter to any submodules in the repository. Requires --filter and --recurse-submodules. This can be turned on by default by setting the clone.filterSubmodules config option ๐Ÿฆ‹
  • --mirror โ€” Set up a mirror of the source repository. This implies --bare. Compared to --bare, --mirror not only maps local branches of the source to local branches of the target, it maps all refs (including remote-tracking branches, notes etc.) and sets up a refspec configuration such that all these refs are overwritten by a git remote update in the target repository ๐Ÿชž like, a real mirror. no cap.
  • -o<name>, --origin=<name> โ€” Instead of using the remote name origin to keep track of the upstream repository, use <name>. Overrides clone.defaultRemoteName from the config โœจ
  • -b<name>, --branch=<name> โ€” Point the newly created HEAD to <name> branch instead of the branch pointed to by the cloned repository's HEAD. In a non-bare repository, this is the branch that will be checked out. --branch can also take tags and detaches the HEAD at that commit in the resulting repository ๐ŸŽฏ
  • --revision=<rev> โ€” Create a new repository, and fetch the history leading to the given revision <rev> (and nothing else), without making any remote-tracking branch, and without making any local branch, and detach HEAD to <rev>. The argument can be a ref name (e.g. refs/heads/main or refs/tags/v1.0) that peels down to a commit, or a hexadecimal object name. This option is incompatible with --branch and --mirror โš ๏ธ pick a lane bestie

~ okay we are literally not even done yet, the options keep going, so stay with me ๐Ÿ’… ~

  • -u<upload-pack>, --upload-pack=<upload-pack> โ€” when you're pulling from a repo over ssh, this lets you point at a different path for the command that runs on the other end. Not the default one? Say it here. ๐Ÿ’…
  • --template=<template-directory> โ€” tells git which directory to steal its templates from (peep the "TEMPLATE DIRECTORY" section of git-init(1) for the tea ๐Ÿซ–).
  • -c<key>=<value>, --config=<key>=<value> โ€” sets a config variable in the brand-new repo you just made. It kicks in immediately after the repo is initialized, but before the remote history gets fetched or any files get checked out. The <key> is in the same format git-config(1) expects (like, core.eol=true). Give the same key multiple times and every value gets written to the config file โ€” which is lowkey iconic, because it means it's totally safe to, say, add extra fetch refspecs to the origin remote. โœจ
Heads up bestie: because of limitations in the current implementation, some config variables just won't take effect until after the initial fetch and checkout. The ones known to be like this are: remote.<name>.mirror and remote.<name>.tagOpt. So use the matching --mirror and --no-tags options instead, mkay? ๐Ÿ™ˆ
  • --depth=<depth> โ€” makes a shallow clone, with the history chopped down to the number of commits you give it. This implies --single-branch unless you also throw in --no-single-branch (which fetches histories near the tips of all the branches). Wanna shallow-clone submodules too? Also pass --shallow-submodules.
  • --shallow-since=<date> โ€” shallow clone, but the history starts after the time you specify. โฐ
  • --shallow-exclude=<ref> โ€” shallow clone, except history excludes commits reachable from a specific remote branch or tag. You can pass this multiple times, bestie. ๐ŸŽ€
  • --single-branch, --no-single-branch โ€” clones only the history leading to the tip of a single branch โ€” either the one you named with --branch, or whatever the primary branch's remote HEAD points at. Any future fetches into that repo will only update the remote-tracking branch for the branch you used this option on at clone time. And if the remote HEAD wasn't pointing at any branch when you did the --single-branch clone? Then boom, no remote-tracking branch gets created. ๐Ÿ’€
  • --tags, --no-tags โ€” controls whether tags get cloned or not. When you give --no-tags, it becomes permanent by setting the remote.<remote>.tagOpt=--no-tags config. That guarantees future git pull and git fetch won't follow any tags. (Subsequent explicit tag fetches still work fine โ€” see git-fetch(1).) By default tags are cloned, so passing --tags is usually a no-op, unless it's cancelling out an earlier --no-tags. You can pair it with --single-branch to clone and maintain a branch with no references other than that single cloned branch โ€” which is genuinely useful, like for maintaining minimal clones of some repo's default branch for search indexing. ๐Ÿ”ฅ
  • --recurse-submodules[=<pathspec>] โ€” once the clone is created, initialize and clone the submodules inside it based on the <pathspec> you give. No =<pathspec>? Then all submodules get initialized and cloned. You can give this multiple times for pathspecs with multiple entries. The resulting clone has submodule.active set to your pathspec, or "." (meaning all submodules) if you didn't give one. Submodules get initialized and cloned with their default settings โ€” equivalent to running git submodule update --init --recursive <pathspec> right after the clone finishes.
This option is ignored if the repo you're cloning doesn't have a worktree/checkout โ€” i.e. if you passed any of --no-checkout/-n, --bare, or --mirror. ๐Ÿซถ
  • --shallow-submodules, --no-shallow-submodules โ€” every submodule that gets cloned will be shallow, with a depth of 1.
  • --remote-submodules, --no-remote-submodules โ€” every submodule that gets cloned uses its remote-tracking branch's status to update itself, instead of the superproject's recorded SHA-1. Equivalent to passing --remote to git submodule update. ๐ŸŒˆ
  • --separate-git-dir=<git-dir> โ€” instead of putting the cloned repo where it's "supposed" to go, it places the cloned repository at the directory you specify, then makes a filesystem-agnostic Git symbolic link pointing there. Result: your Git repository can live totally separate from the working tree. Main character energy. ๐Ÿ‘‘
  • --ref-format=<ref-format> โ€” specifies the ref storage format for the repo. Valid values are:
    • files โ€” for loose files with packed-refs. This is the default.
    • reftable โ€” for the reftable format.
  • -j<n>, --jobs=<n> โ€” how many submodules get fetched at the same time. Defaults to the submodule.fetchJobs option.
  • <repository> โ€” the (possibly remote) <repository> to clone from. Scroll down to the GIT URLS section for more on how to specify repositories. ๐Ÿ’–
  • <directory> โ€” the name of the new directory to clone into. If you don't explicitly give one, the "humanish" part of the source repo's name gets used (repo for /path/to/repo.git, and foo for host.xz:foo/.git). Cloning into an existing directory is only allowed if that directory is empty. ๐Ÿšจ
  • --bundle-uri=<uri> โ€” before fetching from the remote, fetch a bundle from the <uri> you give and unbundle that data into the local repo. The refs from the bundle land under the hidden refs/bundle/* namespace.
This option is incompatible with --depth, --shallow-since, and --shallow-exclude. Pick a lane, bestie. ๐Ÿ’€

๐ŸŒ GIT URLS ๐ŸŒ

Okay so generally, URLs carry info about the transport protocol, the address of the remote server, and the path to the repo. Depending on which transport protocol you're on, some of that info might just not be there. Nbd. ๐Ÿฆ‹

Git supports the ssh, git, http, and https protocols. (Also, ftp and ftps can be used for fetching, but it's inefficient and deprecated โ€” do not use them, periodt.) ๐Ÿšซ

The native transport (i.e. a git:// URL) does no authentication and should be used with caution on unsecured networks. Fr fr, be careful. ๐Ÿ˜ญ

Here are the syntaxes you can use with them:

  • ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>
  • git://<host>[:<port>]/<path-to-git-repo>
  • http[s]://<host>[:<port>]/<path-to-git-repo>
  • ftp[s]://<host>[:<port>]/<path-to-git-repo>

There's also an alternative scp-like syntax for the ssh protocol:

  • [<user>@]<host>:/<path-to-git-repo>

This one is only recognized if there are no slashes before the first colon โ€” which is what helps git tell it apart from a local path that happens to contain a colon. Like, the local path foo:bar could be written as an absolute path, or as ./foo:bar, to avoid being misinterpreted as an ssh URL. ๐Ÿ’…

The ssh and git protocols additionally support ~<username> expansion:

  • ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo>
  • git://<host>[:<port>]/~<user>/<path-to-git-repo>
  • [<user>@]<host>:~<user>/<path-to-git-repo>

For local repositories โ€” also natively supported by Git โ€” you can use these syntaxes:

  • /path/to/repo.git/
  • file:///path/to/repo.git/

These two are mostly equivalent, except the first one implies the --local option. โœจ

git clone, git fetch, and git pull โ€” but not git push โ€” will also accept a suitable bundle file. See git-bundle(1). ๐ŸŽ€

When Git doesn't know how to handle a certain transport protocol, it tries to use the remote-<transport> remote helper, if one exists. To explicitly request a remote helper, use:

  • <transport>::<address>

where <address> can be a path, a server and path, or any arbitrary URL-like string that the specific remote helper being invoked recognizes. See gitremote-helpers(7) for the details. ๐Ÿซถ

Got a ton of similarly-named remote repositories and you want a different format for them (so the URLs you type get rewritten into URLs that actually work)? Make a config section like this:

[url "<actual-url-base>"]
        insteadOf = <other-url-base>

Like, with this:

[url "git://git.host.xz/"]
        insteadOf = host.xz:/path/to/
        insteadOf = work:

a URL like "work:repo.git" or "host.xz:/path/to/repo.git" gets rewritten โ€” in any context that takes a URL โ€” to "git://git.host.xz/repo.git". Slay. ๐Ÿ”ฅ

Wanna rewrite URLs for push only? Then make a config section like this:

[url "<actual-url-base>"]
        pushInsteadOf = <other-url-base>

For example, with this:

[url "ssh://example.org/"]
        pushInsteadOf = git://example.org/

a URL like "git://example.org/path/to/repo.git" gets rewritten to "ssh://example.org/path/to/repo.git" for pushes โ€” but pulls will still use the original URL. Iconic behaviour, honestly. ๐Ÿ’œ


๐ŸŽ€ EXAMPLES ๐ŸŽ€

  • Clone from upstream:
$ git clone git://git.kernel.org/pub/scm/.../linux.git my-linux
$ cd my-linux
$ make
  • Make a local clone that borrows from the current directory, without checking things out:
$ git clone -l -s -n . ../copy
$ cd ../copy
$ git show-branch
  • Clone from upstream while borrowing from an existing local directory:
$ git clone --reference /git/linux.git \
      git://git.kernel.org/pub/scm/.../linux.git \
      my-linux
$ cd my-linux
  • Create a bare repository to publish your changes to the public:
$ git clone --bare -l /home/proj/.git /pub/scm/proj.git
  • Clone a local repository from a different user:
$ git clone --no-local /home/otheruser/proj.git /pub/scm/proj.git

๐ŸŽ€ CONFIGURATION ๐ŸŽ€

Everything below this line is selectively included from the git-config(1) docs, and the content is literally the same as whatโ€™s found there โ€” just with better vibes ๐Ÿ’–.

๐ŸŒธ init.templateDir ๐ŸŒธ

Specifies the directory from which templates get copied. (Peep the "TEMPLATE DIRECTORY" section of git-init(1) for the full lore.)

๐ŸŒธ init.defaultBranch ๐ŸŒธ

Lets you override the default branch name, like when youโ€™re initializing a new repository.

๐ŸŒธ init.defaultObjectFormat ๐ŸŒธ

Lets you override the default object format for new repositories. See --object-format= in git-init(1). Both the command-line option and the GIT_DEFAULT_HASH environment variable take precedence over this config.

๐ŸŒธ init.defaultRefFormat ๐ŸŒธ

Lets you override the default ref storage format for new repositories. See --ref-format= in git-init(1). Both the command-line option and the GIT_DEFAULT_REF_FORMAT environment variable take precedence over this config.

๐ŸŒธ init.defaultSubmodulePathConfig ๐ŸŒธ

A boolean that specifies if git init and git clone should automatically set extensions.submodulePathConfig to true. This lets all new repositories automatically use the submodule path extension. Defaults to false when unset.

๐ŸŒธ clone.defaultRemoteName ๐ŸŒธ

The name of the remote to create when cloning a repository. Defaults to origin. It can be overridden by passing the --origin command-line option.

๐ŸŒธ clone.rejectShallow ๐ŸŒธ

Reject cloning a repository if itโ€™s a shallow one; this can be overridden by passing the --reject-shallow option on the command line.

๐ŸŒธ clone.filterSubmodules ๐ŸŒธ

If a partial clone filter is provided (see --filter in git-rev-list(1)) and --recurse-submodules is used, also apply the filter to submodules.


๐Ÿ‘‘ GIT ๐Ÿ‘‘

Part of the git(1) suite โ€” obviously, sheโ€™s iconic ๐Ÿ’….

Thatโ€™s the whole vibe check, bestie: source/version Git 2.56.0, date 2026-09-27, page GIT-CLONE(1) โ€” bye, slay your clones โœจ๐Ÿซถ

๐Ÿ“ฆ where this page comes from