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

482,691

Solution 1

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.

Solution 2

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.)

Solution 3

Here is a very simple and clean way to push your changes after you have already made a commit --amend:

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master

Which does the following:

  • Reset branch head to parent commit.
  • Stash this last commit.
  • Force push to remote. The remote now doesn't have the last commit.
  • Pop your stash.
  • Commit cleanly.
  • Push to remote.

Remember to change origin and master if applying this to a different branch or remote.

Solution 4

I have solved it by discarding my local amended commit and adding the new changes on top:

# Rewind to commit before conflicting
git reset --soft HEAD~1

# Pull the remote version
git pull

# Add the new commit on top
git add ...
git commit
git push

Solution 5

I had the same problem.

  • Accidentally amended the last commit that was already pushed
  • Done a lot of changes locally, committed some five times
  • Tried to push, got an error, panicked, merged remote, got a lot of not-my-files, pushed, failed, etc.

As a Git-newbie, I thought it was complete FUBAR.

Solution: Somewhat like @bara suggested + created a local backup branch

# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>

# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad

# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"

# Switch back to the original branch
git checkout feature/1234

# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234

# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php

Maybe it's not a fast and clean solution, and I lost my history (1 commit instead of 5), but it saved a day's work.

Share:
482,691
Troj
Author by

Troj

I'm a jack of most trades residing in Sweden and usually involved with full-stack web development technologies. I work for tretton37 as a contractor, my list of clients includes among others Sony and IKEA. I dabble in open source software and have many projects in my Github repository and my Bitbucket repository, among many: RefluxJS - Library for uni-directional data flows, inspired by Facebook's Flux In the little free time that I have, all kinds of stuff happen such as drawing pretty pictures, perform ball juggling, play a guitar, hack on games, and solve a Rubik's cube.

Updated on July 08, 2022

Comments

  • Troj
    Troj almost 2 years

    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.)

  • mipadi
    mipadi over 15 years
    Not really. The issue might be that you haven't updated your local copy from the remote repo. Git won't push to it because you may have to deal with merges manually. In my other reply, I have a command (and explanation) that will force a push -- but beware that is may delete changes in the remote.
  • vedang
    vedang over 13 years
    this did not work with github, it gave me the following message: [remote rejected] master (deletion of current branch prohibited)
  • vedang
    vedang over 13 years
    I didn't want to force push (which i knew would solve the issue), but now I guess I have no choice.
  • bentford
    bentford about 12 years
    How is this different ( better or worse) than git push -f ? Thanks!
  • mipadi
    mipadi about 12 years
    @bentford: It's basically the same thing as git push -f.
  • Mr_and_Mrs_D
    Mr_and_Mrs_D about 12 years
    deleting the remote master branch will free the space in the remote repo ?
  • CB Bailey
    CB Bailey about 12 years
    @Mr_and_Mrs_D: Not immediately, but after a git gc once the reflogs have expired old objects will be pruned. Nobody who clones the repository will get any objects that are no longer reachable as soon as the branch has been updated.
  • mknaf
    mknaf about 10 years
    This is the simplest version!
  • Thomas
    Thomas over 9 years
    If you've successfully pulled back the commit in your last example, why do you need to force push? Wouldn't a standard push suffice? Thanks
  • Jesse Hogan
    Jesse Hogan over 7 years
    This worked for me, and shows as 1 (properly amended) commit in git-log and in Bitbucket. However, my Jira ticket shows two commits. The first one has a different SHA than what I see in Bitbucket and has the unamended commit. The second one has the same SHA with the amended commit. So I guess the unamended commit never goes away it is just hidden by git and other clients. How can I see the unamended commits with git-log?
  • Rolf
    Rolf over 7 years
    I hear that's bad, and I'm sure it is. There is a (good) reason for git to fail by default (and require --force), I am sure.
  • SylvainB
    SylvainB about 7 years
    2 remarks : - make sure to change the name of the branch if your are working on another one - I had to use git add before my commit to include the changes.
  • Bartis Áron
    Bartis Áron over 6 years
    I'd downvote, if I'd have more reputation points, so I'll just ask here politely, that which one was you of the sufferers? The one who amended? The one, who pulled and worked on a branch with amended commit? Before the amend, or after it? I just cleared every modification of mine because I misunderstood you... Fortunately there was not much...
  • MrMister
    MrMister over 6 years
    In Windows CMD, the first command should be escaped: git reset --soft "HEAD^". The rest works fine.
  • Admin
    Admin almost 6 years
    Adding another 'change' commit is better than messing with rewriting history. I agree with @mknaf
  • Admin
    Admin almost 5 years
    Question asked by Thomas is in fact very valid. Myself didn't need to force the push following pull.
  • Admin
    Admin almost 5 years
    "a very simple and clean way.." cit. This procedure includes forced push. In lights of all the critisims in Answers above I am not sure if this procedure is in fact a clean one.
  • Admin
    Admin almost 5 years
    Why not this answer be accounting for major comments raised in previous answers?
  • Farid
    Farid over 4 years
    Please don't call it "the best practice" because there is a way to work around --force, see the accepted answer
  • Vincenzooo
    Vincenzooo almost 4 years
    This is the simple solution (in some cases). I understand other people's concerns about different users accessing the repository, however not all projects have a large number of contributors: I am the only active contributor to my projects, so there is no risk of conflicts, this works perfectly for me.
  • ThinkDigital
    ThinkDigital almost 4 years
    @mipadi, then I would say it's better to go with the more explicit git push -f for simplicity
  • Markus
    Markus about 3 years
    Best answer! It avoids messing around with origin master.