200

I want git push origin to automatically set the upstream reference when I push a locally-created branch for the first time.

I know about git push -u, but I don't want to have to think about whether or not I've used -u before or otherwise set an upstream reference. In other words, I want git push to automatically have the effect of git push -u on any push of a branch that doesn't already have an upstream.

Is this possible? If it requires an alias or utility script, that's fine.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
John
  • 29,546
  • 11
  • 78
  • 79
  • 3
    Have you checked if it's possible to use the `push.default` and `branch..merge` options in [git-config(1)](https://www.kernel.org/pub/software/scm/git/docs/git-config.html)? –  Jul 25 '13 at 01:08
  • 7
    I have `push.default` set to `current` -- that's how I can just say `git push origin` without a refspec or upstream. But it doesn't help with automatically setting the upstream. – John Jul 25 '13 at 01:20

13 Answers13

204

You can configure it with git config --global push.default current (docs) to make it push the current branch to update a branch with the same name.

2022 Update (git>=2.37.0)

git config --global --add --bool push.autoSetupRemote true achieves the same while ALSO setting up the upstream tracking (docs).

Andrea Bergonzo
  • 3,983
  • 4
  • 19
  • 31
  • 15
    I have that set -- that's how I can just say `git push origin` without a refspec or upstream. But it doesn't help with automatically setting the upstream. – John Nov 28 '18 at 18:04
  • 5
    Yeah, as @John says, it's important to keep in mind that this does **not** make the local branch track the remote one; it just creates the remote branch with the same name as the local one. – waldyrious Mar 15 '19 at 12:20
  • Good enough if you just need to `push`, e.g. only one developer is on his branch, who only edits one copy of a repo. – superarts.org May 01 '19 at 19:47
  • 1
    Note, as I documented in [my answer](https://stackoverflow.com/a/72401899/6309), this is for Git 2.37 or more. So... `git>=2.37.0` ;) – VonC Jul 13 '22 at 18:38
  • `push.autoSetupRemote` is available on some versions earlier than 2.37, but (from what I see on version 2.33.0) it only works when `push.default` is set to current (or maybe matching?). It only performs additional useful steps, once the name of the remote branch has been established by `push.default`. Try it with `push.default` set to upstream or simple and it will give an error message: "The current branch has no upstream branch." – jpaugh Dec 29 '22 at 16:16
  • Wish you could upvote more than one time when you come back to the same answer at a later time to solve same issue on a different build :D – Jimmy Long Aug 12 '23 at 21:46
68

2022: Git 2.37 proposes:

git config --global push.autoSetupRemote true

push.autoSetupRemote

If set to "true" assume --set-upstream on default push when no upstream tracking exists for the current branch;

This option takes effect with push.default options 'simple', 'upstream', and 'current'.

It is useful if by default you want new branches to be pushed to the default remote (like the behavior of 'push.default=current') and you also want the upstream tracking to be set.
Workflows most likely to benefit from this option are 'simple' central workflows where all branches are expected to have the same name on the remote.


2013: Note: the fact that the new default push policy "simple" relies on a branch having an upstream one means that:
setting an upstream branch is viewed as a voluntary step, not an hidden automated one

When "git push [$there]" does not say what to push, we have used the traditional "matching" semantics so far (all your branches were sent to the remote as long as there already are branches of the same name over there).

We will use the "simple" semantics that pushes the current branch to the branch with the same name, only when the current branch is set to integrate with that remote branch.
There is a user preference configuration variable "push.default" to change this.


So building up from mechanicalfish's answer, you can define an alias, with the right double quotes (") escaped (\"):

git config alias.pu "![[ $(git config \"branch.$(git rev-parse --abbrev-ref HEAD).merge\") = '' ]] && git push -u || git push"

git pu origin

Sc0ttyD proposes in the comments the following alias:

alias gpu='[[ -z $(git config "branch.$(git symbolic-ref --short HEAD).merge") ]] && git push -u origin $(git symbolic-ref --short HEAD) || git push'

In multiple lines:

alias gpu='[[ -z $(git config "branch.$(git symbolic-ref --short HEAD).merge") ]] && 
           git push -u origin $(git symbolic-ref --short HEAD) || 
           git push'
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 2
    Thanks for showing how to set up the alias. I'm not clear on the connection to or relevance of the first part of your answer though. – John Sep 26 '13 at 16:20
  • 2
    @John my point is: you would circumvent a step which is supposed to be an intentional one. You can setup that alias, but I wanted to make clear to other readers why this explicit `-u` option exists, and why there isn't a config for making said option automatic (hence the alias). – VonC Sep 26 '13 at 16:46
  • 2
    I have a list of zsh aliases in my .zshrc. I modified this answer to create the following zsh alias: `alias gpu='[[ -z $(git config "branch.$(git symbolic-ref --short HEAD).merge") ]] && git push -u origin $(git symbolic-ref --short HEAD) || git push'` – Sc0ttyD Nov 07 '17 at 11:36
  • 2
    @Sc0ttyD Interesting, thank you. I have included your comment in the answer for more visibility. – VonC Nov 07 '17 at 11:42
35

Since I don't think this is possible using git config, here is what you can do in bash:

[[ $(git config "branch.$(git rev-parse --abbrev-ref HEAD).merge") = '' ]] && git push -u || git push

If the current branch has a remote tracking branch, it calls git push otherwise it calls git push -u

mechanicalfish
  • 12,696
  • 3
  • 46
  • 41
  • 37
    You can now do `git config --global push.default current`. – Andrea Bergonzo Feb 12 '18 at 23:03
  • 3
    @AndreaBergonzo this is the only good answer to me, may you add it as an answer? – pdem Nov 15 '18 at 15:18
  • 15
    @AndreaBergonzo, @pdem -- note that `push.default=current` only creates a branch in the remote repository with the same name as the local branch, but does **not** set the local branch to track the remote one. I'm not sure why this is the case, but it's worth keeping in mind. – waldyrious Mar 15 '19 at 12:17
  • Exactly, with this alias one will also see the commits the branch is ahead/behind the upstream one. – Alex Weissnicht Jul 17 '21 at 20:08
24

I've had the same problem. I've made this alias (from my .gitconfig)

[alias]
    track = "!git branch --set-upstream-to=origin/`git symbolic-ref --short HEAD`"

Usage:

  1. Once per new branch (currently checked out): git track
  2. Push as normal :)
Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
Frexuz
  • 4,732
  • 2
  • 37
  • 54
