Git各指令的本質,真是通俗易懂啊

前言

做爲當前世界上最強大的代碼管理工具Git相信你們都很熟悉,但據我所知有很大一批人停留在clone、commit、pull、push...的階段,是否是對rebase內心沒底只敢用merge?遇見版本回退就抓瞎?別問我怎麼知道的,問就是:「我曾經就是這樣啊~~」。針對這些問題,今天我就將這幾年對Git的認知和理解分享出來,儘量的從本質去講解Git,幫助你一步一步去了解Git的底層原理,相信讀完本篇文章你即可以換種姿態,更加風騷得使用Git各類指令。git

目錄

  • 1. 基本概念
    • 1.1 Git的優點
    • 1.2 文件狀態
    • 1.3 commit 節點
    • 1.4 HEAD
    • 1.5 遠程倉庫
  • 2. 分支
    • 2.1 什麼是分支?
  • 3. 命令詳解
    • 3.1 提交相關
    • 3.2 分支相關
    • 3.3 合併相關
    • 3.4 回退相關
    • 3.5 遠程相關

1. 基本概念

1.1 Git的優點

Git是一個分佈式代碼管理工具,在討論分佈式以前避免不了說起一下什麼是中央式代碼管理倉庫服務器

  • 中央式:全部的代碼保存在中央服務器,因此提交必須依賴網絡,而且每次提交都會帶入到中央倉庫,若是是協同開發可能頻繁觸發代碼合併,進而增長提交的成本和代價。最典型的就是svn
  • 分佈式:能夠在本地提交,不須要依賴網絡,而且會將每次提交自動備份到本地。每一個開發者均可以把遠程倉庫clone一份到本地,並會把提交歷史一併拿過來。表明就是Git

Git相比於svn有什麼優點呢?打個比方:"巴拉巴拉寫了一大堆代碼,忽然發現寫的有問題,我想回到一個小時以前",對於這種狀況Git的優點就很明顯了,由於commit的成本比較小而且本地會保存全部的提交記錄,隨時隨刻能夠進行回退。在這並非說svn的不能完成這種操做,只是Git的回退會顯得更加的優雅。Git相比於中央式工具還有不少優勢,就不一一列舉了,感興趣的可自行了解。markdown

1.2 文件狀態

在Git中文件大概分爲三種狀態:已修改(modified)、已暫存(staged)、已提交(committed)網絡

  • 修改:Git能夠感知到工做目錄中哪些文件被修改了,而後把修改的文件加入到modified區域
  • 暫存:經過add命令將工做目錄中修改的文件提交到暫存區,等候被commit
  • 提交:將暫存區文件commit至Git目錄中永久保存

1.3 commit節點

爲了便於表述,本篇文章我會經過節點代稱commit提交併發

在Git中每次提交都會生成一個節點,而每一個節點都會有一個哈希值做爲惟一標示,屢次提交會造成一個線性節點鏈(不考慮merge的狀況),如圖1-1分佈式

節點上方是經過 SHA1計算的哈希值svn

C2節點包含C1提交內容,一樣C3節點包含C一、C2提交內容工具

1.4 HEAD

HEAD是Git中很是重要的一個概念,你能夠稱它爲指針或者引用,它能夠指向任意一個節點,而且指向的節點始終爲當前工做目錄,換句話說就是當前工做目錄(也就是你所看到的代碼)就是HEAD指向的節點。測試

還以圖1-1舉例,若是HEAD指向C2那工做目錄對應的就是C2節點。具體如何移動HEAD指向後面會講到,此處不要糾結。fetch

同時HEAD也能夠指向一個分支,間接指向分支所指向的節點

1.5 遠程倉庫

雖然Git會把代碼以及歷史保存在本地,但最終仍是要提交到服務器上的遠程倉庫。經過clone命令能夠把遠程倉庫的代碼下載到本地,同時也會將提交歷史分支HEAD等狀態一併同步到本地,但這些狀態並不會實時更新,須要手動從遠程倉庫去拉取,至於什麼時候拉、怎麼拉後面章節會講到。

經過遠程倉庫爲中介,你能夠和你的同事進行協同開發,開發完新功能後能夠申請提交至遠程倉庫,同時也能夠從遠程倉庫拉取你同事的代碼。

注意點

由於你和你的同事都會以遠程倉庫的代碼爲基準,因此要時刻保證遠程倉庫的代碼質量,切記不要將未經檢驗測試的代碼提交至遠程倉庫

2. 分支

2.1 什麼是分支?

分支也是Git中至關重要的一個概念,當一個分支指向一個節點時,當前節點的內容便是該分支的內容,它的概念和HEAD很是接近一樣也能夠視爲指針引用,不一樣的是分支能夠存在多個,而HEAD只有一個。一般會根據功能版本創建不一樣的分支

那分支有什麼用呢?

  • 舉個例子:大家的 App 經歷了千辛萬苦終於發佈了v1.0版本,因爲需求緊急v1.0上線以後便快馬加鞭的開始v1.1,正當你開發的興起時,QA同窗說用戶反饋了一些bug,須要修復而後從新發版,修復v1.0確定要基於v1.0的代碼,但是你已經開發了一部分v1.1了,此時怎麼搞?

