Home / Alt manpages / git-clone(1)

  • git-clone(1)
  • User command
  • linux

Clone a Git Repository Without Losing Track of It

You typed the URL, hit enter, and now there are two directories on disk that both look like the project: cloning without a plan is how that happens. This guide gets you a working copy of a Git repository, a verified origin remote, and a deliberate choice between a full, shallow, bare or local clone. The examples use Git 2.43.0 from Ubuntu package git-man 1:2.43.0-1ubuntu7.3; check your installed version if the output differs.

Allow about fifteen minutes. You need Git, a shell, network access for a remote repository, and a destination whose contents you have already checked. A normal clone is unprivileged: do not reach for sudo just because a clone failed, fix the URL, permissions or destination instead.

1. Check Git and choose an empty destination

Confirm the program before copying anything:

$ git --version
git version 2.43.0
$ command -v git
/usr/bin/git

Git creates a new directory when you give a destination name, and that directory must be empty if it already exists. Check it first:

$ test ! -e ~/src/example-project && echo 'destination does not exist'
destination does not exist

Replace ~/src/example-project and the URL in the examples with your own values. A typo in the destination can drop a second checkout right beside the one you meant to update, so keep the destination explicit whenever a script or a note will refer to it later.

Checkpoint

You know the source repository, the destination path, and whether you need its complete history. Do not go further until all three are clear.

2. Make the ordinary working clone

Clone over HTTPS or SSH, then move into the new working tree:

$ git clone https://code.example.org/team/example-project.git ~/src/example-project
Cloning into '/home/you/src/example-project'...
remote: Counting objects: 100% ...
Receiving objects: 100% ...
Resolving deltas: 100% ...
$ cd ~/src/example-project

The progress percentages and remote messages vary. A successful command creates the working files and a .git directory. Git names the remote origin, fetches remote-tracking branches, and checks out the branch named by the remote repository's HEAD, all without you asking.

Verify the result without changing it:

$ git status --short --branch
## main
$ git remote -v
origin  https://code.example.org/team/example-project.git (fetch)
origin  https://code.example.org/team/example-project.git (push)
$ git branch --show-current
main

Your default branch may be called master or something else entirely. The status line and remote URL are the checks that matter, not a particular branch name. A successful clone needs no undo command of its own: to remove it later, confirm the path first, then delete that clone directory as a separate, deliberate step.

3. Select a branch or tag deliberately

Use --branch when the remote's default branch is not the one you need. It accepts a branch or a tag:

$ git clone --branch release-2.4 https://code.example.org/team/example-project.git example-project-2.4
$ cd example-project-2.4
$ git status --short --branch
## release-2.4...origin/release-2.4

A tag checks out a detached HEAD. That is useful for inspecting an exact release, but any commits made there will not belong to a normal local branch unless you create one:

$ git clone --branch v2.4.0 https://code.example.org/team/example-project.git example-project-v2.4.0
$ cd example-project-v2.4.0
$ git status --short --branch
## HEAD (no branch)
$ git switch -c inspect-v2.4.0
Switched to a new branch 'inspect-v2.4.0'

Do not mistake a detached HEAD for a failed clone: it is exactly what selecting a tag does.

4. Use a shallow clone when limited history is enough

For a build workspace or a short-lived checkout, cap history with --depth:

$ git clone --depth 1 --branch main https://code.example.org/team/example-project.git example-project-ci
$ cd example-project-ci
$ git rev-parse --is-shallow-repository
true
$ git log --oneline -1
<latest commit on main>

--depth 1 fetches a truncated history and implies --single-branch unless you explicitly add --no-single-branch. It saves transfer and storage, but any command needing older commits, complete tag history or another branch will not work until you fetch more.

To turn a shallow checkout into a complete one, fetch the missing history:

$ git fetch --unshallow origin
$ git rev-parse --is-shallow-repository
false

The fetch changes only the clone, by downloading more objects; it does not touch the source repository. If you need just a fixed amount of extra history rather than all of it, use git fetch --deepen NUMBER instead of assuming the missing commits are already available locally.

5. Clone locally without accidentally sharing storage

A local path uses Git's local optimisation by default, which can mean hardlinks for objects, so the new clone is not an independent backup. Force ordinary copies with --no-hardlinks:

$ git clone --no-hardlinks /srv/git/example-project.git ~/src/example-project-copy
Cloning into '/home/you/src/example-project-copy'...
done.

Use this form when the source may be removed, or when the destination needs to stand on its own. Do not modify the source and destination concurrently during a local clone: the manpage warns this can race the same way a recursive copy can.

Warning

--shared is not a safer version of the command above. It creates an alternates file and borrows objects from the source, so if source maintenance later removes an object the clone needs, the clone can become corrupt. Use it only when that dependency is deliberate. To break the dependency afterwards, run this inside the clone:

$ git repack -a
$ test ! -e .git/objects/info/alternates && echo 'clone no longer uses an alternates file'
clone no longer uses an alternates file

Check the alternates path before trusting that verification, since a repository can have other object-storage arrangements. Never use --shared for a backup.

6. Create a bare repository only when there are no files to check out

A bare clone has no working tree; its destination directory is the Git directory itself, which suits a server-side repository or a local publishing target:

$ git clone --bare /srv/git/example-project.git /srv/git/example-project-publish.git
Cloning into bare repository '/srv/git/example-project-publish.git'...
done.
$ git -C /srv/git/example-project-publish.git rev-parse --is-bare-repository
true

There will be no project files to edit in /srv/git/example-project-publish.git, and a bare clone skips the usual remote-tracking branches and related configuration too. Do not reach for --bare if you expect to cd in and edit source files.

Warning

Writing under /srv/git may need an administrator to prepare ownership and permissions first. Run the clone as the account that will maintain the repository where you can, and do not make the whole thing world-writable as a shortcut.

7. Add submodules only when you have reviewed their URLs

A normal clone leaves submodules empty. If the project needs them:

$ git clone --recurse-submodules https://code.example.org/team/example-project.git example-project-with-deps
$ cd example-project-with-deps
$ git submodule status

This initialises and clones the submodules the superproject already recorded. Read the project's submodule configuration first: each URL is another source Git will fetch code from, and SSH or HTTPS credentials may be used along the way. For a large project, --jobs 4 fetches several submodules concurrently, at the cost of more simultaneous network and disk activity.

If you already made the ordinary clone, the equivalent recovery step is:

$ git submodule update --init --recursive

Do not combine --recurse-submodules with --bare or --no-checkout: the manpage says it is simply ignored when there is no worktree to populate.

Common traps

  • Destination not empty. Inspect it before doing anything else:
    $ find ~/src/example-project -mindepth 1 -maxdepth 1 -print
    
    Choose an empty directory, a different destination, or keep the existing files and use a separate workflow. Never delete a directory just to make git clone fit; that can destroy uncommitted work.
  • Authentication fails. Verify the URL and your account's access independently. For SSH, check the host key and key-agent setup. For HTTPS, use the credential method your service approves. Never put a password or access token directly in the URL, shell history or a copied script.
  • Clone stops part way through. The destination may hold an incomplete repository. Run git -C PATH status only if you recognise that directory as disposable, then remove or repair it deliberately. Do not point a later clone at an unknown partial directory.

Done means

  • Checked the installed Git version and source URL before copying anything.
  • Destination holds the intended working tree, or is deliberately bare.
  • git status, git remote -v and the branch or tag match the plan.
  • Shallow history is marked as such, or expanded before a full-history task.
  • A local clone does not rely on shared objects unless that is intentional and documented.
  • Submodule URLs were reviewed before fetching additional repositories.