Lei Mao bio photo

Lei Mao

Machine Learning, Artificial Intelligence. On the Move.

Twitter Facebook LinkedIn GitHub   G. Scholar E-Mail RSS

Introduction

Sometimes people are confused about the difference between git push and git push -u. In this blog post, we will dig into this and try to understand the mechanism behind.

Examples

Example Base Repo

We assume we are in a repo which already has a master branch both locally and remotely.

$ git branch -a
* master
  remotes/origin/master

Git Push Experiments for Branches

If we are going to create a new branch called temp_1 and push it to the remote branch temp_1 in the remote repo, running the following commands containing git push would fail.

$ git branch temp_1
$ git checkout temp_1
$ touch temp_1.txt
$ git add .
$ git commit -m "temp_1 commit"
$ git push
fatal: The current branch temp_1 has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin temp_1

Because the current branch have not been set the upstream branch, so it does not know where the commit should go in the remote repo, and will complain to the user. We can validate this by running the following command.

$ git branch -a
  master
* temp_1
  remotes/origin/master

An upstream has to be a remote branch.


However, running the following commands containing git push would actually work.

$ git branch temp_1
$ git checkout temp_1
$ touch temp_1.txt
$ git add .
$ git commit -m "temp_1 commit"
$ git push origin temp_1

Even though the current branch does not have upstream branch, we specifically tells it to push to a branch. If the branch does not exist, it will create a branch for us in the repo.

$ git branch -a
  master
* temp_1
  remotes/origin/master
  remotes/origin/temp_1

The drawback of doing this is that, next time when you try to push some change to the remote branch, you would still need to type the branch name with git push, which might be tedious.

$ git checkout temp_1
$ git push
fatal: The current branch temp_1 has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin temp_1

If we are going to create a new branch called temp_2 based on existing branch temp_1 and push it to the remote branch temp_1 in the remote repo, running the following commands containing git push would update the remote branch temp_1 in the remote repo.

$ git branch temp_2
$ git checkout temp_2
$ touch temp_2.txt
$ git add .
$ git commit -m "temp_2 commit"
$ git push origin temp_1
Everything up-to-date

This is because nothing has been updated on the local temp_1 branch, so the remote temp_1 branch is up-to-date.


If we are going to create a new branch called temp_2 and push it to the remote branch temp_2 in the remote repo, running the following commands containing git push -u would work.

$ git branch temp_2
$ git checkout temp_2
$ touch temp_2.txt
$ git add .
$ git commit -m "temp_2 commit"
$ git push origin -u temp_2
Branch 'temp_2' set up to track remote branch 'temp_2' from 'origin'.

We checked the branches created so far.

$ git branch -a
  master
  temp_1
* temp_2
  remotes/origin/master
  remotes/origin/temp_1
  remotes/origin/temp_2

Next time when you try to push some change to the remote branch, you would just simply do git push without branch name, because the branch already knows what its upstream is.

$ git checkout temp_2
$ git push
Everything up-to-date

It should be noted that the following three commands are equivalent:

git push origin -u temp_2
git push origin --set-upstream temp_2
git push origin temp_2
git branch --set-upstream-to=origin/temp_2 temp_2

If we are going to create a new branch called temp_3 based on local branch temp_2, make some changes, and push it to the remote branch temp_2 in the remote repo, we would need to set the upstream for the local branch temp_3 to remote temp_2. However, in this scenario, Git does not allow us to do git push without specifying the remote branch specifically, for the branches whose branch names do not match between the local branch and remote branch.

$ git branch temp_3
$ git checkout temp_3
$ touch temp_3.txt
$ git add .
$ git commit -m "temp_3 commit"
$ git branch --set-upstream-to=origin/temp_2 temp_3
$ git push 
fatal: The upstream branch of your current branch does not match
the name of your current branch.  To push to the upstream branch
on the remote, use

    git push origin HEAD:temp_2

To push to the branch of the same name on the remote, use

    git push origin temp_3

To choose either option permanently, see push.default in 'git help config'.

We do git push origin HEAD:temp_2 instead, and it would work.

$ git branch temp_3
$ git checkout temp_3
$ touch temp_3.txt
$ git add .
$ git commit -m "temp_3 commit"
$ git branch --set-upstream-to=origin/temp_2 temp_3
$ git push origin HEAD:temp_2

It should be noted that the local branch temp_2 has not been modified, but the remote branch temp_2 has been modified. This means that the local branch temp_2 has fallen behind the remote branch temp_2.


We checked the branches created so far.

$ git branch -a
  master
  temp_1
  temp_2
* temp_3
  remotes/origin/master
  remotes/origin/temp_1
  remotes/origin/temp_2

Branch temp_3 only exists locally but not on the remote server.


Such operation is rare though. Usually people create branches both locally and remotely and always sync between the local and remote branches. If we want to apply some changes from one branch to another, we would do git merge.

Final Remarks

Although we are using Git everyday, it is sometimes hard to understand what is going on behind the Git commands.