lighttpd中handle_start_backend钩子(hook)函数的理解
[
|
2012/04/25 19:59]


之前按字面意思理解handle_start_backend是说连接后端服务端口(webserver,fastcgi等等),今天发现并非如此。
这个hook是在CON_STATE_HANDLE_REQUEST_HEADER状态时,
如果con->mode仍旧是DIRECT类型且con->physical.path为空,会先调用:
plugins_call_handle_uri_raw
plugins_call_handle_uri_clean
plugins_call_handle_docroot
plugins_call_handle_physical
如果con->mode还是DIRECT,那么会判断con->physical.path指定的文件是否存在,
若存在,如果是软链但是con->conf.follow_symlink为0,那么403,如果是目录但请求url不是路径名,则301跳转到目录路径(在末尾加/)
若无权限访问,返回403
若找不到文件,返回404
若ENOTDIR(对文件做了目录操作),则考虑path_info
若EMFILE(进程句柄不足),则返回HANDLER_WAIT_FOR_FD
若不是以上情况,打印错误日志,返回500
如果con->physical.path存在且无错误发生,或为ENOTDIR,那么又判断了一次是否存在(这里代码设计比较恶心)
如果是普通文件且没有软链问题,那么break出去执行plugins_call_handle_start_backend。
反之则一直向上遍历,直到遍历到一个真实存在的文件,如果找不到,那么404,如果找到了,将pathinfo串放入con->request.pathinfo。然后截短con->uri.path。
然后才会去调用plugins_call_handle_start_backend。
所以对于很多动态请求是不会调用plugins_call_handle_start_backend的。
这个钩子被mod_access调用用来实现deny_all功能。
被mod_indexfile调用用来实现默认文件功能(请求/时映射到index.php等)
这个hook是在CON_STATE_HANDLE_REQUEST_HEADER状态时,
如果con->mode仍旧是DIRECT类型且con->physical.path为空,会先调用:
plugins_call_handle_uri_raw
plugins_call_handle_uri_clean
plugins_call_handle_docroot
plugins_call_handle_physical
如果con->mode还是DIRECT,那么会判断con->physical.path指定的文件是否存在,
若存在,如果是软链但是con->conf.follow_symlink为0,那么403,如果是目录但请求url不是路径名,则301跳转到目录路径(在末尾加/)
若无权限访问,返回403
若找不到文件,返回404
若ENOTDIR(对文件做了目录操作),则考虑path_info
若EMFILE(进程句柄不足),则返回HANDLER_WAIT_FOR_FD
若不是以上情况,打印错误日志,返回500
如果con->physical.path存在且无错误发生,或为ENOTDIR,那么又判断了一次是否存在(这里代码设计比较恶心)
如果是普通文件且没有软链问题,那么break出去执行plugins_call_handle_start_backend。
反之则一直向上遍历,直到遍历到一个真实存在的文件,如果找不到,那么404,如果找到了,将pathinfo串放入con->request.pathinfo。然后截短con->uri.path。
然后才会去调用plugins_call_handle_start_backend。
所以对于很多动态请求是不会调用plugins_call_handle_start_backend的。
这个钩子被mod_access调用用来实现deny_all功能。
被mod_indexfile调用用来实现默认文件功能(请求/时映射到index.php等)
lighttpd中钩子(hook)函数的使用
[
|
2012/04/24 22:57]


lighttpd内部使用了状态机处理每个请求,在状态机中插入了若干个钩子来供扩展使用,在执行到钩子函数那里时,会按扩展载入顺序,依次回调使用了该钩子的各扩展指定的函数,这样会有一些编程中隐藏的易错点。
1,顺序在后面的钩子不能假定前面的钩子函数一定会被执行到。
之前遇到过这样的问题,在一个扩展中使用了两个钩子函数,第一个里面申请了一些资源,第二个里面使用并释放,结果实际中发现对于某些请求,第一个钩子可能没有被执行就到了第二个钩子那里,于是出core。
查了一下原因,原来排在该扩展前面的mod_access扩展在第一个钩子被调用时返回了HANDLER_FINISH,这样,对于后续调用该钩子的其他扩展不会被回调。于是该扩展的第一个钩子函数未被调用到。
2,同一个钩子可能会被调用多次。
一些情况下,连接状态会rollback,这样的话同一个hook会被回调多次,还有一些情况会导致调用多次,比如给多个钩子指定了同一个处理函数。
有时我们需要为每个扩展在每个连接生命周期内维护一个变量,这时可以用到con->plugin_ctx[p->id],这是一个void *指针,把数据指针存入该变量,并在连接释放时释放掉即可。
1,顺序在后面的钩子不能假定前面的钩子函数一定会被执行到。
之前遇到过这样的问题,在一个扩展中使用了两个钩子函数,第一个里面申请了一些资源,第二个里面使用并释放,结果实际中发现对于某些请求,第一个钩子可能没有被执行就到了第二个钩子那里,于是出core。
查了一下原因,原来排在该扩展前面的mod_access扩展在第一个钩子被调用时返回了HANDLER_FINISH,这样,对于后续调用该钩子的其他扩展不会被回调。于是该扩展的第一个钩子函数未被调用到。
2,同一个钩子可能会被调用多次。
一些情况下,连接状态会rollback,这样的话同一个hook会被回调多次,还有一些情况会导致调用多次,比如给多个钩子指定了同一个处理函数。
有时我们需要为每个扩展在每个连接生命周期内维护一个变量,这时可以用到con->plugin_ctx[p->id],这是一个void *指针,把数据指针存入该变量,并在连接释放时释放掉即可。
phpLiteAdmin-很强大的sqlite管理面板
[
|
2012/04/23 22:14]


