孤魂野鬼
原始版本如下:
o - A <-- name1
/
o - o - o - o - B <-- name2
\ /
o - C <-- name3
现在把name1移动到B:
o - A
/
o - o - o - o - B <-- name1, name2
\ /
o - C <-- name3
当没有名字指向A的时候,A以及A前面那个提交就成为了孤魂,也就有可能被gc掉。我们可以通过reflog来恢复他,但git只会为我们保存30天。
现在,把name3也移动到B:
o - A
/
o - o - o - o - B <-- name1, name2, name3
\ /
o - C
但是C这个时候并不是孤魂野鬼,它可以通过name3^1来访问。因故他是合法的。所以branch才会在合并之后才能被合法删掉。
把name1移动到B就不是一次fast-forward,把name3移动到B就是。
可以理解为顺着已有的(合并)线移动。
概念:当且仅当一个name移动后,还能碰到之前指向的点的时候,成为一次fast-forward操作。
fast-forward合并是非常流畅的。假使你进行一次fast-forward push,那么git做的事情就是把你本地的repo复制到中心repo,然后顺着fast-forward的路把master指向你的master,不会出现任何孤魂。
merge的时候使用fast-forward与否的区别
若加上--no-ff
选项,则会不使用fast-forward进行合并。这个时候feature分支上的更改会做作为一个新的提交,回到master上。
而如果使用--ff
选项,若master上没有别人的新提交,那么原本指向master最新的head会直接移动到feature的最新上。
为什么公共分支上使用rebase之后不给push?
如上文所说,push到中心repo之后,中心只接受fast-forward得来的结果。再引用之前的一个例子
[站外图片上传中...(image-209ec8-1516171303565)]
中心repo发现从旧的feature移动到新的feature,那么旧的D将会成为一个孤魂,所以被服务器拒绝了。
当A使用--force来强行推送之后,其实B的D开头的feature还是合法的,最后会被git变得尽量fast-forward,也就是会把中心repo上的feature所代表的分支上面的所有内容D'作为一个陌生的新提交和E进行合并。