Home > Software engineering >  What does git push -u origin BRANCH do when you are not on BRANCH?
What does git push -u origin BRANCH do when you are not on BRANCH?

Time:04-08

When I first started using git, I was told by another team member to always push using

git push -u origin MYBRANCH

because it would prevent me accidentally pushing code to the wrong branch. I didn't fully understand and today tried to understand what happens that means.

I created a local repo and provide my exact commands so you could copy/paste this to reproduce what I've done.

In this test I have a local (on disk) repo and two branches:

git branch
  main
* feature/fixthis

I'm on the feature/fixthis branch and run:

git push -u origin main
  # NOTE: the current branch is feature/fixthis

Did I just accidentally push my feature branch onto main?

My Solution (figure it out myself using local test)

To test this out myself, I did the following. The commands are written in such a way that you can copy/past to a UNIX bash shell to reproduce a local git repo and create the exact scenario I'm asking about.

# Step 1:  Create local repo
mkdir so-test; cd so-test; git init --bare local-git-repo.git

# Step 2: git clone local (empty repo).
git clone ./local-git-repo.git test-this

# Step 3: Add a Readme.md file, commit and push the change 
cd test-this; echo hi > README.md; git add README.md; git commit -m "initial commit"; git push -u origin main

# Step 4: Check the branch feature/fixit.
git co -b feature/fixit

# Step 5: Make change and accidentally push it to main.  
echo In feature/fixit >> README.md; git add -u .; git commit -m "change on feature/fixit"; 

# Step 6: Do the push from the feature/fixit branch to main
git push -u origin main

Did the command git push -u origin main accidentally update the main branch?

When I look at the logs I can't figure out what happened to the last push, it doesn't appear to have updated the origin/main branch because I don't see the origin/feature/fixit tag (on any commit).

git log
commit 1bba12ad200080cb0a59aa0e2fb518a1e284b135 (HEAD -> feature/fixit)
Author: [email protected]
Date:   Thu Apr 7 14:25:19 2022  0000

    change on feature/fixit

commit dcf8098bda7c937c80bc60ee974ac6eb9a895ced (origin/main, main)
Author: [email protected]
Date:   Thu Apr 7 14:20:06 2022  0000

    initial commit

Searching for answers

Many others

CodePudding user response:

The command just pushes into the remote origin your local branch MYBRANCH (the remote branch has the same name). This is used when you are working on a branch A and you want to push branch B into the remote.

You could even push into branches with a different name, if so you wished:

git push origin a-local-branch-name:a-remote-branch-name

CodePudding user response:

The -u option merely tells git push to run git branch --set-upstream-to after the push finishes, provided that the push itself finishes successfully.

That doesn't quite get you all the way there because git branch --set-upstream-to needs two parameters: the name of the branch whose upstream is to be set, and the name of the upstream to set. But it does make it clear that, regardless of whether the current branch is br1, br2, or main, git push -u origin main starts out doing the same thing as git push origin main:

  • translate origin to a URL;
  • call up whatever Git software responds at that URL;
  • send them any commits you have, but they lack, that lead up to and include the tip commit you have on your main; and
  • ask them to set their main to point to the same commit that your main points to.

In other words, your br1 and br2 names play no role whatsoever in this operation.

Let's assume now you are on your br1 branch, and that this git push step finishes successfully. Their (origin's) main now names the same commit that your main names, and your origin/main now names that commit as well. Now the run git branch --set-upstream-to action from the -u option kicks in. This will set the upstream of one of your branch names to one of your origin/ names. Which (local) branch name makes sense here? What origin/ name makes sense here?1 The possibilities include:

git branch --set-upstream-to=origin/br2 br2

even though you're on br1 and just pushed br2. That makes no sense at all though. Another possibility is:

git branch --set-upstream-to=origin/main br1

But that's not very sensible as you didn't push your br1 (even though you're on branch br1, as git status would say). You pushed your main. So the actual command is:

git branch --set-upstream-to=origin/main main

and that is what the -u does: after successfully sending your branch's tip commit and other commits if and as needed, and using that to set their branch of the same name and then your corresponding origin/ remote-tracking name, the -u action sets the upstream of that (named) branch to that remote-tracking name.

The most complex case is the one eftshift0 hints at. We could run, e.g.:

git switch main
git push -u origin br2:new-name

This delivers to origin the commits that lead up to the tip commit of br2, whatever commits those may be that they don't already have, then asks them—the origin Git repository—to set their name new-name to point to the tip-most commit that we sent (or didn't bother sending if they already had it). But then what git branch --set-upstream-to happens? Well, let's try it out:

$ git push -u origin fix-signal:new-br
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To [redacted]
 * [new branch]      fix-signal -> new-br
Branch 'fix-signal' set up to track remote branch 'new-br' from 'origin'.

and indeed git branch -vv now includes:

  fix-signal e068bdf [origin/new-br] make signal handler work in py2k and py3k

(note that I'm on master in this repository). If I now delete origin/newbr:

$ git push origin :new-br
...
 - [deleted]         new-br
$ git branch -vv --list fix-signal
  fix-signal e068bdf [origin/new-br: gone] make signal handler work in py2k and py3k

I should now run git branch --unset-upstream fix-signal since I have no origin/new-br any more. (It's not exactly harmful to have a broken upstream like this, it's just useless. The branch had no upstream earlier, so I did actually do that.)


1Using the "what makes sense here" rule is slightly dangerous since not everything Git does always makes sense, but it's mostly a decent guide.

  •  Tags:  
  • git
  • Related