'Updates were rejected error when pushing to new remote branch

I have forked a github repository and by now my fork is several commits ahead. I now want to provide one of these commits as a PR to the original repository.

Following this question's answer, I did:

git remote add official [URL to original repo]
git checkout -b hotfix-for-feature official/master
git cherry-pick [feature-hash]
git push -u origin hotfix-for-feature

and I get:

! [rejected]        hotfix-for-feature -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/myusername/repositoryname'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Note how:

  1. The branch argument to git push -u is just completely ignored and it wants to push to origin/master
  2. Neither origin/hotfix-for-feature nor official/hotfix-for-feature exist remotely.
  3. official/master is not ahead in any way - I literally just fetched it

If I try git branch hotfix-for-feature --set-upstream=origin/hotfix-for-feature I'm told that git push -u is the proper way to do this. If I try git push -u origin/hotfix-for-feature I get:

fatal: You are pushing to remote 'origin/hotfix-for-feature',
which is not the upstream of your current branch 'hotfix-for-feature',
without telling me what to push to update which remote branch.

which - apart from being a good example of how not to write your error messages - I don't understand. I specify what to push (current branch) and which remote branch to update.

I find lots of questions about this error, but it is always about some remote branch being ahead and in this case there is no existing remote branch. Also what is the difference between a "pushed branch" and a "remote [branch]"?



Solution 1:[1]

TL;DR: Don't create your branch from official/master

When you create the branch in the first place, first checkout official/master and then do git checkout -b hotfix-for-feature without specifying what it should be created from.

You can also do git checkout -b hotfix-for-feature master, but explicitly saying git checkout -b hotfix-for-feature official/master sets the upstream in a way you don't want.

Details

This question surprised me at first, because I routinely do a workflow almost identical to yours, and yet by default git push -u origin newbranchname creates branch newbranchname on origin.

So, I tried to see what is different between your workflow and mine, and I just figured it out.

When you ran:

git checkout -b hotfix-for-feature official/master

you specifically asked Git to create branch hotfix-for-feature to track official/master, which means you've already done the -u upfront, and set it wrong.

In my workflow, I do this instead:

git checkout official/master
git checkout -b hotfix-for-feature

which creates a new branch without an upstream.

Then, when I push this branch, using the same syntax as you, the upstream is now set to what you want, on your own fork in your scenario:

git push -u origin hotfix-for-feature

creates hotfix-for-feature on origin and sets origin/hotfix-for-feature for my local hotfix-for-feature branch.

Alternatively, you create the new branch from a local branch, and that won't set the upstream either:

git checkout -b hotfix-for-feature master

It's just having official/master on that last argument that you have to avoid.

Solution 2:[2]

I personally disagree with the other answers. (I feel it's confusing to track remote branches with a different name, and I dislike checking out local copies of shared branches.) The only tweak I would make in your workflow is at branch creation. I would change this line:

git checkout -b hotfix-for-feature official/master

to not track the remote branch, like this:

git checkout -b hotfix-for-feature official/master --no-track

Note, this is what some UI tools do for you when you create a new local branch from a remote branch. For example, in Visual Studio, there is a checkbox for "Track remote branch" which is checked by default, until you change the name of your branch to something else in which case it automatically unchecks that box for you (and adds --no-track behind the scenes).

Tip: if you ever forget to use --no-track, you can always do it after the fact with:

git branch --unset-upstream

That will fix your current problem as well, after which you can do your initial push with git push -u to set your upstream properly.

Side Note: I might also tweak that same line in question to use the newer checkout syntax:

git switch -c hotfix-for-feature official/master --no-track

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2