hg常用命令


關於hg命令選項

如果你是在windows系統下,使用的是圖像界面,你很可能不常用它。但是一旦你了解這些命令之后,會覺得很方便。hg有很多命令,這些命令都有一定的選項,在開始的時候,只知道用它,有時候命令選項以”–”開頭,有時又以”-”開頭。翻閱資料,發現對於命令選項,hg有以下的約定。

  1. 每一個命令選項都有一個長的名稱,如hg log 命令會使用 –rev選項;
  2. 大多數選項擁有一個短的名稱,如—rev有一個-r的短名;
  3. 長名稱以兩條橫線(–)作為起始,短名起始是一條橫線(-)。如—rev、-r;
  4. 無論是長名還是短名,其用途是一致的。如-r和—rev 其后都跟一個變更集合的ID或版本號;
  5. 如果使用的是短名,多個名稱可以連在一起運行。如hg log –v –r –p 2可以寫作hg log –vpr 2。

關於hg log命令

使用該命令可以了解代碼倉庫變更的歷史,其輸出的結果中包含以下幾個字段:

  1. changeset 該字段被一個分號(:)分成兩部分,分號的前面是一個數字,其后是一個十六進制的字符串。在查看版本歷史的時候,常常會用到前面得數字。這里需要注意的是,該數字所代表的變更集合不是唯一的(比如a,b,c在一個代碼倉庫中的順序是0,1,2,在另外一個代碼倉庫中可能是0,2,1)。真正指向唯一的變更集合的是后面的十六進制的字符串。
  2. user 代表集合的創建者;
  3. date 代表集合創建的時間;
  4. summary 創建者提供的關於該集合的描述文本;
  5. tag 有一些集合會包含一個tag字段,這個特別的字段總是指向代碼倉庫中最新的版本。

明白以上字段的含義,對於你查看版本歷史和提交代碼時書寫描述性文本很有意義。在后面的章節中,甚至可以根據這些字段改變其輸出的格式。

要查看特定的版本,在hg log 后跟上版本號即可,如:

1. //查看特定的版本;
2. hg log -r 2

同時查看幾個版本,可以使用如下的命令:

1. //查看版本2,3,4
2. Hg log -r 2:4

如果要查看版本的詳細內容,包括文件發生改變的內容,可以添加-p(–patch)命令選項。

1. //查看版本的詳細內容
2. hg -log -vpr 1

下圖是使用該命令后的輸出結果:

使用hg commit 提交代碼的需要注意的問題

第一次使用hg commit命令提交代碼時,很可能會出現代碼無法提交的問題。這是因為在代碼提交時hg會嘗試去找到一個有效的用戶名。它會按下面的順序去逐個嘗試尋找有效的用戶名:

  1. 如果在使用hg conmit提交代碼時,使用-u命令選項,並在其后跟上一個用戶名(如:dexibe@gmail.com)。此時,該命令將具有最高的優先權;
  2. 如果沒有第一步的命令選項,它會查看你是否設置了HGUSER環境變量;
  3. 如果在你的home目錄下,你創建了.hgrc文件,並且該文件設置了username,它會啟用該用戶名;
  4. 到這一步,它會查看你的email環境變量;
  5. 如果以上都沒有找到合適的用戶信息,hg 將查看你的系統尋找用戶名和主機名稱,並試圖根據這些組件構建有效的用戶名,通常情況下用戶名是不可用的,只會呈現一段警示語句;

下圖是沒有設置用戶名提交代碼時的輸出結果:

拉取和推送代碼

拉取代碼,使用hg pull即可,有一個hg incoming命令我很少用到,仔細看了看,這個命令還是很管用。hg incoming命令不會真正的拉取代碼到本地倉庫,它只是告訴你使用hg pull會將哪些變更集合拉至本地倉庫。這對於你拉取特定的版本集合很管用。

推送代碼,使用hg push即可。在真正推送之前,可以使用hg outgoing查看有哪些改變將會被推送至代碼倉庫。

 

在項目推進的過程中,經常會出現兩個人共同修改一個文件的情況。這個時候,我們就要進行代碼合並。使用hg合並代碼非常簡單。Hg記錄每一次變更集合的父級,如果變更集合一個父級,一個head就是一個沒有子級的集合。當多人修改同一個文件時,就會出現不止一個head的情況,此時需要進行代碼合並。