19

The answers by @VonC and @Frexuz are helpful, but both of their solutions produce an error for me. Using both of their answers, I cobbled together something that works for me:

    [alias]
    pu = ![[ $(git config "branch.$(git symbolic-ref --short HEAD).merge") = '' ]] && git push -u origin $(git symbolic-ref --short HEAD) || git push

This results in executing either git push -u origin $BRANCHNAME or git push, depending on whether its upstream (property branch.$BRANCHNAME.merge) is defined.

Entering this alias on the command line will require escape codes, so it's probably easiest to use an editor to insert into the correct file ($HOME/.gitconfig (global), .git/config (local), or /etc/gitconfig (system) )

Mark
  • 1,035
  • 2
  • 11
  • 24
  • 4
    This is the most straightforward and complete answer. To open up the default editor without hunting for the file, you can `git config --global -e` – Adam Tolley Feb 03 '17 at 17:11
8

Short answer

If you actually like to be explicit and use the -u option when necessary, but just don't want to type the whole:

git push -u origin foo

Then you can use the following alias:

[alias]
    push-u = !git push -u origin $(git symbolic-ref --short HEAD)

And simply type:

git push-u

Long answer

Typically, the need for -u (shorthand for --set-upstream) is when we have just created a new local branch and commit, and we want to push it upstream. The remote repository doesn't yet have the new branch, so we need to tell git to create and track the remote branch before pushing the commit. This is only necessary for the first push on the branch. Here is a typical scenario:

git checkout -b foo         # Create local branch
git commit -m "Foo"         # Create local commit
git push -u origin foo      # Create and track remote branch, and push commit
git commit -m "Bar"         # Create local commit
git push                    # Push commit

Personally, I do like the need to be explicit with git push -u when creating the remote branch: it's a pretty significant operation, sharing a whole new branch to the world.

However, I hate that we have to explicitly write git push -u origin foo. Not only it is a pain to type, but more importantly, it's quite error-prone! It's easy to make a mistake when typing the branch name, and the new remote branch won't have the same name as your local branch! In most cases, really, you want the upstream repository to be origin, and the upstream branch to have the same name as your local branch.

Therefore, I'm using the following alias in my .gitconfig, which is a subset of the excellent answer provided by Mark:

[alias]
    push-u = !git push -u origin $(git symbolic-ref --short HEAD)

Now, we can do the following, which is still explicit, but less error-prone:

