How do I push amended commit to the remote Git repository?

Viewed 522944

When I've worked a bit with my source code, I did my usual thing commit and then I pushed to a remote repository. But then I noticed I forgot to organize my imports in the source code. So I do the amend command to replace the previous commit:

> git commit --amend

Unfortunately the commit can't be pushed back to the repository. It is rejected like this:

> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

What should I do? (I can access the remote repository.)

19 Answers

I actually once pushed with --force and .git repository and got scolded by Linus BIG TIME. In general this will create a lot of problems for other people. A simple answer is "Don't do it".

I see others gave the recipe for doing so anyway, so I won't repeat them here. But here is a tip to recover from the situation after you have pushed out the amended commit with --force (or +master).

  1. Use git reflog to find the old commit that you amended (call it old, and we'll call the new commit you created by amending new).
  2. Create a merge between old and new, recording the tree of new, like git checkout new && git merge -s ours old.
  3. Merge that to your master with git merge master
  4. Update your master with the result with git push . HEAD:master
  5. Push the result out.

Then people who were unfortunate enough to have based their work on the commit you obliterated by amending and forcing a push will see the resulting merge will see that you favor new over old. Their later merges will not see the conflicts between old and new that resulted from your amending, so they do not have to suffer.

You are seeing a Git safety feature. Git refuses to update the remote branch with your branch, because your branch's head commit is not a direct descendent of the current head commit of the branch that you are pushing to.

If this were not the case, then two people pushing to the same repository at about the same time would not know that there was a new commit coming in at the same time and whoever pushed last would lose the work of the previous pusher without either of them realising this.

If you know that you are the only person pushing and you want to push an amended commit or push a commit that winds back the branch, you can 'force' Git to update the remote branch by using the -f switch.

git push -f origin master

Even this may not work as Git allows remote repositories to refuse non-fastforward pushes at the far end by using the configuration variable receive.denynonfastforwards. If this is the case the rejection reason will look like this (note the 'remote rejected' part):

 ! [remote rejected] master -> master (non-fast forward)

To get around this, you either need to change the remote repository's configuration or as a dirty hack you can delete and recreate the branch thus:

git push origin :master
git push origin master

In general the last parameter to git push uses the format <local_ref>:<remote_ref>, where local_ref is the name of the branch on the local repository and remote_ref is the name of the branch on the remote repository. This command pair uses two shorthands. :master has a null local_ref which means push a null branch to the remote side master, i.e. delete the remote branch. A branch name with no : means push the local branch with the given name to the remote branch with the same name. master in this situation is short for master:master.

Short answer: Don't push amended commits to a public repo.

Long answer: A few Git commands, like git commit --amend and git rebase, actually rewrite the history graph. This is fine as long as you haven't published your changes, but once you do, you really shouldn't be mucking around with the history, because if someone already got your changes, then when they try to pull again, it might fail. Instead of amending a commit, you should just make a new commit with the changes.

However, if you really, really want to push an amended commit, you can do so like this:

$ git push origin +master:master

The leading + sign will force the push to occur, even if it doesn't result in a "fast-forward" commit. (A fast-forward commit occurs when the changes you are pushing are a direct descendant of the changes already in the public repo.)

If the message to be changed is for the latest commit to the repository, then the following commands are to be executed:

git commit --amend -m "New message"

git push --force repository-name branch-name

Note: using --force is not recommended unless you are absolutely sure that no one else has cloned your repository after the latest commit.

A safer alternative is to use:

git push --force-with-lease repository-name branch-name

Unlike --force, which will destroy any changes someone else has pushed to the branch, --force-with-lease will abort if there was an upstream change to the repository.

You can do it in a simple and safe way by doing:

  1. Amend your last commit with git commit --amend and whatever options you need to add
  2. git pull to sync your local repo with your remote repo.
  3. After pull, you will have conflicts between local and remote. You just have to solve them by accepting current changes and commit again.
  4. git push

Now your local and remote repo are updated with no need to change your repo history.

I had to fix this problem with pulling from the remote repo and deal with the merge conflicts that arose, commit and then push. But I feel like there is a better way.

The following worked for me when changing Author and Committer of a commit.

git push -f origin master

Git was smart enough to figure out that these were commits of identical deltas which only differed in the meta information section.

Both the local and remote heads pointed to the commits in question.

Here, How I fixed an edit in a previous commit:

  1. Save your work so far.

  2. Stash your changes away for now if made: git stash Now your working copy is clean at the state of your last commit.

  3. Make the edits and fixes.

  4. Commit the changes in "amend" mode: git commit --all --amend

  5. Your editor will come up asking for a log message (by default, the old log message). Save and quit the editor when you're happy with it.

    The new changes are added on to the old commit. See for yourself with git log and git diff HEAD^

  6. Re-apply your stashed changes, if made: git stash apply

To avoid forced push, in the remote bare repository remove the last commit (the one to be amended) using:

git update-ref HEAD HEAD^

then push the amended commit with no conflict.

Note: This assumes no one has pulled the wrong commit in the meantime. If they have, they will have to similarly rewind and pull again, possibly merging their own changes.

Related