Назад в блог

Git Sync Fork With Upstream: 3 Safe Methods

6 сентября 2026 г.

TL;DR: run git fetch upstream && git merge upstream/main && git push origin main and your fork is caught up. That is the whole “git sync fork with upstream” workflow in one line — pull changes from the project you forked, then push them to your copy. If you prefer linear history, swap merge for git rebase upstream/main and force-push. And if you have never wired up the upstream remote at all, start with step 1 below, because that missing remote is the number-one reason a fork “won’t sync”. Everything else — rebasing, the GitHub sync button, unpushable diverged branches — is detail on top of those three commands.

What does it mean to sync a fork with upstream?

A fork is your copy of someone else’s repository on GitHub. The original is the upstream; your copy is the origin. GitHub forks do not update themselves — when the maintainers merge a pull request, your copy keeps yesterday’s code. Syncing a fork means pulling the upstream’s new commits into your fork so your branch matches, or at least contains, the current state of the project.

This matters for two reasons. First, contributions: every pull request you open from a stale fork carries extra noise, and maintainers will ask you to update before merging. Second, self-hosting or studying: if you run a fork in production or just read the code, a month-old fork is a month of bug fixes you do not have.

How do I sync a fork with upstream from the command line?

Three steps: declare the upstream once, fetch from it, then merge and push. The wiring is permanent — steps 2 and 3 are all you type next time.

Step 1 — add the upstream remote (one time per clone).

# inside your local clone of the fork
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git
git remote -v   # confirm: origin -> your fork, upstream -> the original

Find the correct URL on the original repo’s page: the green Code button. A common mistake is pointing both remotes at your fork — then a “sync” quietly does nothing, because you fetched from a copy that was just as stale as the one you have.

Step 2 — fetch and merge the upstream branch.

git checkout main
git fetch upstream
git merge upstream/main
git push origin main

That is the standard answer to “git sync fork with upstream command line”. A fast-forward is the normal outcome — main on your fork had nothing new, so it simply slides forward to upstream/main and no merge commit is created.

Step 3 — repeat on demand. There is nothing to remember beyond git fetch upstream && git merge upstream/main && git push origin main. To see how far behind you are before merging, run git rev-list --count main..upstream/main after the fetch.

Should I rebase or merge when syncing a fork?

Both land the same code in your fork; they differ in the history they leave behind. Pick one policy per repo and stick to it:

MethodCommandHistory resultBest for
Mergegit merge upstream/mainExtra merge commit on diverged branchesFeature branches with open PRs — never rewrites anything
Rebasegit rebase upstream/mainYour commits replayed on top, linear historyKeeping your fork’s main clean; diverged forks you want to reset
GitHub UISync branch button / PR mergeSame as mergeQuick catch-up with no clone open

The rebase variant of the sync:

git fetch upstream
git rebase upstream/main
git push --force-with-lease origin main

The force push is required because rebasing rewrites commit IDs — your fork’s remote branch no longer descends from your local one. Always prefer --force-with-lease over --force: it refuses to overwrite the remote if someone (or another machine of yours) pushed in the meantime, which makes the dangerous command safe by default.

One rule worth tattooing on your wrist: never rebase a branch that has an open pull request unless you know what you are doing — rebasing changes commit IDs, which can detach an open PR from its commits. Sync main with merge (or rebase it before starting new work), and keep PR branches out of it.

Why is my fork not syncing with upstream?

The four usual suspects, in the order they appear in real terminals:

  1. No upstream remotegit remote -v shows only origin. Symptom: git fetch upstream fails with 'upstream' does not appear to be a git repository. Fix: step 1 above.
  2. You fetched but never merged — fetching updates upstream/main in your local repo but touches no working branch. Symptom: git log looks old after a successful fetch. Fix: git merge upstream/main.
  3. Diverged history — you committed to your fork’s main, and upstream moved too. git pull then complains about unrelated histories or forces a merge. Fix, if you want upstream to win: git reset --hard upstream/main (throws away your local main-only commits — check git stash list or back up with a branch first; if a bad reset already happened, the recovery path is the same as in git undo last commit: git reflog still knows the old tip).
  4. Push rejected as non-fast-forward after a rebase — you rebased but pushed normally. Fix: git push --force-with-lease origin main.

A fifth, rare case: the upstream repo was renamed or deleted, so even step 1’s URL 404s. GitHub redirects renamed repos, so a hard failure usually means deleted or made private — nothing to sync to.

Can you sync a fork from the GitHub website?

Yes. On your fork’s page, the branch dropdown shows a Sync fork button whenever your branch is behind; one click pulls upstream in. Below the fold, the same thing works as a pull request: open a PR from upstream/main into your fork’s main and merge it.

The button’s limits explain when to fall back to the CLI: it only does a fast-forward or merge — it will not rebase, and it refuses outright when the branches have diverged, telling you to discard commits or use the command line. It also syncs only the default branch. For everything past a simple catch-up, the three commands above are the tool.

How often should you sync your fork?

Before every new piece of work is the honest answer: branch off a fresh main, and no PR you open starts with “this is based on a version from three weeks ago”. For forks you actively contribute to, a daily or per-session sync of main costs seconds. For a fork you only read or deploy, sync when upstream ships something you want — subscribe to the original repo’s releases feed and sync on release. Syncing is cheap precisely because it is routine; a fork six months behind often needs surgery instead of a merge, which is how “sync my fork” turns into an afternoon.

Cheat sheet

# one-time setup
git remote add upstream https://github.com/ORIGINAL_OWNER/REPO.git

# routine sync (merge policy)
git fetch upstream && git merge upstream/main && git push origin main

# routine sync (rebase policy, linear history)
git fetch upstream && git rebase upstream/main && git push --force-with-lease origin main

# how far behind am I?
git fetch upstream && git rev-list --count main..upstream/main

# diverged beyond repair — make main identical to upstream (destructive)
git fetch upstream && git reset --hard upstream/main && git push --force-with-lease origin main

Keep the routine two-liner in your muscle memory and the diverged fork stays a curiosity you read about, not a problem you fix. If your git housekeeping extends to servers, the journalctl cheat sheet covers the other half of keeping a machine’s history readable.

— mrsaynothing

ss vs netstat: Which Linux Port Command to Use