Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git non-fast-forward rejected

I feel like this question has been asked many times, but the solution is typically "I deleted the directory and re-did my work with a fresh checkout." I did a commit and push but realized that I referred to the wrong ticket number in the commit message. So I looked on SO for a quick solution and ended up typing the following into the terminal:

$ git reset --soft HEAD^ $ git commit -m "... correct message ..." 

The only problem is I am getting the following error message:

To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes before pushing again.  See the 'Note about fast-forwards' section of 'git push --help' for details. 

I am using the git-flow model and am working on the develop branch. How can I merge things back in to make git happy again?

like image 915
rynmrtn Avatar asked Apr 14 '11 17:04

rynmrtn


People also ask

How do you fix a non-Fast-Forward rejection?

If you do a commit in one project and then accidentally push this commit, with bypassing code review, to another project, this will fail with the error message 'non-fast forward'. To fix the problem you should check the push specification and verify that you are pushing the commit to the correct project.

Why is my git push rejected?

A commit gets rejected and causes a failed to push some refs to error because the remote branch contains code that you do not have locally. What this means is that your local git repository is not compatible with the remote origin. Based on the above, your local machine is missing commits C and D.

What is git fast forward?

Fast-forward merges literally move your main branch's tip forward to the end of your feature branch. This keeps all commits created in your feature branch sequential while integrating it neatly back into your main branch.


2 Answers

If you push a commit to the server, and then rewrite that commit locally (with git reset, git rebase, git filter-branch, or any other history manipulation), and then pushed that rewritten commit back up to the server, you will screw up anyone else who had pulled. Here's an example; say you have committed A, and pushed it to the server.

 -*-*-A <-- master  -*-*-A <-- origin/master 

Now you decide to rewrite A, in the way you mentioned, resetting and re-committing. Note that this leaves a dangling commit, A, which will eventually be garbage collected as it is not reachable.

 -*-*-A     \      A' <-- master  -*-*-A  <-- origin/master 

If someone else, let's say Fred, pulls down master from the server while you're doing this, they will have a reference to A, which they might start working from:

 -*-*-A' <-- master  -*-*-A  <-- origin/master  -*-*-A-B <-- fred/master 

Now if you were able to push your A' to origin/master, which would create a non-fast-forward, it wouldn't have A in its history. So if Fred tried to pull again, he'd suddenly have to merge, and would re-introduce the A commit:

 -*-*-A' <-- master  -*-*-A  <-- origin/master  -*-*-A-B-\      \     * <-- fred/master      A'--/ 

If Fred happens to notice this, then he could do a rebase, which would prevent commit A from reappearing again. But he'd have to notice this, and remember to do this; and if you have more than one person who pulled A down, they would all have to rebase in order to avoid getting the extra A commit in the tree.

So, it's generally not a good idea to change history on a repo that other people pull from. If, however, you happen to know that no one else is pulling from that repo (for instance, it's your own private repo, or you only have one other developer working on the project who you can coordinate with easily), then you can forcibly update by running:

git push -f 

or

git push origin +master 

These will both ignore the check for a non-fast-forward push, and update what's on the server to your new A' revision, abandoning the A revision so it will eventually be garbage collected.

It's possible that force pushes are entirely disabled with the receive.denyNonFastForwards config option. This option is enabled by default on shared repositories. In that case, if you really, really want to force a push, the best option is to delete the branch and re-create it, with git push origin :master; git push origin master:master. However, the denyNonFastForwards option is enabled for a reason, which is described above; on a shared repository, it means that now everyone who uses it needs to ensure that they rebase onto the new history.

On a shared repository, it is generally better to just push new commits on top that fix whatever problem you have; you can use git revert to generate commits that will undo the changes of previous commits.

like image 190
Brian Campbell Avatar answered Oct 02 '22 18:10

Brian Campbell


Force git push:

git push origin +develop 
like image 32
Alan Haggai Alavi Avatar answered Oct 02 '22 17:10

Alan Haggai Alavi