[一站式學習git]跟進案例,從淺到深

- GIT與SVN的區別

  GIT是分佈式版本控制系統,它和svn的區別在於它並不只提取最新版本的文件快照,而是把代碼倉庫完整地鏡像下來。 這麼一來,任何一處協同工作用的服務器發生故障,事後都可以用任何一個鏡像出來的本地倉庫恢復。因爲每一次的克隆操作,實際上都是一次對代碼倉庫的完整備份。 要瀏覽項目的歷史,Git 不需外連到服務器去獲取歷史,然後再顯示出來——它只需直接從本地數據庫中讀取。 你能立即看到項目歷史。 如果你想查看當前版本與一個月前的版本之間引入的修改,Git 會查找到一個月前的文件做一次本地的差異計算,而不是由遠程服務器處理或從遠程服務器拉回舊版本文件再來本地處理。   這也意味着你離線或者沒有 VPN 時,幾乎可以進行任何操作。
  舉個例子:如你在飛機或火車上想做些工作,你能愉快地提交,直到有網絡連接時再上傳。 又比如你回家後 VPN 客戶端不正常,你仍能工作。 使用其它系統,做到如此是不可能或很費力的。 比如,用 Subversion 和 CVS,你能修改文件,但不能向數據庫提交修改。 這看起來不是大問題,但是你可能會驚喜地發現它帶來的巨大的不同。

-結合案例分析: GIT目錄下文件的狀態流轉

現在在你的GIT目錄工程中,輸入以下命令

git status

看看我的輸出內容:

enter image description here

從上圖中可以看到有三個紅色的選中框,我們自下而上一一介紹。


(1)Untracked files:(未跟蹤的文件:也就是說,處於這個狀態的文件,無論你修改與否,都不會被git識別處理)
(2)changes not staged commit:
處理這個狀態的文件,已經被git識別跟蹤,但是本次修改未提交到暫存區。
(3)changes to be committed:(處於該狀態的文件,已經在暫存區中,等待被commit)


那麼以上三種狀態是如何流轉的呢?


我們以黑色圖中未被跟蹤的(Untracked files 下).idea 文件爲例子:

(1)未被跟蹤的文件.idea 通過add命令,進入被跟蹤狀態

git add .idea    

(2)我們對.idea 文件隨便做一些修改,然後你會發現,它已經處於“changes not staged commit”狀態。

(3)處於“changes not staged commit”狀態的文件,通過add命令進入暫存區

 git add .idea    

(4)將暫存區的文件提交,.idea 文件狀態恢復到“未改變的狀態”,等待下一次的更改,如果再次更改,文件狀態如以上(2)中的說明。

git commit -m “描述”
說到這裏,要逐重說一下add 命令的作用:
(1)可以用它開始跟蹤新文件
(2)把已跟蹤的文件放到暫存區
(3)還能用於合併時把有衝突的文件標記爲已解決狀態

- 結合案例分析:Git 的基礎原理

  我們現在通過add命令告訴Git系統,我要跟蹤三個文件,A,B,C,那麼git系統會爲我們做些什麼呢? 哈哈,git 會給這些文件照一個“照片”,留個小小的紀念,就這樣,我們有了一張“照片”,這張照片是這個樣子的。

在這裏插入圖片描述

  此時,我想修改以下文件A和文件C,修改完成之後,由於該文件被git跟蹤,此時A 和 C文件處於“changes not staged commit”,也就是以上黑色圖中第二個紅色選中框的位置。那此時git爲我們做了什麼呢?你猜的沒錯,它又給文件再次“照相”。但是此時,它不是所有的文件都照了照片。它只給A 和 C 2個修改之後的文件做了快照。此時,他的結構是這樣的:

在這裏插入圖片描述

  想必大家根據以上案例,已經瞭解了git的原理,git存儲的是文件的快照,它只關係文件是否變化,但是不關心文件到底變化了啥。只要文件變化,它會爲該文件生成新的快照,而不是存儲變化了的細節。

- 結合案例分析:Commit,我們提交了什麼

  上面說到,git 幫我們存儲的是一個一個的文件快照,那文件快照,這張照片到底長什麼樣子呢?我們一起來看一下:

在這裏插入圖片描述

  如果我們一次提交A,B,C三個文件的文件快照,那麼commit都包含什麼呢?它會包含:author ,commiter,和tree(一個指向暫存區的指針)。這個指針包含了暫存區文件的快照地址。我們看一下它的結構:

在這裏插入圖片描述

我們看一下完成的commit的內容吧:

在這裏插入圖片描述

  作些修改後再次提交,那麼這次的提交對象會包含一個指向上次提交對象的指針( parent 對象)。

在這裏插入圖片描述

# - 什麼是分支   現在來談分支。Git 中的分支,其實本質上僅僅是個指向 commit 對象的可變指針。如下圖:

在這裏插入圖片描述

分支其實就是從某個提交對象往回看的歷史

- 分支的新建

  Git 又是如何創建一個新的分支的呢?答案很簡單,創建一個新的分支指針。比如新建一個 testing 分支,可以使用 git branch 命令:

git branch testing

  我們基於第三次提交,創建一個testing分支,上面說到,分支本質上是一個指向提交記錄的指針,那麼也就是說,我們創建了一個指向第三次提交的testing指針,我們來看一下效果圖:

