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 [email protected]:[email protected] # 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 [email protected]:[email protected] # 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 '[email protected]: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 '[email protected]: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