如果一個文件同時被幾個人修改,hg pull命令會告知你”heads”的情況。此時如果使用hg update命令,會出現以下的提示語:abort: crosses branches (use ‘hg merge’ or ‘hg update -C’)

如果要強制更新,可以使用hg update –C。要查看heads可以使用hg heads命令,該命令會告知你head的情況,使用hg merge就會完成兩個head之間的代碼合並。此時使用hg parents命令會看到父級的情況。在完成代碼合並之后,一定不要忘記使用hg commit命令提交更改的代碼。

大多數情況下,代碼合並都很簡單。但是,如果多個人修改文件的同一個地方,情況就有所不同了。除非修改的內容一樣,否則會導致沖突發生。Hg不能很好的處理這些沖突,但是它能運行外部程序來處理這些沖突,如kdiff3。這種合並就是所謂的“三路合並”(three-way merge)。此時,窗口會被分成三部分:

  1. 左邊是文件的的基礎版本;
  2. 中間是你自己的版本,文件包括被修改的內容;
  3. 右側是你將要與之合並的版本。

你可以在三個窗口之間來回切換,修改文件的沖突部分,將其更改為我們需要的部分。一旦完成文件合並,一定要記住提交合並之后的代碼。Hg本身不能處理有沖突的變更集合,它會在存在沖突文件上留下一個標記,告知用戶該文件存在沖突。

仔細回憶一下,從代碼倉庫中拉取代碼(hg pull)后,更新(hg update)本地倉庫,進行代碼合並(hg merge),提交(hg commit)合並的代碼。在hg中有一個命令可以完成前三步操作,它就是fetch。要啟用它,只需在.hgrc中的[extensions] 設置fetch = 即可,這是個標准的擴展,hg知道在何處去查找這個擴展,使用hg help extensions命令,你可以看到關於fetch的描述: pull ,update and merge one command。啟用成功之后,使用hg fetch試試。

前面的兩節簡要地記錄了使用hg命令的一些注意事項,並提到了文件merge的一些知識,這一節將回顧使用hg來添加、刪除、復制文件的一些操作。

一、如何讓HG跟蹤你的文件

hg不會自動的管理你倉庫中文件,hg status命令會告訴你那些它不知道的文件,它會在這些文件的前面打上一個“?”號。假如在你的倉庫中有一個myfile.txt的文件,執行hg status你會看到:

在myfile.txt前面,我們會看到一個“?”號。如要讓hg管理該文件,執行如下命令:

1. hg add myfile.txt

此時運行hg st,你會看到:

文件myfile.txt前面的“?”號變成了“A”。執行hg commit命令之后,myfile.txt就不會再出現在hg status的輸出結果之中。hg status命令的輸出結果中僅包含刪除的(removed)、被修改的(modified)、重命名的(renamed)文件。添加一個文件,hg什么也不會做,它只是在執行下一次提交(hg commit)之前對該文件“拍一張快照”。

在將文件添加到代碼倉庫中,需注意一下幾點:

  1. 如果使用hg add后跟的是一個目錄,該命令會將該目錄下的所有文件添加到倉庫之中,包括子目錄中的文件。假如有一個目錄b,其下有一個文件some.txt和d目錄,d目錄之下有一個文件c.txt。運行hg add b,你會看到:

  2. hg並不追蹤文件夾信息,而是追蹤文件的路徑。在創建一個文件之前,首先創建文件所在的路徑。刪除一個文件后,它會刪除文件所在路徑的所有空的文件夾。一般情況下,很少用到空文件夾。如果在你的代碼倉庫中需要空文件夾,可以通過hg add來添加一個隱藏的文件。在linux系統中,任何以“.”開頭的文件都被視作隱藏文件。除此之外,你可以在需要它之前通過自動化執行腳本方式創建空文件夾。

二、如何停止文件跟蹤

如果你決定不讓代碼倉庫跟蹤你的文件,使用hg remove命令即可。文件刪除之后,運行hg status后的輸出結果中,被刪除的文件之前會打上“R”標識符。假如我移除我倉庫中的myfile.txt文件,你會看到:

