一月 15, 2012

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 莫非定律: 當你相信用不著時,它偏偏派上用場

上禮拜,我作了大掃除。清掉了堆在家裡一段時間的紙箱。結果,今天我的桌上型電腦開不了機了,需要箱子送回維修。

因為「桌上型電腦會壞掉」這件事,我想要把「HG」伺服器,全部丟給 bitbucket.org 管理。我的桌上型電腦只剩下三種功能: hg server, zotera sync server, file backup 。

zotera sync server 用到的機會不多,因為我最近不常看文獻,而且它的使用頻率不高。而 file backup 是將代管的 web system 的資料順便備一份到我家作異地備援,如果我沒開機,則會拖個幾天才作異地備份。

於是,最影響我工作效率的是「 hg server 」無法運作。雖然 hg 是分散式版本控制器,不用中央伺服器存在,也能正常工作。但少了中央伺服器,我的眾多電腦們就不方便傳送 changeset 了。

為此,我相信 bitbucket.org 的伺服器維護能力高於我,所以我要把全部儲存庫交給它們管理。而且 bitbucket.org 的託管方案很優惠,我們可以開設任意數量的 public 或 private 儲存庫,只要這些儲存庫的參與用戶不高於 5 位。超過 5 位才開始計價,詳可閱

七月 6, 2011
» Using perfarce with Mercurial 1.9

If you’re in the kind of situation of using perfarce with Perforce, after upgrade to Mercurial 1.9, you may need the patch at this moment(perfarce changeset c05711ba688f):

diff -r c05711ba688f perfarce.py
--- a/perfarce.py	Fri Apr 15 14:22:16 2011 +0100
+++ b/perfarce.py	Wed Jul 06 11:04:34 2011 +0800
@@ -77,17 +77,17 @@ Five built-in commands are overridden:
            the p4 depot. Directory and filename case is preserved.
            These two setting are workarounds to handle Perforce depots
            containing a path spelled differently from file to file
            (e.g. path/foo and PAth/bar are in the same directory),
            or where the same file may be spelled differently from time
            to time (e.g. path/foo and path/FOO are the same object).
 '''
 
-from mercurial import cmdutil, commands, context, copies, encoding, error, extensions, hg, node, repo, util, url
+from mercurial import cmdutil, commands, context, copies, encoding, error, extensions, hg, node, repo, util, scmutil, url
 from mercurial.node import hex, short
 from mercurial.i18n import _
 
 import marshal, tempfile, os, re, string
 
 def uisetup(ui):
     '''monkeypatch pull and push for p4:// support'''
 
