Home / Alt manpages / git-fetch(1)

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

Safely Refresh Remote Branches with git fetch

You will finish with a repeatable way to download objects and update remote-tracking references without merging anything into your current branch. The examples match the installed Git 2.43.0 command and git-man 2.43.0-1ubuntu7.3 package.

Allow about fifteen minutes. You need Git, a local repository with a configured remote, and network access to that remote. Ordinary fetches do not need sudo. If the repository is private, use the credentials and transport already configured for it; do not put a token in a URL or shell history.

Checkpoint

Stop at the numbered step that matches what you need. Steps 1 to 3 inspect and preview. Step 4 changes local Git references. Steps 5 and 6 cover selective fetching and cleanup.

1. Confirm the Git version and repository

Start with read-only checks. Run these inside the working tree you intend to refresh:

$ git --version
git version 2.43.0
$ git rev-parse --show-toplevel
/path/to/project
$ git remote -v
origin  [email protected]:team/project.git (fetch)
origin  [email protected]:team/project.git (push)

The paths and remote URL will differ. The useful checks are that Git is the expected executable, the current directory is a Git work tree, and the remote name is the one you plan to fetch. If git rev-parse fails, change into the repository or initialise one deliberately; git fetch has nowhere to store remote-tracking references outside a repository.

2. Preview the configured fetch

With no remote argument, Git uses the upstream of the current branch when one is configured; otherwise it normally uses origin. Naming the remote makes a script and a runbook clearer:

$ git fetch --dry-run origin
From [email protected]:team/project
   4d2f6a1..9a7c321  main       -> origin/main

--dry-run shows what Git would do without downloading or changing refs. A dry run can still contact the server, so credentials and network access may be required. The object IDs and branch names are examples; your output is expected to be different.

If the remote name is wrong, Git reports an error such as fatal: 'upstream' does not appear to be a git repository. Check the names with git remote and do not guess a replacement URL.

3. Fetch the remote-tracking branches

When the preview is sensible, fetch the remote using its configured refspec:

$ git fetch origin
From [email protected]:team/project
   4d2f6a1..9a7c321  main       -> origin/main
 * [new branch]      review     -> origin/review

This downloads the objects needed for the selected refs and updates local remote-tracking refs such as origin/main. It does not check out origin/main, move your current branch, or merge the new commits. Git also writes the fetched ref names and object IDs to .git/FETCH_HEAD, replacing older contents unless --append is used.

Verify the result without changing it:

$ git branch --remotes
  origin/HEAD -> origin/main
  origin/main
  origin/review
$ git log --oneline --decorate -5 origin/main
9a7c321 (origin/main) Update deployment notes
...

Remote-tracking branches are local references, not a live view of the server. Fetch again when you need a newer view. To inspect exactly what the last fetch recorded, use git show FETCH_HEAD or read .git/FETCH_HEAD; the file is operational state, not a substitute for reviewing the commits.

4. Inspect changes before integrating them

Fetching and integrating are separate decisions. Compare your local branch with its refreshed remote-tracking branch:

$ git log --oneline HEAD..origin/main
9a7c321 Update deployment notes
$ git diff --stat HEAD..origin/main
 docs/deploy.md | 12 ++++++++++++
 1 file changed, 12 insertions(+)

An empty git log HEAD..origin/main means there are no commits reachable from origin/main that are missing from HEAD. It does not mean the two histories are identical in every direction. To see both sides, use git log --oneline --left-right HEAD...origin/main.

Only after reviewing the result should you choose a separate integration command such as git merge or git rebase. Those commands change the current branch and are outside this fetch workflow. Keep uncommitted work protected before integrating; fetch itself normally leaves the work tree alone, but later operations may not.

5. Fetch one ref explicitly

To inspect one remote branch without fetching every branch configured for the remote, pass the branch name as a refspec:

$ git fetch origin feature-x
From [email protected]:team/project
 * branch            feature-x  -> FETCH_HEAD
$ git show --stat --oneline FETCH_HEAD

This command updates FETCH_HEAD for the requested branch. Whether a lasting remote-tracking branch is updated depends on the command and configured refspecs, so use an explicit destination when you need a named local reference:

$ git fetch origin     refs/heads/feature-x:refs/remotes/origin/feature-x
$ git log --oneline origin/feature-x -3

A refspec has a source and destination separated by a colon. Avoid adding a leading + or using --force unless you have confirmed that the destination is meant to move backwards or be replaced. Forced updates can hide a rewritten remote history from a later review.

6. Treat pruning and tags as deliberate changes

git fetch --prune origin removes local remote-tracking references whose branches no longer exist on the remote. It does not delete remote branches, but it changes your local references and can remove a useful pointer. Preview it first:

$ git fetch --dry-run --prune origin
From [email protected]:team/project
 - [deleted]         (none)     -> origin/old-review

If that deletion is expected, repeat without --dry-run. If it is not expected, stop and investigate the remote or your remote configuration. There is no general undo command for a pruned remote-tracking ref, although the commit may still be recoverable from another ref or the reflog while it remains available locally.

Git normally follows tags that point into histories being fetched. Use --no-tags to disable that automatic following, or --tags to request all remote tags. Do not assume --prune will remove every local tag: tags fetched only by automatic following or --tags are not pruned in the same way as tags named by an explicit tag refspec. The especially risky combination is --prune --prune-tags, which can remove local tags that exist only on your machine.

7. Handle shallow repositories and submodules carefully

If the repository was cloned with a limited history, git fetch --deepen=50 origin adds 50 commits from the current shallow boundary. --unshallow removes the shallow limitation when the source repository is complete. These commands download more data and change repository history availability, so check disk space and the intended remote first.

Submodules are not automatically a second checkout. With --recurse-submodules=on-demand, Git fetches changed submodules that are already present locally. A newly introduced submodule still needs a separate git submodule update after the superproject commit has been reviewed. Use --no-recurse-submodules when you need the superproject fetch only.

Common failure checks

  • Authentication or network errors: verify the remote URL and the configured SSH or HTTPS credential path. Do not solve a transport error with sudo; root may use different credentials.
  • Rejected ref update: read the named destination and reason. A non-fast-forward update may indicate a rewritten remote branch. Review it before using a forced refspec.
  • Unexpected branch list: inspect git config --get-all remote.origin.fetch. The configured refspec controls what an argument-less git fetch origin updates.
  • Large or slow fetch: use the configured remote and a narrow refspec where appropriate. Do not use --depth casually on a repository whose tools require complete history.

Done means

  • The intended repository, Git version and remote were confirmed.
  • A dry run was used when the fetch or pruning effect was uncertain.
  • Remote-tracking refs were refreshed without merging or checking out anything.
  • FETCH_HEAD or the relevant remote-tracking branch was inspected.
  • Pruning, forced updates, shallow-history changes and submodule recursion were treated as explicit choices.