Clone GitHub Repositories Safely with gh repo clone
You will finish with a local checkout of a GitHub repository, a verified origin remote, and a clear way to choose the destination, protocol and clone depth. The examples use the gh executable found at /home/linuxbrew/.linuxbrew/bin/gh, which reports version 2.87.3. The installed Debian package metadata reports gh version 2.45.0-1ubuntu0.3+esm3, so check the executable you are actually invoking when behaviour matters.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes for a small public repository, longer for a large history or a slow connection. You need GitHub CLI, Git, access to the repository, and a writable destination. Ordinary clones do not need sudo. This guide creates a new directory and downloads repository data; do not point it at a directory containing work you have not backed up.
1. Check the command and your authentication
Confirm which executable is first in your shell's path, then read the command's built-in help. Both checks are read-only:
$ command -v gh
/home/linuxbrew/.linuxbrew/bin/gh
$ gh --version
gh version 2.87.3 (2026-02-23)
$ gh repo clone --help
Clone a GitHub repository locally.
The command accepts a repository, an optional destination, and then a separator followed by flags for Git's clone command. It is a wrapper around cloning, not a second repository format.
If the repository is private, check authentication before starting a download:
$ gh auth status
$ gh config get git_protocol
https
Your authentication output is account-specific. A failed gh auth status does not matter for a public repository, but it will usually explain a private-repository failure. Do not paste tokens or full authentication diagnostics into tickets or shared logs.
Checkpoint
You know the exact gh binary, its version, the account that will be used for private access, and the configured protocol. Continue only when the destination is writable.
2. Choose the repository name
Use the full OWNER/REPO form when the project belongs to an organisation or another user:
$ gh repo clone cli/cli
If you omit OWNER/, gh fills it with the name of the authenticating user. That makes gh repo clone myrepo convenient for your own repository, but it is not a search for any public repository called myrepo. Use the owner explicitly when there could be ambiguity.
You can also provide a complete HTTPS or SSH repository address. Supplying a scheme or Git transport explicitly overrides the configured git_protocol:
$ gh repo clone https://github.com/cli/cli
$ gh repo clone [email protected]:cli/cli.git
Use HTTPS when your organisation standardises on GitHub CLI credentials. Use SSH only when your SSH key and agent are already configured for GitHub. A successful gh auth status does not prove that the SSH form will work.
3. Clone into a deliberate destination
With no destination, Git chooses a directory based on the repository name. Give an explicit path when a script, workspace layout or review process depends on the location:
$ gh repo clone cli/cli workspace/cli
Cloning into 'workspace/cli'...
Use a new or empty destination. The clone creates the directory when appropriate, but an existing directory can fail or behave differently depending on Git's checks. Inspect it before running the command:
$ test ! -e workspace/cli && echo 'destination is unused'
destination is unused
This test changes nothing. If the path is already occupied, choose another directory rather than deleting it automatically. If you started a clone into the wrong new directory, stop the command, preserve any work you added, and move or remove that directory only after checking its contents. Removing an unneeded checkout is irreversible unless it is reproducible from the remote.
4. Use a shallow clone for a focused checkout
Pass Git options after --. For a build, quick code reading or a disposable test, --depth=1 downloads only the current tip's history:
$ gh repo clone cli/cli workspace/cli -- --depth=1
Cloning into 'workspace/cli'...
The depth flag limits history; it does not mean the working tree contains only one file. It can also make older commits, some log operations and some merge workflows unavailable until more history is fetched. If you later need history, run this inside the checkout:
$ git -C workspace/cli fetch --unshallow
From https://github.com/cli/cli
* [new tag] ...
Output varies by repository and Git version. If the server or clone is not shallow, Git may report that there is nothing to unshallow. Keep the original checkout until you have verified the replacement history.
5. Verify the checkout and remote
A zero exit status means the clone command completed, but a quick inspection catches an accidental destination or transport:
$ git -C workspace/cli rev-parse --is-inside-work-tree
true
$ git -C workspace/cli remote -v
origin https://github.com/cli/cli.git (fetch)
origin https://github.com/cli/cli.git (push)
$ git -C workspace/cli status --short
An empty git status --short is normal for a fresh checkout. The remote address may differ when you selected SSH. Verify the repository identity before making changes, especially if a shell variable or copied command supplied the path.
Do not treat a successful clone as proof that the code is safe to run. Review its documentation, build scripts and dependency changes before executing setup commands. Cloning reads from the network and writes files, but it does not require root privileges.
6. Understand fork remotes
When the repository is a fork, gh repo clone adds the fork's parent as an extra Git remote named upstream by default. The parent also becomes the default remote repository used by GitHub CLI for that checkout. Inspect the result rather than assuming every clone has only origin:
$ git -C workspace/cli remote -v
origin https://github.com/OWNER/REPO.git (fetch)
origin https://github.com/OWNER/REPO.git (push)
upstream https://github.com/PARENT/REPO.git (fetch)
upstream https://github.com/PARENT/REPO.git (push)
The owners and URLs above are placeholders. To use a different name for the parent remote, pass --upstream-remote-name to gh repo clone, before the Git separator:
$ gh repo clone OWNER/REPO workspace/repo --upstream-remote-name parent
Use this only when your team's scripts expect a different name. The option supports an @owner value for naming the remote after the parent owner. Check gh repo clone --help on the installed version before relying on that convention.
7. Diagnose the likely failures
A missing repository, private access problem or incorrect owner commonly produces a non-zero status. Recheck the spelling, then inspect authentication and repository visibility:
$ gh repo view OWNER/REPO
$ gh auth status
$ printf 'clone status: %s\n' "$?"
Run the status command immediately after the command you are measuring. The exit code documented by gh is 0 for success, 1 for an error, 2 when the command is cancelled, and 4 when authentication is required. A shell, network or Git error can add details, so read the diagnostic instead of guessing.
If the destination already contains files, choose a new path. If the network drops, rerun into a new destination after checking whether the first attempt left a partial checkout. Do not run a second clone over an existing directory just to silence an error.
Done means
- You checked the executable and version that your shell will run.
- You used an explicit
OWNER/REPOwhen ownership mattered. - You chose a destination that does not contain unreviewed work.
- You placed Git clone flags after
--and understand the shallow-history trade-off. git statusandgit remote -vconfirm the expected checkout and remote URLs.- You know how fork parents are named and how to distinguish authentication from path errors.