很久之前用过sqlite,当时是做邮件转发器的时候,遇到的一个问题是没有好的面板,装过一个,页面特效还不错,不过很难用,功能也少,桌面版的也搞过,不过也是很简陋的类型。纯命令行操作实在不行,于是很久没用。
最近搞了新的监控程序,有较大量的监控数据要存储,由于查询很少(也就自己看看),数据重要性不高,放在mysql里不必要(mysql是定期备份的,放mysql里会占用大量备份空间),所以决定放到sqlite里。按月分库,这样查询方便,节省资源。
遇到的问题又是面板,本来打算自己写一个,不过还是先搜搜,放狗搜关键字搜了几个,发现都是停止开发若干时间的不靠谱产品,不过上sqlite官网上的链接里看,排第一位的是phpLiteAdmin,一看这个就眼前一亮,看名字像是跟phpmyadmin有关系,点进位于google code的项目主页上看了看,原来是界面上仿phpmyadmin的,看了截图相当靠谱,看更新时间是1月4号,开发比较活跃,下载了源码看了看,原来整个程序写在了一个php文件中,大概5千行左右,用起来相当方便。装上用了下,功能很不错,界面美观,连帮助文档都有。最新版本是1.9.1,官网说明上说准备写2.0版,改成多文件模式,不过现在的版本也够用了。
最近搞了新的监控程序,有较大量的监控数据要存储,由于查询很少(也就自己看看),数据重要性不高,放在mysql里不必要(mysql是定期备份的,放mysql里会占用大量备份空间),所以决定放到sqlite里。按月分库,这样查询方便,节省资源。
遇到的问题又是面板,本来打算自己写一个,不过还是先搜搜,放狗搜关键字搜了几个,发现都是停止开发若干时间的不靠谱产品,不过上sqlite官网上的链接里看,排第一位的是phpLiteAdmin,一看这个就眼前一亮,看名字像是跟phpmyadmin有关系,点进位于google code的项目主页上看了看,原来是界面上仿phpmyadmin的,看了截图相当靠谱,看更新时间是1月4号,开发比较活跃,下载了源码看了看,原来整个程序写在了一个php文件中,大概5千行左右,用起来相当方便。装上用了下,功能很不错,界面美观,连帮助文档都有。最新版本是1.9.1,官网说明上说准备写2.0版,改成多文件模式,不过现在的版本也够用了。
vps的系统时间不准确问题
[
|
2012/04/21 17:50]


最最早买burst NET的vps时,就是因为其时间老是不准确,最后不使用了,后来用的一些vps都没什么时间问题,openvz的一般时间都比较准,xen的可以自己用ntpdate校准,也不存在问题。
今天发现最近搞的一个vps时间又不准了,前几天发现时间差了半分钟,找客服校准后今天看又差了4秒,平均每天要差1秒多点,相当不爽。发ticket希望客服能加个crontab任务定期校准一下服务器时间。
在印象中电脑主板时钟已经做的不错了,怎么还会有每天差1秒这种问题。。。会不会主机商用的服务器有问题。比较囧。由于那个vps未来想观察一段时间稳定后作为主力机的。所以要求还是比较高。
今天发现最近搞的一个vps时间又不准了,前几天发现时间差了半分钟,找客服校准后今天看又差了4秒,平均每天要差1秒多点,相当不爽。发ticket希望客服能加个crontab任务定期校准一下服务器时间。
在印象中电脑主板时钟已经做的不错了,怎么还会有每天差1秒这种问题。。。会不会主机商用的服务器有问题。比较囧。由于那个vps未来想观察一段时间稳定后作为主力机的。所以要求还是比较高。
webmin/usermin/virtualmin使用
[
|
2012/04/19 23:37]


