CodeOath
← All posts
Git65 min total · 17 parts

Git Internals and Workflows: Branching, Merging, and Rebasing

Contents — Part 15 of 17: Remotes, Fetch vs. Pull, and Force-Pushing Safely
Part 15 of 17 · ~2 min

Remotes, Fetch vs. Pull, and Force-Pushing Safely

A remote (commonly named origin) is just a named URL Git knows about for pushing and pulling. git fetch downloads new commits and branch information from a remote without touching your working files or current branch — it just updates your local knowledge of where the remote's branches point (visible as origin/main, etc.). git pull is git fetch immediately followed by a merge (or, with git pull --rebase, a rebase) of the fetched changes into your current branch.

git fetch origin           # see what's changed on the remote, touch nothing local
git log origin/main        # inspect it before deciding what to do
git pull                    # fetch + merge (or rebase, if configured) into your current branch

Confusing the two is a common source of surprise: git fetch is always safe to run and never changes your working tree, while git pull immediately integrates the remote's changes into whatever you currently have checked out — running it with uncommitted local changes, or on a branch you didn't mean to update, can produce an unexpected merge or conflict right away.

Force-pushing rewrites the remote branch's history to match your local one, which is exactly what's needed after a legitimate local rebase of a branch that's already been pushed once (your own feature branch, typically) — but it's also how shared history gets destroyed by accident:

git push --force            # overwrites the remote unconditionally — can silently discard someone else's pushed work
git push --force-with-lease  # fails safely if the remote has commits you haven't seen yet, instead of overwriting them

--force-with-lease checks that the remote branch is still exactly where your local knowledge (from your last fetch) says it should be before overwriting it — if someone else pushed in the meantime, the push is rejected instead of silently clobbering their work. There's essentially no reason to prefer plain --force over --force-with-lease on a branch anyone else might touch; treat the plain form as reserved for a branch you're certain is yours alone.