面對上面的問題經過引入分支概念即可優雅的解決,如圖2-1

2-1

  • 先看左邊示意圖,假設C2節點既是v1.0版本代碼,上線後在C2的基礎上新建一個分支ft-1.0
  • 再看右邊示意圖,在v1.0上線後可在master分支開發v1.1內容,收到QA同窗反饋後提交v1.1代碼生成節點C3,隨後切換到ft-1.0分支作bug修復,修復完成後提交代碼生成節點C4,而後再切換到master分支併合並ft-1.0分支,到此咱們就解決了上面提出的問題

除此以外利用分支還能夠作不少事情,好比如今有一個需求不肯定要不要上線,可是得先作,此時能夠單首創建一個分支開發該功能,等到啥時候須要上線直接合併到主分支便可。分支適用的場景不少就不一一列舉了。

注意點

當在某個節點建立一個分支後,並不會把該節點對應的代碼複製一份出來,只是將新分支指向該節點,所以能夠很大程度減小空間上的開銷。必定要記着無論是HEAD仍是分支它們都只是引用而已,量級很是輕

3. 命令詳解

3.1 提交相關

前面咱們提到過,想要對代碼進行提交必須得先加入到暫存區,Git中是經過命令 add 實現

添加某個文件到暫存區:

git add 文件路徑
複製代碼

添加全部文件到暫存區:

git add .
複製代碼

同時Git也提供了撤銷工做區暫存區命令

撤銷工做區改動:

git checkout -- 文件名
複製代碼

清空暫存區:

git reset HEAD 文件名
複製代碼

提交:

將改動文件加入到暫存區後就能夠進行提交了,提交後會生成一個新的提交節點,具體命令以下:

git commit -m "該節點的描述信息"
複製代碼

3.2 分支相關

建立分支

建立一個分支後該分支會與HEAD指向同一節點,說通俗點就是HEAD指向哪建立的新分支就指向哪,命令以下:

git branch 分支名
複製代碼

切換分支

當切換分支後,默認狀況下HEAD會指向當前分支,即HEAD間接指向當前分支指向的節點

git checkout 分支名
複製代碼

同時也能夠建立一個分支後當即切換,命令以下:

git checkout -b 分支名
複製代碼

刪除分支

爲了保證倉庫分支的簡潔,當某個分支完成了它的使命後應該被刪除。好比前面所說的單獨開一個分支完成某個功能,當這個功能被合併到主分支後應該將這個分支及時刪除。

刪除命令以下:

git branch -d 分支名
複製代碼

3.3 合併相關

關於合併的命令是最難掌握同時也是最重要的。咱們經常使用的合併命令大概有三個mergerebasecherry-pick

merge

merge是最經常使用的合併命令,它能夠將某個分支或者某個節點的代碼合併至當前分支。具體命令以下:

git merge 分支名/節點哈希值
複製代碼

若是須要合併的分支徹底領先於當前分支,如圖3-1所示

3-1

因爲分支ft-1徹底領先分支ft-2ft-1徹底包含ft-2,因此ft-2執行了「git merge ft-1」後會觸發fast forward(快速合併),此時兩個分支指向同一節點,這是最理想的狀態。可是實際開發中咱們每每碰到是是下面這種狀況:如圖3-2(左)

這種狀況就不能直接合了,當ft-2執行了「git merge ft-1」後Git會將節點C3C4合併隨後生成一個新節點C5,最後將ft-2指向C5 如圖3-2(右)

注意點:

若是C3C4同時修改了同一個文件中的同一句代碼,這個時候合併會出錯,由於Git不知道該以哪一個節點爲標準,因此這個時候須要咱們本身手動合併代碼

rebase

rebase也是一種合併指令,命令行以下:

git rebase 分支名/節點哈希值
複製代碼

merge不一樣的是rebase合併看起來不會產生新的節點(其實是會產生的,只是作了一次複製),而是將須要合併的節點直接累加 如圖3-3

當左邊示意圖的ft-1.0執行了git rebase master後會將C4節點複製一份到C3後面,也就是C4'C4C4'相對應,可是哈希值卻不同。

rebase相比於merge提交歷史更加線性、乾淨,使並行的開發流程看起來像串行,更符合咱們的直覺。既然rebase這麼好用是否是能夠拋棄merge了?其實也不是了,下面我羅列一些mergerebase的優缺點:

merge優缺點:

  • 優勢:每一個節點都是嚴格按照時間排列。當合併發生衝突時,只須要解決兩個分支所指向的節點的衝突便可
  • 缺點:合併兩個分支時大機率會生成新的節點並分叉,長此以往提交歷史會變成一團亂麻

