Table of Contents

Introduction

You've made a new branch, committed to it, typed git push, and Git answered with fatal: The current branch hotfix has no upstream branch. That's the moment most of us learn about -u. It does two things at once: publishes the branch to the remote, and records which remote branch yours goes with, so every later push and pull on it needs no arguments.

In this article, we'll:

  1. Watch git push -u origin hotfix publish a one-commit branch
  2. See what "set upstream" writes and what changes in git status
  3. Cover the setting that makes -u automatic, and how to undo it

What is git push -u?

git push -u <remote> <branch> (long form --set-upstream) pushes <branch> to <remote>, creating the branch there if it doesn't exist, and then sets the local branch's upstream: the remote-tracking branch it's compared against and pulls from by default. The upstream is stored as two config values, branch.<name>.remote and branch.<name>.merge.

Watch it happen

Our sample repo has a new local branch with one commit that origin has never seen. Here's git push -u origin hotfix:

  1. Before: HEAD is attached to hotfix, which points at 4a58e97 "Fix header color", one commit on top of 8c02d5b "Update dependencies", where origin/main points. There is no origin/hotfix, because the remote has no hotfix branch.
  2. Git creates a hotfix branch on the remote at 4a58e97, and a remote-tracking branch origin/hotfix at the same commit. Because of -u, hotfix now tracks origin/hotfix.
  3. hotfix and HEAD don't move, and no commits are created. Git sent only 4a58e97, the one commit the remote lacked. It already had everything from 8c02d5b back.

Before and after

The graph gains one label and nothing else. The bigger difference is in git status. Before, the first line was just ## hotfix: a branch with nothing to compare against. After, it's ## hotfix...origin/hotfix, so from now on status can tell you when you're ahead or behind. Git's own output says what happened, in two parts:

branch 'hotfix' set up to track 'origin/hotfix'.
To ../your_project.git
 * [new branch]      hotfix -> hotfix
The raw git output, if you want to read along in text

git log --oneline --graph --all

before

* 4a58e97 (HEAD -> hotfix) Fix header color
* 8c02d5b (origin/main, origin/HEAD, main) Update dependencies
* a0b2db3 Add user settings page
| * 1117a34 (origin/feature, feature) Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

after

* 4a58e97 (HEAD -> hotfix, origin/hotfix) Fix header color
* 8c02d5b (origin/main, origin/HEAD, main) Update dependencies
* a0b2db3 Add user settings page
| * 1117a34 (origin/feature, feature) Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
|/  
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commit

what git printed

branch 'hotfix' set up to track 'origin/hotfix'.
To ../your_project.git
 * [new branch]      hotfix -> hotfix

What "set upstream" writes

The tracking part is two lines in .git/config:

[branch "hotfix"]
    remote = origin
    merge = refs/heads/hotfix

remote says which remote to talk to and merge says which branch on it. With those set, plain git push on hotfix knows to push to origin's hotfix, git pull knows what to fetch and merge, and git status and git branch -vv can count commits ahead and behind. You only need -u once per branch. Pushing with -u again just rewrites the same two lines.

To set or change the upstream without pushing, use git branch -u origin/hotfix (long form --set-upstream-to). To remove it, git branch --unset-upstream.

For years my first push of every new branch went the same way: plain git push, the "no upstream branch" error, then copying the command Git suggested. Setting push.autoSetupRemote once in my global config got rid of that little ritual, and I haven't typed -u much since.

Making it automatic

Since Git 2.37 there's a setting for exactly this:

git config --global push.autoSetupRemote true

With it, a plain git push on a branch that has no upstream behaves like git push -u origin <branch>, creating the remote branch and setting up tracking in one go. (It pushes to your default remote, normally origin.) Without it, the error message itself mentions the setting, alongside the git push --set-upstream origin hotfix command to copy.

Is it safe?

Safe git-sim pre-flight

No upstream tracking ref found; cannot compare with remote.

The pre-flight report can't compare with the remote because hotfix has no upstream yet, which is the very thing this command sets. Pushing a brand new branch can't overwrite anything on the remote, since there was nothing there by that name. If the remote does already have a hotfix with different commits, the push is rejected like any other non-fast-forward push.

Useful forms

  • git push -u origin HEAD pushes the current branch under the same name, so you don't have to type it.
  • git push -u origin hotfix:fix/header publishes local hotfix as fix/header on the remote and tracks that.
  • git push -u upstream hotfix publishes to a different remote, such as one added with git remote add.
  • git branch -vv lists each local branch with its upstream and how far ahead or behind it is.

How to undo it

To take the branch off the remote:

git push origin --delete hotfix

That deletes the remote hotfix and your origin/hotfix label. Your local hotfix and its commit stay. The branch.hotfix tracking lines are left in config, pointing at a branch that's gone, so git status says the upstream is gone. git branch --unset-upstream clears them. If someone may already have fetched the branch, deleting it won't remove it from their copy.

Try it on your repository

pip install git-sim
git-sim push -u origin hotfix

git-sim draws which commits would be sent and where the new remote-tracking label would land, without contacting the remote.

Common questions

What does git push -u do?

It pushes the branch to the remote and sets it as the local branch's upstream, by writing branch.<name>.remote and branch.<name>.merge to .git/config. After that, plain git push and git pull work on the branch.

What is the difference between git push -u and git push --set-upstream?

None. -u is the short form of --set-upstream, and the git push documentation lists it with the rest of push's options.

Do I need -u every time I push?

No, only the first time for each branch. Once the upstream is set, git push is enough. With push.autoSetupRemote set to true, you never need it.

How do I see a branch's upstream?

git branch -vv shows it in brackets next to each branch, and git status names it on the second line, as in "Your branch is up to date with 'origin/hotfix'".

Summary

In this article, we watched git push -u origin hotfix send 4a58e97 "Fix header color" to the remote and put origin/hotfix on it, saw the two config lines that make it the branch's upstream, and covered push.autoSetupRemote and how to take a published branch back down.

Next steps

git push covers what happens on later pushes, including rejections. git remote add covers publishing to a remote other than origin.

  • git push, for every push after the first
  • git remote add, to push to another remote
  • git clone, which sets up the upstream of the default branch for you
  • git config, where the upstream is stored
  • git fetch, to update origin/hotfix from the remote
  • git pull, which uses the upstream to know what to merge