今天看见有人讨论webmin,这是一个服务器管理面板,用的人比较多。由于我一直都是命令行操作,没有用过面板,有些好奇,于是安装试了一下。
先在一个小内存的vps上试了试,发现内存不足。webmin还是比较重量的。于是找了个内存比较大的装了一下。webmin安装比较快,下载deb包后用dpkg -i安装,解决一些编译依赖后就可以在默认端口10000上使用了。默认是使用root用户密码登陆。
进去以后有点眼花缭乱,左边功能菜单长长的一列,每个点开后都有若干个功能。大概使用了一下,功能非常强大,界面也很不错。基本上覆盖了系统的各项配置,连php、mysql的参数都可以用可视化的方式进行调整,不得不说非常强大。
大概浏览了一下功能列表,cron任务设置、用户管理、自启动程序管理、进程管理、磁盘配额以及各种系统服务的管理,如数据库、ssh、svn、samba、email等等等等等。基本上平时用到的大多数服务都可以以可视化的形式进行配置,并且配置功能很强,页面交互也很友好。
由于是在OpenVZ vps上安装的面板,共享内核的原因,有些功能不能使用,不过已经足够让人眼花了。
在查看可用扩展时,又发现了usermin和virtualmin,在官网上看了下说明,原来分别是普通用户用来管理的面板和虚拟主机管理的面板。
usermin可以直接在webmin里安装,点击安装后自动就装好启动了,默认20000端口,进去后也是一些管理功能,主要是文件、mail等管理,可管理项少了很多,不过也很不错。
然后是virtualmin,这个在官网提供了自动安装脚本,运行了一下,相当复杂,装了半天才装好,装好后还是从10000端口进入,一进去感觉界面很华丽,比webmin好很多。除了有webmin的功能外,主要添加了虚拟主机的操作,主要有增删虚拟主机、设置配额、查看流量、ftp管理等管理项。功能超强。进入usermin后界面也有很大改观,主要增加了一个mail管理界面,可以收发邮件,还有一个邮件列表。
总体使用的感觉非常强大,这应该算是一个比较重量级的管理面板。不过其实平时用的时候根本用不到这么多的功能。也很少有服务器会部署上这么多的服务。个人使用有点太费资源,中小企业用来管理少数几台运行了很多网络基础服务的服务器还是相当不错的。
先在一个小内存的vps上试了试,发现内存不足。webmin还是比较重量的。于是找了个内存比较大的装了一下。webmin安装比较快,下载deb包后用dpkg -i安装,解决一些编译依赖后就可以在默认端口10000上使用了。默认是使用root用户密码登陆。
进去以后有点眼花缭乱,左边功能菜单长长的一列,每个点开后都有若干个功能。大概使用了一下,功能非常强大,界面也很不错。基本上覆盖了系统的各项配置,连php、mysql的参数都可以用可视化的方式进行调整,不得不说非常强大。
大概浏览了一下功能列表,cron任务设置、用户管理、自启动程序管理、进程管理、磁盘配额以及各种系统服务的管理,如数据库、ssh、svn、samba、email等等等等等。基本上平时用到的大多数服务都可以以可视化的形式进行配置,并且配置功能很强,页面交互也很友好。
由于是在OpenVZ vps上安装的面板,共享内核的原因,有些功能不能使用,不过已经足够让人眼花了。
在查看可用扩展时,又发现了usermin和virtualmin,在官网上看了下说明,原来分别是普通用户用来管理的面板和虚拟主机管理的面板。
usermin可以直接在webmin里安装,点击安装后自动就装好启动了,默认20000端口,进去后也是一些管理功能,主要是文件、mail等管理,可管理项少了很多,不过也很不错。
然后是virtualmin,这个在官网提供了自动安装脚本,运行了一下,相当复杂,装了半天才装好,装好后还是从10000端口进入,一进去感觉界面很华丽,比webmin好很多。除了有webmin的功能外,主要添加了虚拟主机的操作,主要有增删虚拟主机、设置配额、查看流量、ftp管理等管理项。功能超强。进入usermin后界面也有很大改观,主要增加了一个mail管理界面,可以收发邮件,还有一个邮件列表。
总体使用的感觉非常强大,这应该算是一个比较重量级的管理面板。不过其实平时用的时候根本用不到这么多的功能。也很少有服务器会部署上这么多的服务。个人使用有点太费资源,中小企业用来管理少数几台运行了很多网络基础服务的服务器还是相当不错的。
一个不错的linux screen配置文件
[
|
2012/04/19 00:04]