![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20181210223424678.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p6MjAxMDQ1MzQ=,size_16,color_FFFFFF,t_70)
# -解讀 HEAD指針   我們現在有了2個分支,那怎麼決定我們在哪個分支上開發呢?這就要說到HEAD指針了,HEAD指針標示了我們正在工作的分支。比如說我現在在新建的testing分支上開發,那麼HEAD 指針就會指向我的testing分支,HEAD 可以理解成分支的別名,讓我們一起看下效果圖。

在這裏插入圖片描述

-結合案例分析:merge的Fast forward

  我們現在有2個分支,master 和 testing,現在我們在testing分支上,進行第四次提交。那麼我們提交的樣子就會編程以下這個樣子:

在這裏插入圖片描述

  假設,我們現在要將testing分支合併到master 上,那要怎麼做呢?   我們當前在testing分支上,我們要做的是:回到 master 分支並把hotfix合併到master
$ git checkout master
$ git merge testing
Updating f42c576..3a0874c
Fast-forward
 README | 1 -
 1 file changed, 1 deletion(-)
  請注意,合併時出現了“Fast forward”的提示。由於當前 master 分支所在的提交對象是要併入的 hotfix 分支的直接上游,Git 只需把 master 分支指針直接右移。換句話說,如果順着一個分支走下去可以到達另一個分支的話,那麼 Git 在合併兩者時,只會簡單地把指針右移,因爲這種單線的歷史分支不存在任何需要解決的分歧,所以這種合併過程可以稱爲快進(Fast forward)。

-結合案例分析:更爲複雜的merge

  經過以上的合併,我們會得到這樣的結果圖,master指針指向了第四次提交。

在這裏插入圖片描述

假設,我們有三個分支:master ,testing 和 branch3,他們的結構是這個樣子的。

在這裏插入圖片描述

第一步,我們切換到testing分支,並做第四次提交,那麼結構就會變成:

在這裏插入圖片描述

第二步:我們將master 和 testing 合併,我們的結構會變成以下的樣子:

在這裏插入圖片描述

第三步,我們切換到branch3分支,做第五次提交,那麼我們的結構就會變成:

在這裏插入圖片描述

第四步:接下來,我們讓master 合併branch3

    $ git checkout master
    $ git merge iss53

那麼會發生什麼呢?

這次合併操作的底層實現,並不同於之前 testing的併入方式。因爲這次你的開發歷史是從更早的地方開始分叉的。由於當前 master 分支所指向的提交對象(第四次提交)並不是 branch3 分支的直接祖先,Git 不得不進行一些額外處理。就此例而言,Git 會用兩個分支的末端以及它們的共同祖先(第三次提交)進行一次簡單的三方合併計算。這次,Git 沒有簡單地把分支指針右移,而是對三方合併後的結果重新做一個新的快照,並自動創建一個指向它的提交對象(第六次提交),這個提交對象比較特殊,它有兩個祖先(第四次提交和 第五次提交)。

在這裏插入圖片描述

# -分支的合併:變基 rebase   把一個分支中的修改整合到另一個分支的辦法有兩種:merge 和 rebase。   我們回到上一章節:如圖:

在這裏插入圖片描述

  我們將branch3 合併到 master,除了用merge還可以用rebase,及(將branch3裏面的變化補丁在master),那要怎麼做呢?
第一步:切換分支到branch3,生成補丁,把 branch3 裏產生的改變到 C4 上重演一遍。
$ git checkout branch3
$ git rebase master
  它的原理是回到兩個分支最近的共同祖先(第三次提交),根據當前分支(branch3)後續的歷次提交對象,生成一系列文件補丁,然後以基底分支( master)最後一個提交對象(第四次提交)爲新的出發點,逐個應用之前準備好的補丁文件,最後會生成一個新的合併提交對象,從而改寫 branch3 的提交歷史,使它成爲 master 分支的直接下游,如圖

在這裏插入圖片描述

第二步:回到 master 分支,進行一次快進合併.(快進合併:Fast-forward),該內容在上一節分支合併之merge中,有詳細的講解。
git checkout master
git merge branch3

在這裏插入圖片描述

  merge 和 rebase 雖然最後整合得到的結果沒有任何區別,但變基能產生一個更爲整潔的提交歷史。如果視察一個變基過的分支的歷史記錄,看起來會更清楚:彷彿所有修改都是在一根線上先後進行的,儘管實際上它們原本是同時並行發生的。   一般我們使用變基的目的,是想要得到一個能在遠程分支上乾淨應用的補丁 — 比如某些項目你不是維護者,但想幫點忙的話,最好用變基:先在自己的一個分支裏進行開發,當準備向主項目提交補丁的時候,根據最新的 origin/master 進行一次變基操作然後再提交,這樣維護者就不需要做任何整合工作(實際上是把解決分支補丁同最新主幹代碼之間衝突的責任,化轉爲由提交補丁的人來解決。),只需根據你提供的倉庫地址作一次快進合併,或者直接採納你提交的補丁。   請注意,合併結果中最後一次提交所指向的快照,無論是通過變基,還是三方合併,都會得到相同的快照內容,只不過提交歷史不同罷了。變基是按照每行的修改次序重演一遍修改,而合併是把最終結果合在一起。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章