使用hg remove刪除一個文件后,hg將停止追蹤該文件的任何改變。即使你重新創建一個與之同名的文件, hg也會無動於衷。假設你重新創建一個與之同名的文件,運行hg add命令讓hg跟蹤它。hg會認為新添加的文件與先前的同名文件毫無關聯。

刪除一個文件並不會對該文件的歷史帶來任何影響。它僅僅從當前工作目錄中移除文件的當前版本,並在下一次代碼提交的時候讓hg停止對該文件的追蹤。

如果你不是使用hg remove來刪除一個文件,hg會認為文件丟失。它會在丟失的文件之前打上“!”標識符。假設我手動刪除工作目錄下的myfile.txt,然后運行hg status命令,你會看到如下結果:

假設你的本意是將該文件刪除,你可以在任何時候運行hg remove –after命令來真正的刪除該文件。緊跟上面的例子,執行該命令會看到如下結果:

可以看到,myfile.txt前面打上了“R”標識符。

如果意外的刪除了丟失的文件,可以使用hg revert命令將其恢復。還是緊跟上面的例子,運行該命令,你會看到:

你可能認為文件添加和刪除操作相當繁瑣。令人興奮的是,hg有一些快捷方式可以一次完成文件的添加和刪除文件操作。

  1. 使用hg addremove命令;
  2. 在提交代碼時使用-A參數,即hg commint -A -m “提交代碼”。

三、復制文件

hg提供了hg copy命令來復制一個文件。用該命令來復制文件,hg會記住新的的文件是源文件的副本。在你合並代碼的時候,它會對其作特殊的處理。下圖是使用hg copy復制文件后的截圖:

從圖中可以看到,hg status -C 可以看到myfile-copy.txt是從myfile.txt復制而來。復制的文件在代碼合並的時候會發生什么呢?以下是在在兩個工作目錄中復制文件,並在一個倉庫中修改文件時的截圖。

查看myfile-copy.txt,你會看到,對myfile.txt所作的修改同步到了myfile-copy.txt。這看上去有些怪異,但是其結果卻相當盡如人意。可以想見,如果hg不將其同步到文件副本,那么該副本就會保持原來的版本不變。當然,你也可以手動去修改副本文件。這里需要注意的是,這種信息直播僅發生在以下幾種情況:

  1. 代碼合並的時;
  2. 你的代碼倉庫中還沒有該文件的副本時。

如果說這種文件復制所導致的信息直播並不是你所需要的結果,你可以使用系統正常的文件復制操作。比如使用unix中的cp命令,然后用hg add命令將其添加至代碼倉庫。

如果你修改一個文件,但是在沒有提交代碼的情況下復制該文件,那么在該副本文件中仍將包含文件被修改的部分。

hg copy命令與unix系統中的cp命令極其相似,只需要提供兩個或三個以上的參數即可,最后的一個參數被視作目的地,其它都被視作復制源。這種操作包括以下幾種情況:

  1. 目的地不存在,源文件為單個文件,將創建同名的新文件;如:
    1. hg copy a k//目錄k不存在,重建k目錄,並將a復制到k文件夾之下
  2. 目的地是一個目錄,將源文件復制到該目錄之下;如:
    1. hg copy a b d// 將a 和b 復制到d目錄之下
  3. 復制源跟目的地都是目錄,則將復制源復制到目標文件夾之下,並在目標文件夾之下根據復制源目錄的名稱重建目錄,且保持復制源的目錄樹結構;如:
    1. hg copy z d //假設z的目錄樹結構為z/a/c,復制到目錄d后,d的目錄樹結構為d/z/a/c
  4. 復制源是一個目錄,目的地不存在,則創建新的目錄,並將復制源下的目錄樹復制到新的目錄之下;如:
    1. hg copy z e//假設z的目錄結構為z/a/c,復制完成后e的目錄結構為e/a/c

與hg remove命令一樣,如果你手動復制一個文件,並讓hg能跟蹤此文件,可以使用hg copy –after [源文件] [目標文件],如:

1. cp  a b
2. hg copy --after a b

四、文件重命名

與文件復制操作相比,文件重命名操作更為常見。在hg代碼管理中,文件重命名操作在本質上等同於文件復制操作。因此,理解了文件的復制操作,文件重命名操作就不是太難。