一个好用的.screenrc配置,f11和f12分别是左右切换tab。很好用,也很简洁。
#termcapinfo rxvt* 'hs:ts=\E]2;:fs=\007:ds=\E]2;\007'
#hardstatus string "screen (%n: %t)"
source /etc/screenrc
altscreen off
hardstatus none
# hardstatus string '%{= kg}[ %H ][%{= kw}%= %?%-Lw%?%{R}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{W} %c %{g}]'
# hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %d/%m %{W}%c %{g}]'
# hardstatus string "%{= bk} %{= wk} %-Lw%{bw}%n+%f %t%{wk}%{wk}%+Lw %=%{kw}%{= R}%{-}"
# hardstatus string "%{= kw} %H %{wk} [%= %-Lw%{r}%n+%f %t%{k}%+Lw %= ] %{kw} %c %{kw}%{= R}%{-}"
# hardstatus string "%{= rw} %H %{wk} %-Lw%{r}%n+%f %t%{wk}%+Lw %= %c%{kw}%{= R}%{-}"
# caption always "%{= rw} %H %{wk} %h %= %-Lw%{r}%n+%f %t%{wk}%+Lw %{kw}%{= R}%{-}"
# caption always "%{= rw} %H %{kw}- %-Lw%{r}%n+%f %t%{kw}%+Lw%=%{= rw}%c %{= R}%{-}"
# caption always "%{= rw} %H %{wk} %-Lw%{r}%n+%f %t%{wk}%+Lw %= %c%{kw}%{= R}%{-}"
# caption always "%{= KW} %l %{KW}%-Lw%{kW} %n+%f %t %{KW}%+Lw %=%c%{KW}%{= R}%{-}"
# caption always "%{= kw} %-Lw%{G}%n+%f %t%{kw}%+Lw %= %c%{kw}%{= R}%{-}"
# caption always "%{= KW} %h %=%{kw}%{= R}%{-}"
# caption always "%{= wk} %{wk}%-Lw%{rw} %n+%f %t %{wk}%+Lw %=%c%{kw}%{= R}%{-}"
caption always "%{= wk}%{wk}%-Lw%{rw} %n+%f %t %{wk}%+Lw %=%c%{= R}%{-}"
# caption always "%{= KW} %{KW}%-Lw%{wk} %n+%f %t %{KW}%+Lw %=%{KW}%c%{KW}%{= R}%{-}"
# caption always "%{= KW} %{KW}%-Lw%{Wk} %n+%f %t %{KW}%+Lw %=%{KW}%c%{KW}%{= R}%{-}"
shelltitle "$ |bash"
defscrollback 50000
startup_message off
# escape ^aA
escape ^aa
termcapinfo xterm|xterms|xs|rxvt ti@:te@ # scroll bar support
term rxvt # mouse support
width 130
height 40
bindkey -k k; screen
bindkey -k F1 prev
bindkey -k F2 next
bindkey -d -k kb stuff ^H
bind x remove
bind j eval "focus down"
bind k eval "focus up"
bind s eval "split" "focus down" "prev"
vbell off
shell -bash
#termcapinfo rxvt* 'hs:ts=\E]2;:fs=\007:ds=\E]2;\007'
#hardstatus string "screen (%n: %t)"
source /etc/screenrc
altscreen off
hardstatus none
# hardstatus string '%{= kg}[ %H ][%{= kw}%= %?%-Lw%?%{R}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{W} %c %{g}]'
# hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %d/%m %{W}%c %{g}]'
# hardstatus string "%{= bk} %{= wk} %-Lw%{bw}%n+%f %t%{wk}%{wk}%+Lw %=%{kw}%{= R}%{-}"
# hardstatus string "%{= kw} %H %{wk} [%= %-Lw%{r}%n+%f %t%{k}%+Lw %= ] %{kw} %c %{kw}%{= R}%{-}"
# hardstatus string "%{= rw} %H %{wk} %-Lw%{r}%n+%f %t%{wk}%+Lw %= %c%{kw}%{= R}%{-}"
# caption always "%{= rw} %H %{wk} %h %= %-Lw%{r}%n+%f %t%{wk}%+Lw %{kw}%{= R}%{-}"
# caption always "%{= rw} %H %{kw}- %-Lw%{r}%n+%f %t%{kw}%+Lw%=%{= rw}%c %{= R}%{-}"
# caption always "%{= rw} %H %{wk} %-Lw%{r}%n+%f %t%{wk}%+Lw %= %c%{kw}%{= R}%{-}"
# caption always "%{= KW} %l %{KW}%-Lw%{kW} %n+%f %t %{KW}%+Lw %=%c%{KW}%{= R}%{-}"
# caption always "%{= kw} %-Lw%{G}%n+%f %t%{kw}%+Lw %= %c%{kw}%{= R}%{-}"
# caption always "%{= KW} %h %=%{kw}%{= R}%{-}"
# caption always "%{= wk} %{wk}%-Lw%{rw} %n+%f %t %{wk}%+Lw %=%c%{kw}%{= R}%{-}"
caption always "%{= wk}%{wk}%-Lw%{rw} %n+%f %t %{wk}%+Lw %=%c%{= R}%{-}"
# caption always "%{= KW} %{KW}%-Lw%{wk} %n+%f %t %{KW}%+Lw %=%{KW}%c%{KW}%{= R}%{-}"
# caption always "%{= KW} %{KW}%-Lw%{Wk} %n+%f %t %{KW}%+Lw %=%{KW}%c%{KW}%{= R}%{-}"
shelltitle "$ |bash"
defscrollback 50000
startup_message off
# escape ^aA
escape ^aa
termcapinfo xterm|xterms|xs|rxvt ti@:te@ # scroll bar support
term rxvt # mouse support
width 130
height 40
bindkey -k k; screen
bindkey -k F1 prev
bindkey -k F2 next
bindkey -d -k kb stuff ^H
bind x remove
bind j eval "focus down"
bind k eval "focus up"
bind s eval "split" "focus down" "prev"
vbell off
shell -bash
linux screen修改会话名字
[
|
2012/04/18 15:10]


