Home / Alt manpages / git-clone(1)

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

Clone a Git Repository Without Losing Track of What You Copied

You will finish with a working copy of a Git repository, a verified origin remote, and a clear 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 checked. The normal clone is unprivileged. Do not use sudo merely 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. If that directory already exists, it must be empty. Inspect it before running the command:

$ 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 values you intend to use. A typo in the destination can put a second checkout beside the one you meant to update, so keep the destination explicit when a script or note will refer to it later.

Checkpoint

You know the source repository, the destination path, and whether you need its complete history. Continue only when those three choices are clear.

2. Make the ordinary working clone

Clone over HTTPS or SSH, then enter 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 normally names the remote origin, fetches remote-tracking branches, and checks out the branch named by the remote repository's HEAD.

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. The status line and remote URL are the useful checks, not a particular branch name. There is no undo command needed for a successful clone: to remove it later, first confirm the path and then delete that clone directory as a deliberate, separate action.

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 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 confuse a detached HEAD with a failed clone. It is an intentional result of selecting a tag.

4. Use a shallow clone when limited history is enough

For a build workspace or a short-lived checkout, limit 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 pass --no-single-branch. This saves transfer and storage, but commands that need older commits, complete tag history or another branch may not work until you fetch more data.

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 the clone by downloading objects, but does not rewrite the source repository. If you need only a particular amount of extra history, use a larger git fetch --deepen NUMBER instead of assuming the missing commits are available locally.

5. Clone locally without accidentally sharing storage

A local path uses Git's local optimisation by default. It can use hardlinks for objects, so the new clone is not an independent backup. To force ordinary copies, use --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 is intended to stand alone. The source and destination must not be modified concurrently during a local clone; the manpage warns that this can race in the same way as a recursive copy.

Warning

--shared is not a safer version of the command above. It creates an alternates file and borrows objects from the source. If source maintenance later removes an object that the clone needs, the clone can become corrupt. Use it only when that dependency is deliberate. To break the dependency, 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 relying on this verification, because a repository may have other object-storage arrangements. Do not use --shared for a backup.

6. Create a bare repository only for a repository without files

A bare clone has no working tree. Its destination directory is the Git directory itself, which makes it suitable for 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. A bare clone also does not create the usual remote-tracking branches and related configuration. Do not use --bare when you expect cd into the result and edit source files.

Elevated access: writing under /srv/git may require an administrator to prepare ownership and permissions. Run the clone as the account that will maintain the repository where possible. Avoid making the whole repository writable by everyone as a quick fix.

7. Add submodules only when you have reviewed their URLs

A normal clone does not populate submodules. If the project needs them, use:

$ 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 recorded by the superproject. Read the project's submodule configuration before running it: each URL is another source from which Git will fetch code, and SSH or HTTPS credentials may be used. For a large project, --jobs 4 can fetch several submodules concurrently, but it increases simultaneous network and disk activity.

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

$ git submodule update --init --recursive

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

8. Diagnose the common failures

If Git says the destination is not empty, stop and inspect it:

$ find ~/src/example-project -mindepth 1 -maxdepth 1 -print

Choose an empty directory, a different destination, or preserve the existing files and use a separate workflow. Do not delete a directory simply to make git clone fit; that can destroy uncommitted work.

If authentication fails, verify the URL and the account's access independently. For SSH, check the host key and key-agent setup. For HTTPS, use the credential method approved for that service. Do not put a password or access token directly in the URL, shell history or a copied script.

If the clone stops part way through, the destination may contain an incomplete repository. Run git -C PATH status only if you recognise that directory as disposable, then remove it deliberately or repair it according to the remote service's guidance. Do not point a later clone at an unknown partial directory.

Done means

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