90

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?

Community
  • 1
  • 1
rynmrtn
  • 3,371
  • 5
  • 28
  • 44
  • Duplicate of [What's a "fast-forward" in Git?](http://stackoverflow.com/questions/4684352/whats-a-fast-forward-in-git) –  May 18 '14 at 16:57

4 Answers4

176

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.

Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
  • great education, and you got the command right in the end, but my branch was called develop (based on git-flow), and the other guy put `+develop` in his command - so the check goes to him. You've got an astronomical number of points anyway :P – rynmrtn Apr 14 '11 at 19:00
  • 8
    Or use the less cryptic `git push --force` – Bennett McElwee Nov 21 '11 at 22:23
  • 3
    @Panique You're trying to allow several people to work on a large, complex codebase at the same time, without blocking each other (allowing only one person to work on it at a time), and without changes overwriting each other. You need each person to be able to make changes independently, and merge those changes. Merging (whether manual or automatic) can introduce unexpected problems; so you want to retain as much information as possible in order to be able to figure out what happened if it went wrong. This is intrinsically complex; it's not dirty, just a hard problem. – Brian Campbell Jul 10 '12 at 20:29
  • I tried both -f and + option to rewrite remote repo history. In both options, I ran into non-fast-forward issue. [ 5:05PM]$ git push -f origin local_A:remote_A Counting objects: 35, done. Delta compression using up to 2 threads. Compressing objects: 100% (18/18), done. Writing objects: 100% (21/21), 7.41 KiB, done. Total 21 (delta 9), reused 0 (delta 0) remote: To prevent you from losing history, non-fast-forward updates were rejected. Merge the remote changes (e.g. 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details. – Srikanth Jan 25 '13 at 01:08
  • 4
    @Srikanth It's possible to entirely disable forced pushes 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 :remote_A; git push origin local_A:remote_A`. But read what I wrote above about why it's a bad idea to do this kind of workflow on a shared repository. You should try to only do this if you have something that causes serious problems in the commit you are trying to get rid of or rewrite. – Brian Campbell Jan 25 '13 at 16:45
  • @BrianCampbell Thanks. In my case the force push worked gr8, and also i think in my case i will not make harm to any other working on the repo. My case is the following : we have Pull request(PR) system enabled for our git repo, so anyone who wants to make changes in repo - have to commit changes in one branch and push the changes and submit its PR using that branch. So in my case, i commit changes in branch, and later on do a git pull --rebase, and again make some changes depending on first commit i made in branch (note that the PR is not excepted yet). then do a force push in this branch. – jospratik Aug 01 '13 at 08:51
52

Force git push:

git push origin +develop
Alan Haggai Alavi
  • 72,802
  • 19
  • 102
  • 127
  • 24
    That's a solution, but read Brian Campbell's comment so you understand what you're doing before you use this. – thelem Mar 15 '12 at 15:28
  • 5
    git push origin +master – Aniket Thakur Nov 12 '13 at 12:02
  • See also the note about `receive.denyNonFastForwards` in [Brian Campbell's answer](https://stackoverflow.com/a/5667883/1256452): `+` or `--force` may not be sufficiently forceful, depending on how they—whoever they are—have configured *their* Git repository. – torek Apr 10 '20 at 00:12
14

You might have to do a git pull, which MAY auto merge stuff for you. Then you can commit again. If you have conflicts, it'll prompt you to resolve them.

Keep in mind, you have to specify which branch to pull from if you haven't updated your gitconfig to specify...

For example:

git pull origin develop:develop
Tony
  • 933
  • 7
  • 15
  • Still mad about non-fast-forward. Any thoughts on how to force it to merge? `! [rejected] develop -> develop (non-fast-forward)` – rynmrtn Apr 14 '11 at 18:19
  • I think the switch is -f but I could be wrong. http://www.kernel.org/pub/software/scm/git/docs/git-pull.html – Tony Apr 14 '11 at 18:23
  • This partially works. I'm not seeing the updates on github, though (it shows the previous commit as the latest even with a `git push origin develop`) – rynmrtn Apr 14 '11 at 18:28
7

I was using EGit and I faced this issue also. Just tried to rebase the current branch and It worked.

Nguyen Minh Binh
  • 23,891
  • 30
  • 115
  • 165