C.W.K.
Stream
Lesson 03 of 05 · published

Push, Upstream, and Push Rejection

~18 min · push, upstream

Level 0Untracked Rookie
0 XP0/47 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

push uploads, push rejection protects history

git push origin feature/x uploads commits on your local branch feature/x to the remote's feature/x. The first push of a new branch needs -u to set tracking: git push -u origin feature/x. After that, plain git push from feature/x defaults to the right place. Tracking turns the branch into a single line of effort that flows in both directions.

Push rejection is Git refusing to overwrite history that exists on the server but not in your local copy. The error is clear: "Updates were rejected because the remote contains work that you do not have locally." Your job is not to bypass the rejection — it is to integrate the remote work first. git fetch, then either rebase your branch onto the new tip (git rebase origin/feature/x) or merge it (git merge origin/feature/x), then push again.

Force push is the escape hatch you should never reach for casually. git push --force overwrites the remote's branch with your local history, even if you would lose commits. The catastrophic version: someone else pushed work you did not have, and force-push wipes their commits from the server. The safer alternative — and the only one any senior engineer should use — is git push --force-with-lease, which refuses to push if the remote tip moved since your last fetch. Same effect when nothing surprising happened, refused operation when it did.

Two patterns are worth muscle memory. Set up tracking on first push: git push -u origin <branch>. Force-push rebased history with the safety net: git push --force-with-lease. Configure git config --global push.default current so git push with no arguments always pushes the current branch to its tracked remote, removing one more category of accidental wrong-branch pushes.

Code

First push and routine push·bash
# First push of a new branch — sets up tracking:
git push -u origin feature/profile-page

# After tracking is set, just:
git push

# See what would be pushed without actually pushing:
git push --dry-run

# Push to a different remote (e.g. fork-and-upstream setup):
git push fork feature/profile-page

# Delete a remote branch:
git push origin --delete feature/profile-page
Force-push safely after rebase·bash
# After local rebase that rewrote published commits:
git push --force-with-lease

# What --force-with-lease checks:
#   It refuses to push if origin/<branch> has moved since
#   your last fetch — meaning someone pushed concurrently.

# DANGEROUS — only when you know nobody else used this branch:
git push --force          # wipes remote history blindly

# Configure once for safer push defaults:
git config --global push.default current
git config --global push.followTags true

External links

Exercise

Create a fresh branch, make a couple of commits, push with git push -u. Now git rebase against main (or amend the most recent commit) so the local history diverges from the remote. Push first with plain git push and read the rejection. Then push with git push --force-with-lease and confirm success. Note in writing the exact wording the rejection used and what would have happened if you had used plain --force instead.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.