Git reset –hard and a remote repository
I had a repository that had some bad commits on on it (D, E and F for this example).
A-B-C-D-E-F master and origin/master
git - does it work on image? Eclipse + Maven + Git + Multi-Module projects = Unhappiness Unexpected merge error in a git svn system? How to clone from github from behind corporate proxy No refs in common and none specified; doing nothing How does npm version work?
I’ve modified the local repository specifically with a git reset hard. I took a branch before the reset so now I have a repo that looks like:
A-B-C master \ D-E-F old_master A-B-C-D-E-F origin/master
Now I needed some parts of those bad commits so I cheery picked the bits I needed and made some new commits so now I have the following locally:
A-B-C-G-H master \ D-E-F old_master
Now I want to push this state of affairs to the remote repo. However, when I try to do a git push git politely gives me the brush off:
$ git push origin +master:master --force Total 0 (delta 0), reused 0 (delta 0) error: denying non-fast forward refs/heads/master (you should pull first) To firstname.lastname@example.org:myrepo.git ! [remote rejected] master -> master (non-fast forward) error: failed to push some refs to 'email@example.com:myrepo.git'
How do I get the remote repo to take the current state of the local repo?
4 Solutions collect form web for “Git reset –hard and a remote repository”
If forcing a push doesn’t help (“
git push --force origin” or “
git push --force origin master” should be enough), it might mean that the remote server is refusing non fast-forward pushes either via receive.denyNonFastForwards config variable (see git config manpage for description), or via update / pre-receive hook.
With older Git you can work around that restriction by deleting “
git push origin :master” (see the ‘:’ before branch name) and then re-creating “
git push origin master” given branch.
If you can’t change this, then the only solution would be instead of rewriting history to create a commit reverting changes in D-E-F:
A-B-C-D-E-F-[(D-E-F)^-1] master A-B-C-D-E-F origin/master
To complement Jakub’s answer, if you have access to the remote git server in ssh, you can go into the git remote directory and set:
user@remote$ git config receive.denyNonFastforwards false
Then go back to your local repo, try again to do your commit with
user@local$ git push origin +master:master --force
And finally revert the server’s setting in the original protected state:
user@remote$ git config receive.denyNonFastforwards true
Instead of fixing your “master” branch, it’s way easier to swap it with your “desired-master” by renaming the branches. See https://stackoverflow.com/a/2862606/2321594. This way you wouldn’t even leave any trace of multiple revert logs.
The whole git resetting business looked far to complicating for me.
So I did something along the lines to get my src folder in the state i had a few commits ago
# reset the local state git reset <somecommit> --hard # copy the relevant part e.g. src (exclude is only needed if you specify .) tar cvfz /tmp/current.tgz --exclude .git src # get the current state of git git pull # remove what you don't like anymore rm -rf src # restore from the tar file tar xvfz /tmp/current.tgz # commit everything back to git git commit -a # now you can properly push git push
This way the state of affairs in the src is kept in a tar file and git is forced to accept this state without too much fiddling basically the src directory is replaced with the state it had several commits ago.