<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                為了理解 Git 分支的實現方式,我們需要回顧一下 Git 是如何儲存數據的。或許你還記得第一章的內容,Git 保存的不是文件差異或者變化量,而只是一系列文件快照。 在 Git 中提交時,會保存一個提交(commit)對象,該對象包含一個指向暫存內容快照的指針,包含本次提交的作者等相關附屬信息,包含零個或多個指向該提交對象的父對象指針:首次提交是沒有直接祖先的,普通提交有一個祖先,由兩個或多個分支合并產生的提交則有多個祖先。 為直觀起見,我們假設在工作目錄中有三個文件,準備將它們暫存后提交。暫存操作會對每一個文件計算校驗和(即第一章中提到的 SHA-1 哈希字串),然后把當前版本的文件快照保存到 Git 倉庫中(Git 使用 blob 類型的對象存儲這些快照),并將校驗和加入暫存區域: ~~~ $ git add README test.rb LICENSE $ git commit -m 'initial commit of my project' ~~~ 當使用 git commit 新建一個提交對象前,Git 會先計算每一個子目錄(本例中就是項目根目錄)的校驗和,然后在 Git 倉庫中將這些目錄保存為樹(tree)對象。之后 Git 創建的提交對象,除了包含相關提交信息以外,還包含著指向這個樹對象(項目根目錄)的指針,如此它就可以在將來需要的時候,重現此次快照的內容了。 現在,Git 倉庫中有五個對象:三個表示文件快照內容的 blob 對象;一個記錄著目錄樹內容及其中各個文件對應 blob 對象索引的 tree 對象;以及一個包含指向 tree 對象(根目錄)的索引和其他提交信息元數據的 commit 對象。概念上來說,倉庫中的各個對象保存的數據和相互關系看起來如圖 3-1 所示: ![2015-05-18/5559fd1067c0e](https://box.kancloud.cn/2015-05-18_5559fd1067c0e.png) 圖 3-1. 單個提交對象在倉庫中的數據結構 作些修改后再次提交,那么這次的提交對象會包含一個指向上次提交對象的指針(譯注:即下圖中的 parent 對象)。兩次提交后,倉庫歷史會變成圖 3-2 的樣子: ![2015-05-18/5559ff5ab607f](https://box.kancloud.cn/2015-05-18_5559ff5ab607f.png) 圖 3-2. 多個提交對象之間的鏈接關系 現在來談分支。Git 中的分支,其實本質上僅僅是個指向 commit 對象的可變指針。Git 會使用 master 作為分支的默認名字。在若干次提交后,你其實已經有了一個指向最后一次提交對象的 master 分支,它在每次提交的時候都會自動向前移動。 ![2015-05-18/5559ff8756754](https://box.kancloud.cn/2015-05-18_5559ff8756754.png) 圖 3-3. 分支其實就是從某個提交對象往回看的歷史 那么,Git 又是如何創建一個新的分支的呢?答案很簡單,創建一個新的分支指針。比如新建一個 testing 分支,可以使用 git branch 命令: `$ git branch testing` 這會在當前 commit 對象上新建一個分支指針(見圖 3-4)。 ![2015-05-18/5559ffea76284](https://box.kancloud.cn/2015-05-18_5559ffea76284.png) 圖 3-4. 多個分支指向提交數據的歷史 那么,Git 是如何知道你當前在哪個分支上工作的呢?其實答案也很簡單,它保存著一個名為 HEAD 的特別指針。請注意它和你熟知的許多其他版本控制系統(比如 Subversion 或 CVS)里的 HEAD 概念大不相同。在 Git 中,它是一個指向你正在工作中的本地分支的指針(譯注:將 HEAD 想象為當前分支的別名。)。運行 git branch 命令,僅僅是建立了一個新的分支,但不會自動切換到這個分支中去,所以在這個例子中,我們依然還在 master 分支里工作(參考圖 3-5)。 ![2015-05-18/555a000c5bb41](https://box.kancloud.cn/2015-05-18_555a000c5bb41.png) 圖 3-5. HEAD 指向當前所在的分支 要切換到其他分支,可以執行 git checkout 命令。我們現在轉換到新建的 testing 分支: `$ git checkout testing` 這樣 HEAD 就指向了 testing 分支(見圖3-6)。 ![2015-05-18/555a010dd9394](https://box.kancloud.cn/2015-05-18_555a010dd9394.png) 圖 3-6. HEAD 在你轉換分支時指向新的分支 這樣的實現方式會給我們帶來什么好處呢?好吧,現在不妨再提交一次: ~~~ $ vim test.rb $ git commit -a -m 'made a change' ~~~ 圖 3-7 展示了提交后的結果。 ![2015-05-18/555a01365cc25](https://box.kancloud.cn/2015-05-18_555a01365cc25.png) 圖 3-7. 每次提交后 HEAD 隨著分支一起向前移動 非常有趣,現在 testing 分支向前移動了一格,而 master 分支仍然指向原先 `git checkout `時所在的 commit 對象。現在我們回到 master 分支看看: `$ git checkout master` 圖 3-8 顯示了結果。 ![2015-05-18/555a0159cbd7d](https://box.kancloud.cn/2015-05-18_555a0159cbd7d.png) 圖 3-8. HEAD 在一次 checkout 之后移動到了另一個分支 這條命令做了兩件事。它把 HEAD 指針移回到 master 分支,并把工作目錄中的文件換成了 master 分支所指向的快照內容。也就是說,現在開始所做的改動,將始于本項目中一個較老的版本。它的主要作用是將 testing 分支里作出的修改暫時取消,這樣你就可以向另一個方向進行開發。 我們作些修改后再次提交: ~~~ $ vim test.rb $ git commit -a -m 'made other changes' ~~~ 現在我們的項目提交歷史產生了分叉(如圖 3-9 所示),因為剛才我們創建了一個分支,轉換到其中進行了一些工作,然后又回到原來的主分支進行了另外一些工作。這些改變分別孤立在不同的分支里:我們可以在不同分支里反復切換,并在時機成熟時把它們合并到一起。而所有這些工作,僅僅需要 branch 和 checkout 這兩條命令就可以完成。 ![2015-05-18/555a018d77ee5](https://box.kancloud.cn/2015-05-18_555a018d77ee5.png) 圖 3-9. 不同流向的分支歷史 由于 Git 中的分支實際上僅是一個包含所指對象校驗和(40 個字符長度 SHA-1 字串)的文件,所以創建和銷毀一個分支就變得非常廉價。說白了,新建一個分支就是向一個文件寫入 41 個字節(外加一個換行符)那么簡單,當然也就很快了。 這和大多數版本控制系統形成了鮮明對比,它們管理分支大多采取備份所有項目文件到特定目錄的方式,所以根據項目文件數量和大小不同,可能花費的時間也會有相當大的差別,快則幾秒,慢則數分鐘。而 Git 的實現與項目復雜度無關,它永遠可以在幾毫秒的時間內完成分支的創建和切換。同時,因為每次提交時都記錄了祖先信息(譯注:即 `parent` 對象),將來要合并分支時,尋找恰當的合并基礎(譯注:即共同祖先)的工作其實已經自然而然地擺在那里了,所以實現起來非常容易。Git 鼓勵開發者頻繁使用分支,正是因為有著這些特性作保障。 接下來看看,我們為什么應該頻繁使用分支。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看