使用hg rename進行重命名操作時,hg先對文件進行復制操作,然后刪除該文件,並標注該文件已經刪除。如:

從圖中可以看到,重命名的newfile.txt前面打上了“A”標識符,源文件myfile.txt前面打上了“R”標識符。運行hg status -C你會看到如下的結果:

同樣,如果你手動重命名一個文件,你也可以使用–after選項來讓hg追蹤你重命名的文件。在 unix系統中,可以使用hg mv命令來重命名一個文件。以下是在windows系統中操作的截圖:

既然重命名操作與復制操作相似,那么在代碼合並時對被重命名文件所作的操作將會同步至被重命名后的文件。比如,當你對一個文件進行修改,而你的同伴對該文件進行了重命名操作。在代碼合並的時候,你所做的修改將被同步到被重命名的文件之中。

對文件進行重命名操作時,會遇到以下兩種情況:

  1. 同一個文件被重命名為不同的名稱。在這種情況下,進行代碼合並的時候,hg會發出警告,提示用戶該文件存在不同的文件名,讓用戶去決定選擇哪一個文件名;
  2. 不同的文件被命名為相同的文件名。在這種情況下,hg會按正常合並程序來合並代碼,讓用戶去選擇合適的方案
  3. 在你的代碼倉庫中的有一個目錄文件,它的名稱與另外一個代碼倉庫中的文件名相同。這種情況下進行代碼合並時,合並將會終止,這是Mercurial 遺留下來的一個bug。詳情可以查看http://mercurial.selenic.com/bts/issue29。

五、如何處理較為復雜的代碼合並

一般來說,合並代碼是一件很簡單的事情。不過有些時候代碼合並也不是那么順利。假如一個項目中有一個較大的文件同時被幾個人編輯,沖突就很容易出現,運行hg heads命令就會看到兩個或多個head的情況,此時就需要分別與每一個head進行合並,並提交代碼,直至看到一個head為止。如果代碼合並沒有完成,hg將會阻止代碼提交。

如果合並代碼后提交代碼失敗,可以使用hg resolve命令。進行代碼合並后,如果 hg發現文件為unresolved 狀態,則認為代碼合並失敗。hg resolve –list或hg resolve -l會輸出每一個合並文件的狀態,如果文件前面有一個標識符“U”,則認為合並不成功,提交代碼就會失敗。對於hg resolve,有以下幾個常見的選項:

  1. –all或-a,嘗試去合並所有unresolved 狀態的文件;
  2. –mark或-m,直接將文件修改為resolved 狀態;
  3. –unmask或-u,直接將文件修改為unresolved 狀態。

六、關於hg diff

hg diff有一個選項–Git或者-g,該選項我們很少用到。假如你修改了一個文件的權限,運行hg status會看到文件被修改,而運行hg diff將看不到任何輸出結果。如果在hg diff后跟上-g選項,你將會看到文件的實際狀態。在unix系統下運行以下代碼,看看輸出結果。

1. chmod +x a
2. hg diff -g

七、后話

版本控制系統通常用來管理文本文件,一些集中式版本控制系統也能處理二進制文件。集中式版本控制系統提供一種鎖定機制來編輯文件,這會很好的處理文件沖突的發生。假如一個項目中有多個人頻繁的修改一些二進制文件,那么hg或其它的分布式管理系統也許就不是最好的工具。

在修改文件時,hg僅僅存貯文件當前版本與上一個版本間的差異。如果對文件做一次小小的改動導致文件的邏輯發生了巨大的改變,hg就不能很有效的存儲這些差異,並直接影響到存儲的空間和clone代碼所花費的時間。因此,對於以下的兩種情形應慎之又慎:

  1. 較大而且不能壓縮的文件;
  2. 文件頻繁編輯導致版本間產生巨大差異。

hg維護着克隆的所有歷史,任何人的代碼倉庫都可以作為備份源。當然,可以在遠程服務器上構建一個小小的腳本來定時備份代碼倉庫。如果只是作傳統的備份,運行hg clone -U myrepo myrepo.bak即可,這里的選項-U會在clone完成后不對工作目錄進行更新操作,詳情可以參看hg help clone。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM