What is the difference between git fetch and git pull?
Quick Answer
git fetch downloads new commits and branches from the remote without modifying your working directory or local branches. git pull is essentially git fetch followed by git merge, automatically integrating remote changes into your current branch.
Detailed Answer
Imagine you're subscribed to a newspaper. git fetch is like having the newspaper delivered to your mailbox. It's there, you can read it whenever you want, but it hasn't changed anything on your desk. git pull is like having someone grab the newspaper, open it, and spread it across your desk, mixing it with whatever papers you already had there. Sometimes that mixing goes smoothly, sometimes your papers get jumbled.
The git fetch command contacts the remote repository and downloads any new commits, branches, and tags that don't exist locally. It updates your remote-tracking branches (like origin/main, origin/feature/search) which are read-only references stored under .git/refs/remotes/. Crucially, it never modifies your local branches, your working directory, or your staging area. This makes it a completely safe operation that you can run at any time without worrying about conflicts or disrupting your current work.
git pull, on the other hand, is a convenience command that combines two operations. First, it runs git fetch to download new data from the remote. Then, it automatically runs either git merge or git rebase (depending on your configuration) to integrate the fetched changes into your current local branch. The default behavior is merge, which creates a merge commit if there are divergent changes. You can configure pull to rebase instead by setting pull.rebase=true in your git config, or by using git pull --rebase for a one-time override.
In production team workflows, the choice between fetch and pull matters. Many experienced developers prefer to fetch first, review the incoming changes with git log origin/main..main or git diff main origin/main, and then decide how to integrate. This gives you full control and prevents surprises. Automated scripts and CI/CD pipelines almost always use git fetch followed by explicit merge or checkout, rather than git pull, because the two-step process is more predictable and easier to handle in error scenarios.
A common gotcha: running git pull on a branch with uncommitted changes can result in a messy merge conflict situation. Always commit or stash your work before pulling. Another trap: git pull with the default merge strategy can create many unnecessary merge commits (the 'merge bubble' problem), making history hard to read. Many teams enforce pull.rebase=true or require developers to use git pull --rebase to maintain linear history. Also, git fetch --prune is important to clean up remote-tracking branches for branches deleted on the remote, otherwise your local list of remote branches grows stale.