<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hant-TW">
	<id>https://jiva.dila.edu.tw/index.php?action=history&amp;feed=atom&amp;title=Pro_Git_3.1_%E5%88%86%E6%94%AF%E6%98%AF%E4%BB%80%E9%BA%BC</id>
	<title>Pro Git 3.1 分支是什麼 - 修訂歷史</title>
	<link rel="self" type="application/atom+xml" href="https://jiva.dila.edu.tw/index.php?action=history&amp;feed=atom&amp;title=Pro_Git_3.1_%E5%88%86%E6%94%AF%E6%98%AF%E4%BB%80%E9%BA%BC"/>
	<link rel="alternate" type="text/html" href="https://jiva.dila.edu.tw/index.php?title=Pro_Git_3.1_%E5%88%86%E6%94%AF%E6%98%AF%E4%BB%80%E9%BA%BC&amp;action=history"/>
	<updated>2026-05-05T21:13:15Z</updated>
	<subtitle>本 Wiki 上此頁面的修訂歷史</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://jiva.dila.edu.tw/index.php?title=Pro_Git_3.1_%E5%88%86%E6%94%AF%E6%98%AF%E4%BB%80%E9%BA%BC&amp;diff=530&amp;oldid=prev</id>
		<title>imported&gt;Ray：​新頁面: 為了理解 Git 分支(branch)的實做方式，我們需要回顧一下 Git 是如何儲存資料的。或許你還記得第一章的內容，Git 保存的不是檔案差異或者變化...</title>
		<link rel="alternate" type="text/html" href="https://jiva.dila.edu.tw/index.php?title=Pro_Git_3.1_%E5%88%86%E6%94%AF%E6%98%AF%E4%BB%80%E9%BA%BC&amp;diff=530&amp;oldid=prev"/>
		<updated>2011-05-25T01:21:52Z</updated>

		<summary type="html">&lt;p&gt;新頁面: 為了理解 Git 分支(branch)的實做方式，我們需要回顧一下 Git 是如何儲存資料的。或許你還記得第一章的內容，Git 保存的不是檔案差異或者變化...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新頁面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;為了理解 Git 分支(branch)的實做方式，我們需要回顧一下 Git 是如何儲存資料的。或許你還記得第一章的內容，Git 保存的不是檔案差異或者變化量，而只是一系列檔案快照。&lt;br /&gt;