rebase優缺點:

  • 優勢:會使提交歷史看起來更加線性、乾淨
  • 缺點:雖然提交看起來像是線性的,但並非真正的按時間排序,好比圖3-3中,無論C4早於或者晚於C3提交它最終都會放在C3後面。而且當合併發生衝突時,理論上來說有幾個節點rebase到目標分支就可能處理幾回衝突

對於網絡上一些只用rebase的觀點,做者表示不太認同,若是不一樣分支的合併使用rebase可能須要重複解決衝突,這樣就得不償失了。但若是是本地推到遠程並對應的是同一條分支能夠優先考慮rebase。因此個人觀點是 根據不一樣場景合理搭配使用mergerebase,若是以爲都行那優先使用rebase

cherry-pick

cherry-pick的合併不一樣於mergerebase,它能夠選擇某幾個節點進行合併,如圖3-4

命令行:

git cherry-pick 節點哈希值
複製代碼

3-4

假設當前分支是master,執行了git cherry-pick C3(哈希值),C4(哈希值)命令後會直接將C3C4節點抓過來放在後面,對應C3'C4'

3.4 回退相關

分離HEAD

在默認狀況下HEAD是指向分支的,但也能夠將HEAD從分支上取下來直接指向某個節點,此過程就是分離HEAD,具體命令以下:

git checkout 節點哈希值
//也能夠直接脫離分支指向當前節點
git checkout --detach
複製代碼

因爲哈希值是一串很長很長的亂碼,在實際操做中使用哈希值分離HEAD很麻煩,因此Git也提供了HEAD基於某一特殊位置(分支/HEAD)直接指向前一個前N個節點的命令,也即相對引用,以下:

//HEAD分離並指向前一個節點
git checkout 分支名/HEAD^
複製代碼
//HEAD分離並指向前N個節點
git checkout 分支名~N
複製代碼

HEAD分離出來指向節點有什麼用呢?舉個例子:若是開發過程發現以前的提交有問題,此時能夠將HEAD指向對應的節點,修改完畢後再提交,此時你確定不但願再生成一個新的節點,而你只需在提交時加上--amend便可,具體命令以下:

git commit --amend
複製代碼

回退

回退場景在平時開發中仍是比較常見的,好比你巴拉巴拉寫了一大堆代碼而後提交,後面發現寫的有問題,因而你想將代碼回到前一個提交,這種場景能夠經過reset解決,具體命令以下:

//回退N個提交
git reset HEAD~N
複製代碼

reset相對引用很像,區別是reset會使分支HEAD一併回退。

3.5 遠程相關

當咱們接觸一個新項目時,第一件事情確定是要把它的代碼拿下來,在Git中能夠經過clone從遠程倉庫複製一份代碼到本地,具體命令以下:

git clone 倉庫地址
複製代碼

前面的章節我也有提到過,clone不只僅是複製代碼,它還會把遠程倉庫的引用(分支/HEAD)一併取下保存在本地,如圖3-5所示:

其中origin/masterorigin/ft-1爲遠程倉庫的分支,而遠程的這些引用狀態是不會實時更新到本地的,好比遠程倉庫origin/master分支增長了一次提交,此時本地是感知不到的,因此本地的origin/master分支依舊指向C4節點。咱們能夠經過fetch命令來手動更新遠程倉庫狀態

小提示:

並非存在服務器上的才能稱做是遠程倉庫,你也能夠clone本地倉庫做爲遠程,固然實際開發中咱們不可能把本地倉庫看成公有倉庫,說這個只是單純的幫助你更清晰的理解分佈式

fetch

說的通俗一點,fetch命令就是一次下載操做,它會將遠程新增長的節點以及引用(分支/HEAD)的狀態下載到本地,具體命令以下:

git fetch 遠程倉庫地址/分支名
複製代碼

pull

pull命令能夠從遠程倉庫的某個引用拉取代碼,具體命令以下:

git pull 遠程分支名
複製代碼

其實pull的本質就是fetch+merge,首先更新遠程倉庫全部狀態到本地,隨後再進行合併。合併完成後本地分支會指向最新節點

另外pull命令也能夠經過rebase進行合併,具體命令以下:

git pull --rebase 遠程分支名
複製代碼

push

push命令能夠將本地提交推送至遠程,具體命令以下:

git push 遠程分支名
複製代碼

若是直接push可能會失敗,由於可能存在衝突,因此在push以前每每會先pull一下,若是存在衝突本地解決。push成功後本地的遠程分支引用會更新,與本地分支指向同一節點

綜上所述

  • 無論是HEAD仍是分支,它們都只是引用而已,引用+節點是 Git 構成分佈式的關鍵
  • merge相比於rebase有更明確的時間歷史,而rebase會使提交更加線性應當優先使用
  • 經過移動HEAD能夠查看每一個提交對應的代碼
  • clonefetch都會將遠程倉庫的全部提交引用保存在本地一份
  • pull的本質其實就是fetch+merge,也能夠加入--rebase經過rebase方式合併

文章中圖畫的有點low,全程ppt,你們知道有比較好的免費的畫圖工具嗎?事先謝過~

相關文章
相關標籤/搜索