@@ -1279,27 +1279,27 @@ def push(original, ui, repo, dest=None, 
 
     try:
         # now add/edit/delete the files
         if mod:
             modal(_('opening for edit: %s\n'), 'edit -c %s' % use, mod, client.encodename)
 
         if mod or add:
             ui.note(_('retrieving file contents...\n'))
-            opener = util.opener(client.rootpart)
+            opener = scmutil.opener(client.rootpart)
 
             for name, mode in mod + add:
                 ui.debug(_('writing: %s\n') % name)
                 if 'l' in mode:
                     opener.symlink(ctx[name].data(), name)
                 else:
                     fp = opener(name, mode="w")
                     fp.write(ctx[name].data())
                     fp.close()
-                util.set_flags(client.localpath(name), 'l' in mode, 'x' in mode)
+                util.setflags(client.localpath(name), 'l' in mode, 'x' in mode)
 
         if add:
             modal(_('opening for add: %s\n'), 'add -f -c %s' % use, add, lambda n:n)
 
         if ntg:
             ui.note(_('opening for integrate: %s\n') % ' '.join(f[1] for f in ntg))
             for f in ntg:
                 client.runs('integrate -c %s %s %s' % (use, f[0], f[1]))

» Using perfarce with Mercurial 1.9

If you’re in the kind of situation of using perfarce with Perforce, after upgrade to Mercurial 1.9, you may need the patch at this moment(perfarce changeset c05711ba688f):

diff -r c05711ba688f perfarce.py
--- a/perfarce.py	Fri Apr 15 14:22:16 2011 +0100
+++ b/perfarce.py	Wed Jul 06 11:04:34 2011 +0800
@@ -77,17 +77,17 @@ Five built-in commands are overridden:
            the p4 depot. Directory and filename case is preserved.
            These two setting are workarounds to handle Perforce depots
            containing a path spelled differently from file to file
            (e.g. path/foo and PAth/bar are in the same directory),
            or where the same file may be spelled differently from time
            to time (e.g. path/foo and path/FOO are the same object).
 '''
 
-from mercurial import cmdutil, commands, context, copies, encoding, error, extensions, hg, node, repo, util, url
+from mercurial import cmdutil, commands, context, copies, encoding, error, extensions, hg, node, repo, util, scmutil, url
 from mercurial.node import hex, short
 from mercurial.i18n import _
 
 import marshal, tempfile, os, re, string
 
 def uisetup(ui):
     '''monkeypatch pull and push for p4:// support'''
 
@@ -1279,27 +1279,27 @@ def push(original, ui, repo, dest=None, 
 
     try:
         # now add/edit/delete the files
         if mod:
             modal(_('opening for edit: %s\n'), 'edit -c %s' % use, mod, client.encodename)
 
         if mod or add:
             ui.note(_('retrieving file contents...\n'))
-            opener = util.opener(client.rootpart)
+            opener = scmutil.opener(client.rootpart)
 
             for name, mode in mod + add:
                 ui.debug(_('writing: %s\n') % name)
                 if 'l' in mode:
                     opener.symlink(ctx[name].data(), name)
                 else:
                     fp = opener(name, mode="w")
                     fp.write(ctx[name].data())
                     fp.close()
-                util.set_flags(client.localpath(name), 'l' in mode, 'x' in mode)
+                util.setflags(client.localpath(name), 'l' in mode, 'x' in mode)
 
         if add:
             modal(_('opening for add: %s\n'), 'add -f -c %s' % use, add, lambda n:n)
 
         if ntg:
             ui.note(_('opening for integrate: %s\n') % ' '.join(f[1] for f in ntg))
             for f in ntg:
                 client.runs('integrate -c %s %s %s' % (use, f[0], f[1]))

十二月 4, 2010
» Mercurial 介紹簡報



今天在 TWJUG 做的 Mercurial 簡報

九月 28, 2010
» DropBox & SparkleShare

http://linuxtoy.org/archives/sparkleshare-beta.html

DropBox是種結合了本地和雲端, 能改變使用者習慣的重要技術。

DropBox讓使用者可以用原本的形式來處理檔案和文件, 只要在各種作業系統上安裝DropBox提供的軟體,登入DropBox帳號後即會在本地建立一個資料夾。
這個資料夾中的所有檔案都會自動同步到DropBox伺服器。如果你有多台設備(電腦, iPad, 智慧手機),並都登入了同一帳號,那麼當資料夾中的任一檔案被更新後,其他台設備很快就也能接收到這些檔案的更新。DropBox真正做到了隨處可得。

很方便的是,不管是對檔案、文件夾改名,或是刪除檔案都難不倒它。如果在其中一台刪除了檔案,其他台的檔案也會一併被刪除。為了解決客戶對誤操作的擔憂,DropBox還提供了類似蘋果電腦上的時光回溯(Time Machine)功能(技術上基本就是將檔案操作結合版本控制系統),若是做了誤操作,可以登入到DropBox網站上將上次的誤操作回復到之前狀態,真是非常安心。

另外,放在DropBox檔案夾下的檔案,除了可以像以前的作法用網芳分享給在同個網域下的朋友外,還可以直接將一個資料夾分享給其他同樣有DropBox帳號的朋友,真正是天涯若彼鄰。

SparkleShare 則是它的 open source 替代品,後端使用GIT版本控制系統。

PS: 大家看了我上面的介紹,可以知道我真的很愛這種東西。因為研究所時我也花過一段時間研究,並發過一篇一樣為解決多台設備間資料同步問題的 paper,而人家真的做出來了 :D

九月 26, 2010

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 如何處理「合併(merge)錯誤的 hg 儲存庫」? 就是再用「merge」來復原!

學弟把我們已經作好的分枝要合併進主線時,不知怎麼搞地 merge 得非常混亂,而且也 push -f 進 hg 伺服器。

我們總共有三種分枝: 'default', 'Release for XXX', 'convert to InnoDB',這次是要把 'convert to InnoDB' 的成果合併進 'default' ,再合併到 'Release for XXX' 。'convert to InnoDB' 是我們將 django-based 的系統從 MyISAM 引擎改到 InnoDB 所作的程式碼修改。主要的修改是發生在索引上,因為原本有一個地方設定了 unique_together = (('name', 'uplevel_id'), ) ,而它會造成 MySQL Error code 1071錯誤('Specified key was too long; max key length is 767 bytes'),因為 name 的原長度是 256 ,而我們又使用 utf8 ,所以它的實際長度為 256 * 3 = 768 ,但在 InnoDB 的索引中,限制為 767 以下,所以我們必須將 name 的長度限制為 255 。

當我改完程式碼後,就請學弟們在自己的本機上測試,如果沒問題的話,就作合併的動作,並送到實際運作的網站去。

結果,他合出了下面這個東西:



D 版是我的分枝成果,我希望他把 D 合併到 B 跟 C 中。但他生出了 E, F, G, H 。這 4 個版本都不是我想要的。

一開始,我的作法是再次作手動合併,結果我迷失在那些修改的程式碼中,花了快 3 個小時,依舊無法解開,所以我當時用下策來處理,就是以 hg strip 指令把 hg 伺服器上的 E ~ H 的版本洗掉。然後重作合併。

這個方法十分爛,但當下,剛好沒有人上傳程式碼,而我又陷在那堆程式碼中,所以我選了這個作法。

這種作法,會有一個大問題,如果有人在未刪除版本前,就作了 pull, update ,那麼下次他在 push 時,就會出現衝突。他一定會 merge 到亂掉,因為他手上的 E ~ H 版本的程式碼不具含意,所以他也無法以程式碼內含意義來作合併,這樣他會像我一樣陷入毛線當中。

所以,在我解決 hg 伺服器上的亂象後,我靜下心來仔細思考,才發現我何必管 E ~ H 作了什麼事呢! 我只要在 merge 時,忽略它們的修改就行啦!

首先,我 clone 一個 LOCAL 儲存庫,而且只 clone A, B, C, D 之前的版本。作法必須分兩次,因為 clone 只會把該版本的媽媽下載下來,所以像是 A, B, C, D 4 個版本,卻有 2 個 heads ,我就得分兩個指令來下載,指令如下:

$ hg clone https://SERVER/my_software LOCAL -r C
$ cd LOCAL
$ hg pull -u -r D

然後,依我原本想要的合併方式處理:

$ hg ci -m '"convert to InnoDB" branch ...' --close-branch #P.S. 這個作法事後會造成問題 *1
$ hg merge -r B
$ hg ci -m WRITE_f'_COMMIT_MESAGE # 產生 f'
$ hg merge -r C
$ hg ci -m WRITE_g'_COMMIT_MESAGE # 產生 g'

這樣 LOCAL 的版本圖就像下圖一樣。



再來,我把伺服器上的錯誤版本 clone 到本機的 SERVER-FIX ,然後在 SERVER-FIX 中依 branch 作合併,最後合併出 'convert to InnoDB' 及 'Release for XXX' 兩種 heads ,指令如下:

$ hg clone https://SERVER/my_software SERVER-FIX
$ cd SERVER-FIX
$ hg update -C H
$ hg merge -r E
$ hg ci -m WHATEVER_MESSAGE

成果如下圖:



接下來,我回到 LOCAL 儲存庫中,把 changeset push 到 SERVER-FIX 中,成果如下圖:



最後,我要作的就是把 I, G, g' 三者合而為一,而且要在 merge 時,完全忽略 I, G 的程式碼修改,怎麼作呢? 指令如下:

$ cd SERVER-FIX
$ hg update -C g'
$ hg merge -r I
$ hg status
M models.py
$ hg cat -r g' models.py > models.py # I 版的修改,只在 models.py 上,而我又用 g' 版的 models.py 把 I 版修改完全洗掉了
$ hg ci -m MERGE_g'_I_MESSAGE
$ hg merge -r G
$ hg status
M models.py
$ hg cat -r g' models.py > models.py # G 版的修改,只在 models.py 上,而我又用 g' 版的 models.py 把 G 版修改完全洗掉了
$ hg ci -m MERGE_g'_I_G_MESSAGE

最後成果如下圖:



再為各位整理一下,合併「錯誤的 hg 儲存庫」步驟:

1. 在本機上,重作一個完全正確的 LOCAl 儲存庫。
2. 在本機上,重現一個與伺服器相同的 SERVER-FIX 儲存庫,並依 branch 作合併,讓一個 branch 只有一個 head 。
3. 將 LOCAL 的成果 push 到 SERVER-FIX 中。
4. 讓 SERVER-FIX 中的 head 與 LOCAL 的 tip 合併。而且在合併時,完全消除程式碼的修改,讓它們合併完,程式碼是與 LOCAL 的 tip 程式碼完全相同。
5. 確認無誤,就能 push 到 hg 伺服器了。

以這種方式處理完的 hg 伺服器,才可以讓所有人都免去再次合併 E~H 這段錯誤程式碼的痛苦。

基本上, hg 的主要運作方法,就是要讓所有人習慣在自己的本機上, merge 自己與其他人的成果,如果你能順暢地走完 1 ~ 4 的步驟,也代表你足以應用 hg 在大部份的程式碼修改工作了。

註1 我太早在 'convert to InnoDB' 分枝上下 --close-branch ,所以我後來在使用 hg update -C 'convert to InnoDB' 時,它居然是 update 到 I 版,而不是 e' 版。

九月 11, 2010
» 分散式版本控制的合作模式

傳統的版本控制系統(Version Control System, VCS)只有一台單一的版本庫(repository),所有的版本控制都必須經由這台版本庫主機才能管理。新一代的分散式版本控制系統(Distributed Version Control System, DVCS)如 git, Mercurial 則每份抓下來的 code 都可起到等同於版本庫的作用,使得在離線時做版本控制,並能容易地合併回主版本庫的工作模式成為可能。

因為分散的特性,也衍生出各種可能的合作模式。
git 有 A successful Git branching model,Mercurial有 Workflows: Branch As Needed, Stable & Default, Translation Branches 等方式。

實際上該採用哪種方式比較好?先看看其他人怎麼做,從中選擇,或是加點創意,找出適合自己團隊使用的方法吧。

» Mercurial, 分支與合併很簡單

Mercurial(Hg) 一直是我很愛用的版本控制工具。以前自己最常用的用途是拿來取代 svn,單純享受單機/離線使用版本控制系統開發的樂趣。

要單機使用版本控制系統開發,照著水銀分散式版本控制系統的使用概念做就行了。

最近看了Hg initProGit兩份分別講Hg和Git分散式版本控制的書,裡面都相當推崇「分支(Branch)開發」的概念。
所謂「分支開發」,就是將主幹(trunk)保持在穩定可運作的版本(雖然本來就該這麼做),在開發任何新功能時都另建新分支(branch),開發到一段落之後再合併回主幹。能支援這樣的開發模式,是因為Hg或Git這些分散式版本控制系統做開分支、合併等動作的額外開銷都很低。

那麼要實際使用時該怎麼做呢?

開分支

我有一個名為「ZAKU」(薩克)的目錄,主幹版本代號為3, 現在要實作一個將綠色變成紅色的功能,這時我們可以建立一個新分支來繼續開發這個新功能。分支命令的格式為:

$ hg branch [branch name]

因此要建立一個名為「red」的分支,可以使用以下命令:
$ hg branch red
marked working directory as branch red

這麼一來,之後 commit 的 code 都會進入「red」這個分支了。

查看狀態

在 commit 進一些 code 之後(版本代號到13),輸入「hg branchs」命令可以列出所有版本

$ hg branches
default 3:e2287f9031a1 (inactive)
red 13:e590de4b0dc9

切換分支

在開發新功能的同時,也可能會碰上整個專案共通的bug,以前老派的作法是再 check out 一份主幹的程式碼,然後兩邊修正,現在有了hg, 只要先暫時切換回主幹,把bug修正了再合併回分支(或到時一次把分支合併回主幹)。

要切換回主幹,輸入「hg update default」即可。

$ hg up default
4 files 已更新, 0 files 已合併, 3 files 已移除, 0 files unresolved

合併

當我們把「red」分支中的新功能做好後,可以很容易地將這些修改合併回主幹。

首先,用上面的方法切換回主幹,然後輸入「hg merge red」,即可將「red」分支中的修改加進主幹。

$ hg merge red
5 files 已更新, 0 files 已合併, 0 files 已移除, 0 files unresolved
(branch merge, don't forget to commit)

合併命令的格式為

hg merge [branch name]

合併完後確認沒問題,就將程式碼再 commit 進版本庫吧!

如果只想 push 某 branch 的修改到版本庫,可以使用
hg push --rev [version]

命令,這樣只會將與指定版本相關的修改上傳到版本庫。

One more thing

同樣的方法,我們可以再建立一個分支「horn」來開發長角的功能,然後再將「horn」分支合併回主幹。

別忘了hg還有提供一個離線網頁瀏覽功能,輸入「hg serve -p 5000」,在瀏覽器上輸入「http://localhost:5000」就能看到類似 gitweb 的版本控制訊息網頁。點選左側的「graph」標籤,可以用視覺化的方式看到之前所有分支合併的圖形記錄囉!

學會分支與合併後,你的開發效率會不會也變成三倍速哩?

參考資料:
* http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/

九月 8, 2010
» [Mercurial]多來源更新

在做完「hg clone」(就如同從 Server 端 Check Out 程式碼)後,除了可以對原 Server 做「hg pull」以更新程式碼之外,也可以多加別台 Server 進列表。

如原來從 Alice 處「hg clone」下來原始碼,而現在也想要從 Bob 處直接取得他的更新,可以使用

$ hg pull [bob server]
命令。

另一個好方法是可以在 .hg/hgrc 中定義額外的 Server 別名(alias)。

例如原來的 .hg/hgrc 長這樣:
[paths]
default = [Alice Server]/[project]

我們在其後加入 Bob Server 的別名如下:
[paths]
default = [Alice Server]/[project]
bob = [Bob server]/[project]

儲存後,要再從 Bob 處直接取得他的更新,可以使用
$ hg pull bob

命令來直接取得 bob 的原始碼。分散式版本控制是不是很方便呢 :)

二月 3, 2010
» GoogleCode & Mercurial 版本控制介紹

今天在台北 GTUG 講「GoogleCode & Mercurial 版本控制介紹」。

一月 20, 2010
» 分散式版本控制系統大亂鬥

讀到 DVCS Round-Up: One System to Rule Them All? 記錄一下。(還有Part IIPart III)這麼長的文章在一般狀況下實在沒什麼耐心看下去。還好 Mac 上的 Text-To-Speech 功能做的非常好用,把預設的語速調快,並設定快速鍵(我設成 Command+~)後,讀一篇長文其實花不了幾分鐘。

現在最常用的版本控制系統應該是 svn、hg、git 三種。
svn(Subversion)、hg(Mercurial) 是自己平時會使用的版本控制系統,由於 hg 跟 svn 的命令幾乎相同,轉換時的學習曲線相當平緩,都是相當方便的工具。google code 剛好也是支援這兩種。git 則是開發 linux 系統時的常用的工具。

十二月 28, 2007
» 開源的 Java 社群正向著水銀遷移

剛剛發現開源的 Java 社群在版本控制系統(version control) 的選擇,正向著 Python mercurial 遷移。

證據是 Mercurial 的官方網站上列出了近期的幾個 Sun 的重要專案都採用了 Mercurial:

# 2007-12-12 NetBeans migrates to mercurial
# 2007-12-05 OpenJDK (aka Java) switches to Mercurial
# 2006-10-18 OpenSolaris announces ON Mercurial repository mirror

包含 Sun 官方的 Java、NetBeans 跟 OpenSolaris 都採用 mercurial 分散式版本控制系統。
這對社群有極佳的示範作用。

試想一下,就跟許多 Linux 發佈套件開始用 BT 來分流一樣。
既然都開放下載了,用分散式的版本控制系統有助 Sun 降低其公司的網路流量,應該能省下不少花費。

另外,在 Windows 上相當有名的 tortoise 系列圖形化版本控制工具也出了 Mercurial 版囉,名叫tortoisehg。(另外兩種是 tortoisecvs 跟 tortoisesvn)

九月 21, 2007
» 水銀 (mercurial) 浸入了大恐龍(Mozilla)

最近 mozilla 宣佈要採用 水銀(mercurial, hg) 當作他們未來的版本控制系統.

我試了一下發現mercurial有用 twist 提供內建的 web server,
想用版本控制時再也不用先搞定 apache 設定了, Python 真是好呀

水銀分散式版本控制系統的使用概念如下:

0. 開個檔案夾([origin]), 開始 coding.
1. 告訴自己這個檔案夾裡放的是版本庫 (hg init).
2. 將原始版本中的所有檔案放進版本庫(hg commit *).
3. 怕接下來的修改把原始版本改糟了, 所以另外複製一份來改 (hg clone [origin] [dst]).
4. 在複製檔案夾上改一改, 覺得弄完一小階段了, 先大致查看一下修改了些甚麼(hg status), 然後儲存修改 (hg commit).
5. 重複修改的過程.
5.x 哇!遇到錯誤了怎麼辦? 沒關係, 用'快速鍵'將修改復原(hg revert [id]).
6. 改得滿意了, 將修改的東西存回原始檔案夾 (hg push [origin]).
7. 整理一下原始檔案夾(hg update), 確認修改沒衝突.

其他應用
* 開個 分享讓其他人也可以用(hg serve [-p port])
* 看看修改歷程(hg log)
* 看看修改的內容 (hg diff)
* 修改有衝突了, 進去檔案看看, 解決它 (hg merge)
* 接受其他人的修改 (hg pull)

biggo.com.tw

A Django site.