&lt;br /&gt;
在 Git 中提交時，會保存一個提交（commit）物件，它包含一個指向暫存內容快照的指標，作者和相關附屬資訊，以及一定數量（也可能沒有）指向該提交物件直接祖先的指標：第一次提交是沒有直接祖先的，普通提交有一個祖先，由兩個或多個分支合併產生的提交則有多個祖先。&lt;br /&gt;
&lt;br /&gt;
為直觀起見，我們假設在工作目錄中有三個檔，準備將它們暫存後提交。暫存操作會對每一個檔案計算校驗和(checksum, 即第一章中提到的 SHA-1 雜湊字串)，然後把當前版本的檔案快照保存到 Git 倉庫中（Git 使用 blob 類型的物件儲存這些快照），並將校驗和加入暫存區域：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git add README test.rb LICENSE2&lt;br /&gt;
$ git commit -m 'initial commit of my project'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
當使用 git commit 新建一個提交物件前，Git 會先計算每一個子目錄（本例中就是專案根目錄）的校驗和，然後在 Git 倉庫中將這些目錄保存為樹（tree）物件。之後 Git 創建的提交物件，除了包含相關提交資訊以外，還包含著指向這個樹物件（專案根目錄）的指標，如此它就可以在將來需要的時候，重現此次快照的內容了。&lt;br /&gt;
&lt;br /&gt;
現在，Git 倉庫中有五個物件：三個表示檔案快照內容的 blob 物件；一個記錄著目錄樹內容及其中各個檔對應 blob 物件索引的 tree 物件；以及一個包含指向 tree 物件（根目錄）的索引和其他提交資訊中繼資料(metadata)的 commit 物件。概念上來說，倉庫中的各個物件保存的資料和相互關係看起來如圖 3-1 所示：&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-1.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-1. 一次提交後倉庫裡的資料&lt;br /&gt;
&lt;br /&gt;
作些修改後再次提交，那麼這次的提交物件會包含一個指向上次提交物件的指標（譯注：即下圖中的 parent 物件）。兩次提交後，倉庫歷史會變成圖 3-2 的樣子：&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-2.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-2. 多次提交後的 Git 物件資料&lt;br /&gt;
&lt;br /&gt;
現在來談分支。Git 中的分支，其實本質上僅僅是個指向 commit 物件的可變指標。Git 會使用 master 作為分支的預設名字。在若干次提交後，你其實已經有了一個指向最後一次提交物件的 master 分支，它在每次提交的時候都會自動向前移動。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-3.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-3. 指向提交資料歷史的分支&lt;br /&gt;
&lt;br /&gt;
那麼，Git 又是如何創建一個新的分支的呢？答案很簡單，創建一個新的分支指標。比如新建一個 testing 分支，可以使用 git branch 命令：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git branch testing&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
這會在當前 commit 物件上新建一個分支指標（見圖 3-4）。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-4.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-4. 多個分支指向提交資料的歷史&lt;br /&gt;
&lt;br /&gt;
那麼，Git 是如何知道你當前在哪個分支上工作的呢？其實答案也很簡單，它保存著一個名為 &amp;lt;b&amp;gt;HEAD&amp;lt;/b&amp;gt; 的特別指標。請注意它和你熟知的許多其他版本控制系統（比如 Subversion 或 CVS）裡的 HEAD 概念大不相同。在 Git 中，它是一個&amp;lt;b&amp;gt;指向你正在工作中的本地分支的指標&amp;lt;/b&amp;gt;。運行 git branch 命令，僅僅是建立了一個新的分支，但不會自動切換到這個分支中去，所以在這個例子中，我們依然還在 master 分支裡工作（參考圖 3-5）。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-5.png]]&amp;lt;br&amp;gt; &lt;br /&gt;
圖 3-5. HEAD 指向當前所在的分支&lt;br /&gt;
&lt;br /&gt;
要切換到其他分支，可以執行 git checkout 命令。我們現在轉換到新建的 testing 分支：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git checkout testing&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
這樣 HEAD 就指向了 testing 分支（見圖3-6）。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-6.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-6. HEAD 在你轉換分支時指向新的分支&lt;br /&gt;
&lt;br /&gt;
這樣的實現方式會給我們帶來什麼好處呢？好吧，現在不妨再提交一次：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ vim test.rb&lt;br /&gt;
$ git commit -a -m 'made a change'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
圖 3-7 展示了提交後的結果。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-7.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-7. 每次提交後 HEAD 隨著分支一起向前移動&lt;br /&gt;
&lt;br /&gt;
非常有趣，現在 testing 分支向前移動了一格，而 master 分支仍然指向原先 git checkout 時所在的 commit 物件。現在我們回到 master 分支看看：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ git checkout master&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
圖 3-8 顯示了結果。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-8.png]]&amp;lt;br&amp;gt; &lt;br /&gt;
圖 3-8. HEAD 在一次 checkout 之後移動到了另一個分支&lt;br /&gt;
&lt;br /&gt;
這條命令做了兩件事。它把 HEAD 指標移回到 master 分支，並把工作目錄中的檔案換成了 master 分支所指向的快照內容。也就是說，現在開始所做的改動，將始於本專案中一個較老的版本。它的主要作用是將 testing 分支裡作出的修改暫時取消，這樣你就可以向另一個方向進行開發。&lt;br /&gt;
&lt;br /&gt;
我們作些修改後再次提交：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;XML&amp;quot;&amp;gt;&lt;br /&gt;
$ vim test.rb&lt;br /&gt;
$ git commit -a -m 'made other changes'&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
現在我們的專案項目提交歷史產生了分叉（如圖 3-9 所示），因為剛才我們創建了一個分支，轉換到其中進行了一些工作，然後又回到原來的主分支進行了另外一些工作。這些改變分別孤立在不同的分支裡：我們可以在不同分支裡反復切換，並在時機成熟時把它們合併到一起。而所有這些工作，僅僅需要 branch 和 checkout 這兩條命令就可以完成。&lt;br /&gt;
&lt;br /&gt;
[[圖片:pro-git-3-9.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
圖 3-9. 分叉了的分支歷史&lt;br /&gt;
&lt;br /&gt;
由於 Git 中的分支實際上僅是一個包含所指物件校驗和（40 個字元長度 SHA-1 字串）的檔案，所以創建和銷毀一個分支就變得非常廉價。說白了，新建一個分支就是向一個檔案寫入 41 個位元組（外加一個分行符號）那麼簡單，當然也就很快了。&lt;br /&gt;
&lt;br /&gt;
這和大多數版本控制系統形成了鮮明對比，它們管理分支大多採取備份所有專案檔案到特定目錄的方式，所以根據專案檔案數量和大小不同，可能花費的時間也會有相當大的差別，快則幾秒，慢則數分鐘。而 Git 的實做方法與專案複雜度無關，它永遠可以在幾毫秒的時間內完成分支的創建和切換。同時，因為每次提交時都記錄了祖先資訊（譯注：即 parent 物件），所以以後要合併分支時，尋找恰當的合併基礎（譯注：即共同祖先）的工作其實已經完成了一大半，實現起來非常容易。Git 鼓勵開發者頻繁使用分支，正是因為有著這些特性作保障。&lt;br /&gt;
&lt;br /&gt;
接下來看看，我們為什麼應該頻繁使用分支。&lt;/div&gt;</summary>
		<author><name>imported&gt;Ray</name></author>
	</entry>
</feed>