By admin , 28 April 2026

Introduction

git push uploads commits to a remote and updates that remote's refs. Unlike fetch, it modifies state on the server, so safety mechanisms exist to prevent overwriting other people's work.

The sequence

  1. Resolve the remote URL and target refspec.
  2. Open a connection.
  3. Negotiate capabilities.
  4. Server advertises current values of refs.
  5. Client checks each push: is it a fast-forward of the server's ref?
  6. Client packs missing objects and uploads them.
  7. Server runs pre-receive hook.
  8. For each ref, server runs update hook and atomically updates the ref.
  9. Server runs post-receive hook.
  10. Server reports success or rejection to the client.

Commands

git push                                  # current branch to upstream
git push origin main                      # explicit
git push -u origin feature/login          # set upstream
git push origin --delete feature/login    # delete remote branch
git push origin v1.0.0                    # push a tag
git push --follow-tags
git push --force-with-lease

Fast-forward enforcement

By default, a push is rejected if it would not fast-forward the remote ref. This protects against accidentally overwriting work others have pushed:

 ! [rejected]   main -> main (non-fast-forward)
error: failed to push some refs to 'origin'
hint: Updates were rejected because the tip of your current branch is behind ...

Resolve by fetching and integrating, then pushing again.

Force pushing

git push --force                   # dangerous: ignores remote state
git push --force-with-lease        # safer: refuses if remote moved
git push --force-with-lease=feature/login:abc1234

--force-with-lease requires that the remote ref still equals what your tracking ref says. Always prefer it.

Atomic pushes

git push --atomic origin branchA branchB

With --atomic, either all updates succeed or none do; useful when refs must move together.

Push policies

git config --global push.default simple        # current branch to its upstream
git config --global push.default current       # current branch to remote of same name
git config --global push.default upstream      # current to its upstream's name
git config --global push.autoSetupRemote true  # 2.37+: auto -u for new branches

Server-side hooks

Hosting platforms run pre-receive and update hooks to enforce policies (signed commits, branch naming, mandatory CI green). When a push is rejected, the server message names the offending ref or commit. Read the message before retrying.

Common mistakes

Force-pushing to a shared branch like main and rewriting other people's commits. Coordinate, or use --force-with-lease on private branches only. Pushing tags individually and forgetting to push commits, leaving dangling tags on the server. Use --follow-tags. Pushing to a wrong remote because you have multiple configured; git push -v shows exactly where it is going. Finally, expecting git push --delete to delete files; it deletes refs. To delete files, commit a removal and push that commit.