在使用git的时候, 我用git commit --amend 命令修改了上一个提交的一些内容, 而上一个提交的内容已经被我用push推到远程服务器了, 现在我用git push -u origin master 推送 amend之后的提交, 推送失败了, 并给出了错误提示如下:
To https://github.com/xuzhezhaozhao/Practice.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/xuzhezhaozhao/Practice.git'
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.
上网搜了一下, 在stackoverflow上找到了解决办法, 是用 -f 参数 来push: git push -f origin master. stackoverflow真是一个好网站, 就像一个程序员百科全书一样, 基本上所有的问题都能在上面找到, 你还能贴出你遇到的问题, 让里面的大神帮忙解决, 解决问题的速度都很快, 起码我看到的都是半个小时以内就有人回复了, 强烈推荐.
参考: http://stackoverflow.com/questions/3598355/i-am-not-able-to-push-on-git
https://www.kernel.org/pub/software/scm/git/docs/git-push.html#_note_about_fast_forwards
原回答如下:
Dealing with “non-fast-forward” errors
From time to time you may encounter this error while pushing:
$ git push origin master
To ../remote/
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to '../remote/'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again. See the 'non-fast forward'
section of 'git push --help' for details.
This error can be a bit overwhelming at first, do not fear.
Simply put, git cannot make the change on the remote without losing commits, so it refuses the push. Usually this is caused by another user pushing to the same branch.
You can remedy this by fetching and merging the remote branch, or using pull to perform both at once.In other cases this error is a result of destructive changes made locally by using commands like
git commit --amend
orgit rebase
.
While you can override the remote by adding--force
to the push command, you should only do so if you are absolutely certain this is what you want to do. Force-pushes can cause issues for other users that have fetched the remote branch, and is considered bad practice. When in doubt, don’t force-push.
Mode details on the "Note about fast-forwards" of git push
, as mentioned by Michael Mrozek in the comments.
Note about fast-forwards 的内容, 前面的情况是多人工作下出现这个问题解决方法, 最后面就是单人工作下出现问题的解决方法.
Note about fast-forwards
When an update changes a branch (or more in general, a ref) that used to point at commit A to point at another commit B, it is called a fast-forward update if and only if B is a descendant of A.
In a fast-forward update from A to B, the set of commits that the original commit A built on top of is a subset of the commits the new commit B builds on top of. Hence, it does not lose any history.
In contrast, a non-fast-forward update will lose history. For example, suppose you and somebody else started at the same commit X, and you built a history leading to commit B while the other person built a history leading to commit A. The history looks like this:
B / ---X---A
Further suppose that the other person already pushed changes leading to A back to the original repository from which you two obtained the original commit X.
The push done by the other person updated the branch that used to point at commit X to point at commit A. It is a fast-forward.
But if you try to push, you will attempt to update the branch (that now points at A) with commit B. This does not fast-forward. If you did so, the changes introduced by commit A will be lost, because everybody will now start building on top of B.
The command by default does not allow an update that is not a fast-forward to prevent such loss of history.
If you do not want to lose your work (history from X to B) nor the work by the other person (history from X to A), you would need to first fetch the history from the repository, create a history that contains changes done by both parties, and push the result back.
You can perform "git pull", resolve potential conflicts, and "git push" the result. A "git pull" will create a merge commit C between commits A and B.
B---C / / ---X---A
Updating A with the resulting merge commit will fast-forward and your push will be accepted.
Alternatively, you can rebase your change between X and B on top of A, with "git pull --rebase", and push the result back. The rebase will create a new commit D that builds the change between X and B on top of A.
B D / / ---X---A
Again, updating A with this commit will fast-forward and your push will be accepted.
There is another common situation where you may encounter non-fast-forward rejection when you try to push, and it is possible even when you are pushing into a repository nobody else pushes into. After you push commit A yourself (in the first picture in this section), replace it with "git commit --amend" to produce commit B, and you try to push it out, because forgot that you have pushed A out already. In such a case, and only if you are certain that nobody in the meantime fetched your earlier commit A (and started building on top of it), you can run "git push --force" to overwrite it. In other words, "git push --force" is a method reserved for a case where you do mean to lose history.