开了多个screen的话,每次screen -r的时候都有一大串需要选择,默认是用进程号.终端号.主机名来做名字的,无法分辨分别是做什么的,只能一个一个试。
用ctrl+a+A试了下,发现只能改一个tab的名字。问了问高人,原来用:
ctrl+a :sessionname my_screen_name
即可。
当然,最好是在启动screen的时候用screen -S my_screen_name来直接指定名字。
用ctrl+a+A试了下,发现只能改一个tab的名字。问了问高人,原来用:
ctrl+a :sessionname my_screen_name
即可。
当然,最好是在启动screen的时候用screen -S my_screen_name来直接指定名字。
lemon语法分析器模板初探
[
|
2012/04/18 00:24]


今天看了一下lighttpd解析http头的过程,之前一直以为是单纯用遍历字符串的形式做的,今天发现除了遍历字符串,还用到了语法分析器来做解析,生成语法分析器模板的就是lemon,语法比较直观,不看文档就能大概看出逻辑,不过深入研究就要借助文档了,文档比较晦涩,需要仔细研究。
大概用法:使用lemon的语法编写一个.y文件,然后调用lemon命令或使用lemon源文件将.y转化成.c和.h,转化后的.c看起来就很晕了,完全看不懂的说。
这个东西还是挺有意思的,lighttpd还用它来解析配置文件。不过配置文件用lua也很不错啊。我准备以后多使用lua作为配置文件,方便灵活。
大概用法:使用lemon的语法编写一个.y文件,然后调用lemon命令或使用lemon源文件将.y转化成.c和.h,转化后的.c看起来就很晕了,完全看不懂的说。
这个东西还是挺有意思的,lighttpd还用它来解析配置文件。不过配置文件用lua也很不错啊。我准备以后多使用lua作为配置文件,方便灵活。
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更高级的权限,需要单独授予。
为blog添加ping插件-自动通知搜索引擎
[
|
2012/04/13 22:13]


现在主流搜索引擎都支持ping功能了,每当网站更新时可以主动向搜索引擎发一个xml格式信息,称之为”ping“,通知搜索引擎来抓取,对于收录是非常有好处的。
之前一直懒得搞,今天弄了一下。
参照百度站长工具里提供的格式,搞了一个,试试是否好用呢。
添加了baidu和google的ping地址:
http://ping.baidu.com/ping/RPC2
http://blogsearch.google.com/ping/RPC2
之前一直懒得搞,今天弄了一下。
参照百度站长工具里提供的格式,搞了一个,试试是否好用呢。
添加了baidu和google的ping地址:
http://ping.baidu.com/ping/RPC2
http://blogsearch.google.com/ping/RPC2