git push中的non-fast-forward问题
[| 2012/04/16 13:50]
今天在回滚一个git操作记录时(使用了git reset --hard)遇到了问题,在push回服务器时提示:
error: failed to push some refs to 'qiuxueda@bb-iis-dev01.vm:code/comlogsvr-proxy'
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.
看了一下文档:
原文:
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 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.
我的翻译版(不是严格依照原文,按自己理解的意思复述):
关于 FAST-FORWARDS
当修改一个branch(或ref)时,在a是b的直接基线或祖先基线的情况下,将HEAD指针从a移动为b叫做fast-forwards
在这种情况下,因为不会丢失任何历史数据,所以叫做fast-forward
但是,对于non-fast-forward就会丢失历史数据,设想你和另一个人同时以x为基线开发,你开发了一个叫b的commit,而那个人开发了一个叫a的commit:
B
/
---X---A
如果那个人已经将a提交到了服务端,现在服务端的head指向了a,如果你试图去提交b,那么服务端会试图将head从a移动到b上,如此一来,就会丢失a的修改内容,这就是non-fast-forward。
所以默认情况下不允许这种提交,以防止数据丢失
如果你不想丢失你的和别人的工作成果,那么需要先从服务端获取其他人的修改,生成一个包含你的和其他人修改的commit,然后将其提交到服务器。
你可以先运行git pull,然后解决合并冲突,然后git push。git pull会基于a和b生成一个c记录,同时包含两者的修改内容
B---C
/ /
---X---A
这样提交c请求就变成了fast-forward请求,从而被允许。
同样的,你可以在a基础上添加从x到b的这些请求,使用git pull --rebase并push结果到服务器,这样会生成一个commit:d,在a的基础上添加了从x到b的修改
B D
/ /
---X---A
这也是一个fast-forward请求,是被允许的。
(这一段不是特别理解。。像是废话,因为跟上图第一种情况看起来是一回事)还有一种情况,即使没有其他人向版本库推送过数据,你也可能遇到non-fast-forward的情况:
当你推送a到服务端后,又使用了git commit --amend 修改a为b,然后可能忘记已经推送过a,于是试图去推送b到版本库。这样的话,当你确认没有人fetch过a的话,可以使用git push --force去覆盖这个记录。
也就是说,当你确认你确实需要丢失历史数据时,可以使用git push --force来强制推送
在gitolite中,对于每个版本库的授权就有“RW+”字段,其中的“+”权限,就是强制推送的权限,由于可能会导致历史提交丢失,所以是比W更高级的权限,需要单独授予。
error: failed to push some refs to 'qiuxueda@bb-iis-dev01.vm:code/comlogsvr-proxy'
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.
看了一下文档:
原文:
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 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.
我的翻译版(不是严格依照原文,按自己理解的意思复述):
关于 FAST-FORWARDS
当修改一个branch(或ref)时,在a是b的直接基线或祖先基线的情况下,将HEAD指针从a移动为b叫做fast-forwards
在这种情况下,因为不会丢失任何历史数据,所以叫做fast-forward
但是,对于non-fast-forward就会丢失历史数据,设想你和另一个人同时以x为基线开发,你开发了一个叫b的commit,而那个人开发了一个叫a的commit:
B
/
---X---A
如果那个人已经将a提交到了服务端,现在服务端的head指向了a,如果你试图去提交b,那么服务端会试图将head从a移动到b上,如此一来,就会丢失a的修改内容,这就是non-fast-forward。
所以默认情况下不允许这种提交,以防止数据丢失
如果你不想丢失你的和别人的工作成果,那么需要先从服务端获取其他人的修改,生成一个包含你的和其他人修改的commit,然后将其提交到服务器。
你可以先运行git pull,然后解决合并冲突,然后git push。git pull会基于a和b生成一个c记录,同时包含两者的修改内容
B---C
/ /
---X---A
这样提交c请求就变成了fast-forward请求,从而被允许。
同样的,你可以在a基础上添加从x到b的这些请求,使用git pull --rebase并push结果到服务器,这样会生成一个commit:d,在a的基础上添加了从x到b的修改
B D
/ /
---X---A
这也是一个fast-forward请求,是被允许的。
(这一段不是特别理解。。像是废话,因为跟上图第一种情况看起来是一回事)还有一种情况,即使没有其他人向版本库推送过数据,你也可能遇到non-fast-forward的情况:
当你推送a到服务端后,又使用了git commit --amend 修改a为b,然后可能忘记已经推送过a,于是试图去推送b到版本库。这样的话,当你确认没有人fetch过a的话,可以使用git push --force去覆盖这个记录。
也就是说,当你确认你确实需要丢失历史数据时,可以使用git push --force来强制推送
在gitolite中,对于每个版本库的授权就有“RW+”字段,其中的“+”权限,就是强制推送的权限,由于可能会导致历史提交丢失,所以是比W更高级的权限,需要单独授予。