git checkout -b foo         # Create local branch
git commit -m "Foo"         # Create local commit
git push-u                  # Create and track remote branch, and push commit
git commit -m "Bar"         # Create local commit
git push                    # Push commit
Boris Dalstein
  • 7,015
  • 4
  • 30
  • 59
7

I solved this issue by using this simple Bash script. It won't work on existing branches, but if you create all of your branches with this function, you'll always have your upstream branch set automatically.

function con { git checkout -b $1 && git push --set-upstream origin $1; }

The $1 represents the first argument you pass after con so it's just like doing:

git checkout -b my-new-branch && git push -u my-new-branch

...by just doing this:

con my-new-branch
JT Jobe
  • 113
  • 1
  • 7
5

If you wanna use the built-in git features only with the less possible keypress, just type:

$ git push -u o tab H tab

and the autocomplete will give you $ git push -u origin HEAD

To enable autocomplate on OSX set up a ~/.git-completition.bash file with this content and add the following lines to your ~/.bash_profile file and restart your terminal:

# git branch autocomplete
if [ -f ~/.git-completion.bash ]; then
  . ~/.git-completion.bash
fi
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

It affects built-in terminals too, like the one in vscode etc.

gazdagergo
  • 6,187
  • 1
  • 31
  • 45
  • 1
    autocomplete? git doesn't have autocomplete. Your shell (bash? zsh?) has a set of autocomplete rules loaded. Can you provide information regarding which set of autocomplete rules you are using, and where to get them? – vy32 Jul 24 '20 at 17:50
  • Oh, in deed thanks. I've completed my answer with my autocomplete settings. – gazdagergo Jul 25 '20 at 19:37
  • Without knowing the contents of your file ~/.git-completion.bash, your answer is not operationalizable. – vy32 Jul 25 '20 at 23:59
  • 1
    Good point. I found the source of my `git-completition.bash` and added to my answer. – gazdagergo Jul 26 '20 at 12:58
5

The only completely honest answer to this is "you can't".

I've read all the responses in this, and other questions that ask the same thing.

Every answer posted still requires you to pass special parameters on your first push to a new branch.

korona
  • 2,308
  • 1
  • 22
  • 37
  • You actually can. See https://stackoverflow.com/a/53322776/11262633. – mherzog Dec 03 '21 at 20:28
  • 1
    @mherzog push.default current does not actually set the upstream, it just pushes to a branch of the same name. So for example that means you won't get the "Your branch is up to date / behind / ahead" message when running `git status`. – Tim Goodman Mar 02 '22 at 22:16
  • That said, it will let you set the upstream with just `git push -u` instead of `git push -u origin branch_name`. But you still have to remember the `-u` on the first push if you want to set the upstream. – Tim Goodman Mar 02 '22 at 22:59
3

Simply:

$ alias gush="git push -u origin HEAD"
djanowski
  • 5,610
  • 1
  • 27
  • 17
3

Today I came across (a new?) option "push.autoSetupRemote". git config help says:

If set to "true" assume --set-upstream on default push when no upstream tracking exists for the current branch; this option takes effect with push.default options simple,
       upstream, and current. It is useful if by default you want new branches to be pushed to the default remote (like the behavior of push.default=current) and you also want
       the upstream tracking to be set. Workflows most likely to benefit from this option are simple central workflows where all branches are expected to have the same name on
       the remote.
  • Yes, see [Why do I need to do `--set-upstream` all the time?](https://stackoverflow.com/a/72401899/6309). – VonC Jun 29 '22 at 13:02
  • Finally! This looks like exactly the configuration option I was looking for. Marked as the accepted answer. – John Jul 07 '22 at 21:56
1

I made a git extension with useful scripts, including this one:

usage: git line push

Push the current branch and set an upstream if needed.

https://github.com/jvenezia/git-line

jvenezia
  • 890
  • 7
  • 10
1

If, for whatever reason, none of the other answers work for you, then you can substitute git push with this bash function to automatically re-send the push request with the correct flags when necessary.

gitpush()
{
    git push -v 2>&1 | # perform push command, pipe all output
    tee /dev/tty | # keep output on screen and pipe it forward
    (
     cmd=$(sed -n "s/^.*\(git push --set-upstream origin .*\)$/\1/p");
     [[ -n "${cmd// }" ]] && (echo "> $cmd"; eval $cmd);
    ) # if we get output that matches the command to perform, execute it
}

You will be sacrificing the progress portion of the push output, but other than that everything works as expected.

Personally, I will be using JT Jobe's answer.

Raphael
  • 441
  • 1
  • 6
  • 12