2009-10-31 17 views
11

分佈式版本控制(Git,Bazaar和Mercurial)中的每一個都以不同的方式處理分支。例如,在集市中,分支機構是單獨的回購協議(實際上是父代回購協議的不同副本);在您的文件系統上,不同的分支位於不同的目錄中。另一方面,在Git中,您可以在同一個倉庫中存在多個分支(因此可以在您的文件系統的同一目錄中)。 Mercurial支持both behaviors,後者與named branchesDVCS中不同分支模型的優缺點

這些不同的分支模型有哪些優缺點?在我看來,Bazaar的一個分支,一個回購的方法比Git的方法更讓分支更痛苦(例如,在集市中使用分支,我必須先創建分支,然後從我當前的工作副本中cd出來,然後退房新的分支,就像我在SVN中那樣)。

+4

命名分支是完全不同於git分支,詳情請參閱這裏:http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/ – tonfa 2009-10-31 19:37:01

+0

另請參見我的答案在「Git和Mercurial - 比較和對比」中,也涵蓋了分支:http://stackoverflow.com/questions/1598759/git-and-mercurial-compare-and-contrast/1599930#1599930 – 2009-10-31 22:00:00

+0

男人,tonfa永遠在我做之前設法發佈我的博客條目! :) – 2009-11-01 14:18:32

回答

9

Bazaar並不要求你按照你描述的方式工作。實際上我前兩天寫了a blog post。你可以只用一個工作樹來工作,在不同的分支之間切換並創建新的分支而不用離開工作樹。對此有用的命令是:checkout,switch,branch --switch。查看Bazaar的workflow文檔,您將看到您可以以任何您想要的方式對其進行配置。

+0

很高興知道Bazaar比我想象的更加靈活。我實際上想知道如果在你的倉庫裏創建一個「branches」目錄可以解決我在我的問題中提到的問題。感謝您的洞察力。 – ThisSuitIsBlackNot 2009-10-31 19:15:05

6

對於Git以外的VCS中的分支模型我不太瞭解。我想說,在任何DVCS中,您都可以通過克隆來實現分支(通過克隆創建分支)。 Mercurial所謂的「命名分支」(據我所知)實際上承諾標籤只被解釋爲分支,有時需要本地編號修訂以解決歧義。 Mercurial「書籤」,我認爲,與Git分支非常相似。具有非常不同概念的分支的兩個DVCS是MonotoneDarcs。我認爲Subversion使用的「通過複製分支」,其中項目名稱和分支名稱之間的分隔是約定,這是錯誤的想法。


在Git修訂版中形成了提交的有向無環圖(DAG)。它是直接的,因爲承諾有父母。這是一個非常重要的問題:提交DAG中的邊緣是從提交到它的父代(或者在合併提交的情況下,它的兩個或多個父代)。提交圖是非循環的,這意味着不存在以相同對象開始和結束的鏈(無路徑)。

Git glossary將「分支」定義爲活動發展線。這個想法背後是在Git中實現分支。

分支上最近的提交被稱爲該分支的提示。分支的頂端由分支頭引用,它只是此提交的符號名稱。在它的「鬆散」形式中,這樣的分支頭(例如名爲'master'的分支)只是在git倉庫(位於.git dir)內的refs/heads/目錄中的某個文件,其中包含對分支當前尖端的引用:其SHA-1提交的標識符(作爲十六進制字符串)。

當你在Git中創建一個新的提交時,當前簽出的分支的前端向前移動。換句話說,新的提交被創建在當前分支的頂端,並且分支頭部前進到新的提交(有點類似於指向棧頂的指針可能前進)。

一個git倉庫可以跟蹤任意數量的分支,但是你的工作樹(如果有的話)只與其中一個(「當前」或「簽出」分支)相關聯。當前分支由HEAD指針給出。 HEAD是(通常)指向當前檢出分支(到分支頭名稱)的指針,就像分支頭是指向分支尖的指針。

例如,如果當前已簽出分支是「主」,則.git/HEAD文件(表示HEAD)將包含單個LF終止ref: refs/heads/master(一個符號引用refs/heads/master),和.git/refs/heads/master(「主」分支的頭)線將包含例如LF終止線0b127cb8ab975e43398a2b449563ccb78c437255,這是SHA-1標識符到'主'分支的提示(也就是說,如果當前分支不是「打包」的:那麼你必須看看.git/packed-refs)。

Git中的一些命令,如「git commit」或「git reset」操縱/更改分支頭;其他如「git checkout」操縱/更改HEAD(對當前分支的符號引用)。

git log branch」命令顯示所有可從分支提示中獲得的提交,這意味着分支的提示,它的父代,父提交等。它顯示提交的DAG的一部分。

在Git刪除分支意味着只需刪除分支頭。這可能意味着某些提交變得「不可見」,無法訪問的freom refs(分支和標籤),這意味着在某些時候,這些提交可能會從存儲庫中收集垃圾並將其從中移除。但是,如果你可以用「git branch -d <branchname>」刪除分支,那麼這意味着不會有任何提交丟失;你可以用「git branch -D <branchname>」強制刪除分支。重命名分支只是重命名分支頭的一個問題,它是分支尖端的符號引用(符號名稱);分支名稱不保存在提交對象的任何地方。


GIT中還具有reflogs,這是其中分支末梢尖(以及何時)的本地歷史概念。例如,如果您修改了「git commit --amend」的提交,則分支提示將被修改的提交替換,並且在修改之前和之後HEAD ^將成爲提交的父代,而在修改之前將會在reflog中輸入版本,修改後。如果您使用「git reset」重繞歷史記錄,則reflog將在倒帶前包含舊分支提示的信息。

總之,reflog爲git命令提供了額外的安全性和簡單的恢復。