最近我們在知識星球開設了《實用主義Git教程》打卡課程,幫助大家成0到1認識、使用Git。 課程主要包含如下內容: 1、學習掌握Git這個流行且強大的版本控制軟件的常用方法 2、學會如何配合Github、Gitee等平臺方便地管理自己的遠程倉庫 3、學習流行的Git圖形化軟件GitKarken的用法,vscode中git插件的用法 4、學習日常如何加速Github訪問使用、自建Git服務器等實用技能 當前課程已進行到第5課,歡迎來一起學習。
掃下面二維碼進星球學習!
以下正文。 1前言
作為當前世界上最強大的代碼管理工具Git相信大家都很熟悉,但據我所知有很大一批人停留在clone、、pull、push...的階段,是不是對心里沒底只敢用merge?碰見版本回退就抓瞎?別問我怎么知道的,問就是:“我曾經就是這樣啊~~”。針對這些問題,今天我就將這幾年對Git的認知和理解分享出來,盡可能的從本質去講解Git,幫助你一步一步去了解Git的底層原理,相信讀完本篇文章你便可以換種姿態,更加風騷得使用Git各種指令。
2目錄基本概念分支命令詳解31. 基本概念1.1 Git的優勢
Git是一個分布式代碼管理工具,在討論分布式之前避免不了提及一下什么是中央式代碼管理倉庫
那Git相比于svn有什么優勢呢?打個比方:"巴拉巴拉寫了一大堆代碼,突然發現寫的有問題,我想回到一個小時之前",對于這種情況Git的優勢就很明顯了,因為的成本比較小并且本地會保存所有的提交記錄,隨時隨刻可以進行回退。在這并不是說svn的不能完成這種操作,只是Git的回退會顯得更加的優雅。Git相比于中央式工具還有很多優點,就不一一列舉了,感興趣的可自行了解。
1.2 文件狀態
在Git中文件大概分為三種狀態:已修改()、已暫存()、已提交()
1.3 節點
為了便于表述,本篇文章我會通過節點代稱提交
在Git中每次提交都會生成一個節點,而每個節點都會有一個哈希值作為唯一標示,多次提交會形成一個線性節點鏈(不考慮merge的情況),如圖1-1
節點上方是通過 SHA1計算的哈希值
C2節點包含C1提交內容,同樣C3節點包含C1、C2提交內容
1.4 HEAD
HEAD是Git中非常重要的一個概念,你可以稱它為指針或者引用,它可以指向任意一個節點,并且指向的節點始終為當前工作目錄,換句話說就是當前工作目錄(也就是你所看到的代碼)就是HEAD指向的節點。
還以圖1-1舉例,如果HEAD指向C2那工作目錄對應的就是C2節點。具體如何移動HEAD指向后面會講到,此處不要糾結。
同時HEAD也可以指向一個分支,間接指向分支所指向的節點
1.5 遠程倉庫
雖然Git會把代碼以及歷史保存在本地,但最終還是要提交到服務器上的遠程倉庫。通過clone命令可以把遠程倉庫的代碼下載到本地,同時也會將提交歷史、分支、HEAD等狀態一并同步到本地,但這些狀態并不會實時更新,需要手動從遠程倉庫去拉取,至于何時拉、怎么拉后面章節會講到。
通過遠程倉庫為中介,你可以和你的同事進行協同開發,開發完新功能后可以申請提交至遠程倉庫,同時也可以從遠程倉庫拉取你同事的代碼。
注意點
因為你和你的同事都會以遠程倉庫的代碼為基準,所以要時刻保證遠程倉庫的代碼質量,切記不要將未經檢驗測試的代碼提交至遠程倉庫
42. 分支2.1 什么是分支?
分支也是Git中相當重要的一個概念,當一個分支指向一個節點時,當前節點的內容即是該分支的內容,它的概念和HEAD非常接近同樣也可以視為指針或引用,不同的是分支可以存在多個,而HEAD只有一個。通常會根據功能或版本建立不同的分支
那分支有什么用呢?
面對上面的問題通過引入分支概念便可優雅的解決,如圖2-1
除此之外利用分支還可以做很多事情,比如現在有一個需求不確定要不要上線,但是得先做,此時可以單獨創建一個分支開發該功能,等到啥時候需要上線直接合并到主分支即可。分支適用的場景很多就不一一列舉了。
注意點
當在某個節點創建一個分支后,并不會把該節點對應的代碼復制一份出來,只是將新分支指向該節點,因此可以很大程度減少空間上的開銷。一定要記著不管是HEAD還是分支它們都只是引用而已,量級非常輕
53. 命令詳解3.1 提交相關
前面我們提到過,想要對代碼進行提交必須得先加入到暫存區,Git中是通過命令 add 實現
添加某個文件到暫存區:
git?add?文件路徑
復制代碼添加所有文件到暫存區:
git?add?.
復制代碼同時Git也提供了撤銷工作區和暫存區命令
撤銷工作區改動:
git?checkout?--?文件名
復制代碼清空暫存區:
git?reset?HEAD?文件名
復制代碼提交:
將改動文件加入到暫存區后就可以進行提交了,提交后會生成一個新的提交節點,具體命令如下:
git?commit?-m?"該節點的描述信息"
復制代碼3.2 分支相關創建分支
創建一個分支后該分支會與HEAD指向同一節點,說通俗點就是HEAD指向哪創建的新分支就指向哪git命令行拉取代碼,命令如下:
git?branch?分支名
復制代碼切換分支
當切換分支后,默認情況下HEAD會指向當前分支,即HEAD間接指向當前分支指向的節點
git?checkout?分支名
復制代碼同時也可以創建一個分支后立即切換,命令如下:
git?checkout?-b?分支名
復制代碼刪除分支
為了保證倉庫分支的簡潔,當某個分支完成了它的使命后應該被刪除。比如前面所說的單獨開一個分支完成某個功能,當這個功能被合并到主分支后應該將這個分支及時刪除。
刪除命令如下:
git?branch?-d?分支名
復制代碼3.3 合并相關
關于合并的命令是最難掌握同時也是最重要的。我們常用的合并命令大概有三個merge、、-pick
merge
merge是最常用的合并命令,它可以將某個分支或者某個節點的代碼合并至當前分支。具體命令如下:
git?merge?分支名/節點哈希值
復制代碼如果需要合并的分支完全領先于當前分支,如圖3-1所示
由于分支ft-1完全領先分支ft-2即ft-1完全包含ft-2,所以ft-2執行了“git merge ft-1”后會觸發fast (快速合并),此時兩個分支指向同一節點,這是最理想的狀態。但是實際開發中我們往往碰到是是下面這種情況:如圖3-2(左)
這種情況就不能直接合了,當ft-2執行了“git merge ft-1”后Git會將節點C3、C4合并隨后生成一個新節點C5,最后將ft-2指向C5 如圖3-2(右)
注意點:
如果C3、C4同時修改了同一個文件中的同一句代碼,這個時候合并會出錯,因為Git不知道該以哪個節點為標準,所以這個時候需要我們自己手動合并代碼
也是一種合并指令,命令行如下:
git?rebase?分支名/節點哈希值
復制代碼與merge不同的是合并看起來不會產生新的節點(實際上是會產生的,只是做了一次復制),而是將需要合并的節點直接累加 如圖3-3
當左邊示意圖的ft-1.0執行了git 后會將C4節點復制一份到C3后面,也就是C4',C4與C4'相對應,但是哈希值卻不一樣。
相比于merge提交歷史更加線性、干凈,使并行的開發流程看起來像串行,更符合我們的直覺。既然這么好用是不是可以拋棄merge了?其實也不是了,下面我羅列一些merge和的優缺點:
merge優缺點:
優缺點:
對于網絡上一些只用的觀點,作者表示不太認同,如果不同分支的合并使用可能需要重復解決沖突,這樣就得不償失了。但如果是本地推到遠程并對應的是同一條分支可以優先考慮。所以我的觀點是 根據不同場景合理搭配使用merge和,如果覺得都行那優先使用
-pick
-pick的合并不同于merge和,它可以選擇某幾個節點進行合并,如圖3-4
命令行:
git?cherry-pick?節點哈希值
復制代碼假設當前分支是,執行了git -pick C3(哈希值),C4(哈希值)命令后會直接將C3、C4節點抓過來放在后面,對應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所示:
其中/和/ft-1為遠程倉庫的分支,而遠程的這些引用狀態是不會實時更新到本地的,比如遠程倉庫/分支增加了一次提交,此時本地是感知不到的,所以本地的/分支依舊指向C4節點。我們可以通過fetch命令來手動更新遠程倉庫狀態
小提示:
并不是存在服務器上的才能稱作是遠程倉庫,你也可以clone本地倉庫作為遠程,當然實際開發中我們不可能把本地倉庫當作公有倉庫,說這個只是單純的幫助你更清晰的理解分布式
fetch
說的通俗一點,fetch命令就是一次下載操作,它會將遠程新增加的節點以及引用(分支/HEAD)的狀態下載到本地,具體命令如下:
git?fetch?遠程倉庫地址/分支名
復制代碼pull
pull命令可以從遠程倉庫的某個引用拉取代碼,具體命令如下:
git?pull?遠程分支名
復制代碼其實pull的本質就是fetch+merge,首先更新遠程倉庫所有狀態到本地,隨后再進行合并。合并完成后本地分支會指向最新節點
另外pull命令也可以通過進行合并,具體命令如下:
git?pull?--rebase?遠程分支名
復制代碼push
push命令可以將本地提交推送至遠程git命令行拉取代碼,具體命令如下:
git?push?遠程分支名
復制代碼如果直接push可能會失敗,因為可能存在沖突,所以在push之前往往會先pull一下,如果存在沖突本地解決。push成功后本地的遠程分支引用會更新,與本地分支指向同一節點
6綜上所述來源:/post/
【我們談論數據科學】知識星球正在進行新的系列課程:【實用主義Git課程】費老師將從0到1,配合文字+視頻+案例+作業,帶大家入門并掌握Git。課程主要包含如下內容:1、學習掌握Git這個流行且強大的版本控制軟件的常用方法2、學會如何配合、Gitee等平臺方便地管理自己的遠程倉庫3、學習流行的Git圖形化軟件的用法,中git插件的用法4、學習日常如何加速訪問使用、自建Git服務器等實用技能
為此,我們公眾號申請了一些優惠券,可以掃碼進入一起學習Git。