1. Git 各指令的本質(zhì),最全總結(jié)

        共 6456字,需瀏覽 13分鐘

         ·

        2022-12-31 06:35


        最近我們在知識星球開設(shè)了《實(shí)用主義Git教程》打卡課程,幫助大家成0到1認(rèn)識、使用Git。
        課程主要包含如下內(nèi)容:
        1、學(xué)習(xí)掌握Git這個流行且強(qiáng)大的版本控制軟件的常用方法
        2、學(xué)會如何配合Github、Gitee等平臺方便地管理自己的遠(yuǎn)程倉庫
        3、學(xué)習(xí)流行的Git圖形化軟件GitKarken的用法,vscode中g(shù)it插件的用法
        4、學(xué)習(xí)日常如何加速Github訪問使用、自建Git服務(wù)器等實(shí)用技能
        當(dāng)前課程已進(jìn)行到第5課,歡迎來一起學(xué)習(xí)。


        掃下面二維碼進(jìn)星球?qū)W習(xí)!



        以下正文。

        1前言

        作為當(dāng)前世界上最強(qiáng)大的代碼管理工具Git相信大家都很熟悉,但據(jù)我所知有很大一批人停留在clone、commit、pull、push...的階段,是不是對rebase心里沒底只敢用merge?碰見版本回退就抓瞎?別問我怎么知道的,問就是:“我曾經(jīng)就是這樣啊~~”。針對這些問題,今天我就將這幾年對Git的認(rèn)知和理解分享出來,盡可能的從本質(zhì)去講解Git,幫助你一步一步去了解Git的底層原理,相信讀完本篇文章你便可以換種姿態(tài),更加風(fēng)騷得使用Git各種指令。




        2目錄

        1. 基本概念
        • 1.1 Git的優(yōu)勢
        • 1.2 文件狀態(tài)
        • 1.3 commit 節(jié)點(diǎn)
        • 1.4 HEAD
        • 1.5 遠(yuǎn)程倉庫
        1. 分支
        • 2.1 什么是分支?
        1. 命令詳解
        • 3.1 提交相關(guān)
        • 3.2 分支相關(guān)
        • 3.3 合并相關(guān)
        • 3.4 回退相關(guān)
        • 3.5 遠(yuǎn)程相關(guān)

        31. 基本概念

        1.1 Git的優(yōu)勢

        Git是一個分布式代碼管理工具,在討論分布式之前避免不了提及一下什么是中央式代碼管理倉庫

        • 中央式:所有的代碼保存在中央服務(wù)器,所以提交必須依賴網(wǎng)絡(luò),并且每次提交都會帶入到中央倉庫,如果是協(xié)同開發(fā)可能頻繁觸發(fā)代碼合并,進(jìn)而增加提交的成本和代價(jià)。最典型的就是svn
        • 分布式:可以在本地提交,不需要依賴網(wǎng)絡(luò),并且會將每次提交自動備份到本地。每個開發(fā)者都可以把遠(yuǎn)程倉庫clone一份到本地,并會把提交歷史一并拿過來。代表就是Git

        Git相比于svn有什么優(yōu)勢呢?打個比方:"巴拉巴拉寫了一大堆代碼,突然發(fā)現(xiàn)寫的有問題,我想回到一個小時之前",對于這種情況Git的優(yōu)勢就很明顯了,因?yàn)閏ommit的成本比較小并且本地會保存所有的提交記錄,隨時隨刻可以進(jìn)行回退。在這并不是說svn的不能完成這種操作,只是Git的回退會顯得更加的優(yōu)雅。Git相比于中央式工具還有很多優(yōu)點(diǎn),就不一一列舉了,感興趣的可自行了解。

        1.2 文件狀態(tài)

        在Git中文件大概分為三種狀態(tài):已修改(modified)、已暫存(staged)、已提交(committed)

        • 修改:Git可以感知到工作目錄中哪些文件被修改了,然后把修改的文件加入到modified區(qū)域
        • 暫存:通過add命令將工作目錄中修改的文件提交到暫存區(qū),等候被commit
        • 提交:將暫存區(qū)文件commit至Git目錄中永久保存

        1.3 commit節(jié)點(diǎn)

        為了便于表述,本篇文章我會通過節(jié)點(diǎn)代稱commit提交

        在Git中每次提交都會生成一個節(jié)點(diǎn),而每個節(jié)點(diǎn)都會有一個哈希值作為唯一標(biāo)示,多次提交會形成一個線性節(jié)點(diǎn)鏈(不考慮merge的情況),如圖1-1

        節(jié)點(diǎn)上方是通過 SHA1計(jì)算的哈希值

        C2節(jié)點(diǎn)包含C1提交內(nèi)容,同樣C3節(jié)點(diǎn)包含C1、C2提交內(nèi)容

        1.4 HEAD

        HEAD是Git中非常重要的一個概念,你可以稱它為指針或者引用,它可以指向任意一個節(jié)點(diǎn),并且指向的節(jié)點(diǎn)始終為當(dāng)前工作目錄,換句話說就是當(dāng)前工作目錄(也就是你所看到的代碼)就是HEAD指向的節(jié)點(diǎn)。

        還以圖1-1舉例,如果HEAD指向C2那工作目錄對應(yīng)的就是C2節(jié)點(diǎn)。具體如何移動HEAD指向后面會講到,此處不要糾結(jié)。

        同時HEAD也可以指向一個分支,間接指向分支所指向的節(jié)點(diǎn)

        1.5 遠(yuǎn)程倉庫

        雖然Git會把代碼以及歷史保存在本地,但最終還是要提交到服務(wù)器上的遠(yuǎn)程倉庫。通過clone命令可以把遠(yuǎn)程倉庫的代碼下載到本地,同時也會將提交歷史分支、HEAD等狀態(tài)一并同步到本地,但這些狀態(tài)并不會實(shí)時更新,需要手動從遠(yuǎn)程倉庫去拉取,至于何時拉、怎么拉后面章節(jié)會講到。

        通過遠(yuǎn)程倉庫為中介,你可以和你的同事進(jìn)行協(xié)同開發(fā),開發(fā)完新功能后可以申請?zhí)峤恢吝h(yuǎn)程倉庫,同時也可以從遠(yuǎn)程倉庫拉取你同事的代碼。

        注意點(diǎn)

        因?yàn)槟愫湍愕耐露紩赃h(yuǎn)程倉庫的代碼為基準(zhǔn),所以要時刻保證遠(yuǎn)程倉庫的代碼質(zhì)量,切記不要將未經(jīng)檢驗(yàn)測試的代碼提交至遠(yuǎn)程倉庫

        42. 分支

        2.1 什么是分支?

        分支也是Git中相當(dāng)重要的一個概念,當(dāng)一個分支指向一個節(jié)點(diǎn)時,當(dāng)前節(jié)點(diǎn)的內(nèi)容即是該分支的內(nèi)容,它的概念和HEAD非常接近同樣也可以視為指針引用,不同的是分支可以存在多個,而HEAD只有一個。通常會根據(jù)功能版本建立不同的分支

        那分支有什么用呢?

        • 舉個例子:你們的 App 經(jīng)歷了千辛萬苦終于發(fā)布了v1.0版本,由于需求緊急v1.0上線之后便馬不停蹄的開始v1.1,正當(dāng)你開發(fā)的興起時,QA同學(xué)說用戶反饋了一些bug,需要修復(fù)然后重新發(fā)版,修復(fù)v1.0肯定要基于v1.0的代碼,可是你已經(jīng)開發(fā)了一部分v1.1了,此時怎么搞?

        面對上面的問題通過引入分支概念便可優(yōu)雅的解決,如圖2-1

        • 先看左邊示意圖,假設(shè)C2節(jié)點(diǎn)既是v1.0版本代碼,上線后在C2的基礎(chǔ)上新建一個分支ft-1.0
        • 再看右邊示意圖,在v1.0上線后可在master分支開發(fā)v1.1內(nèi)容,收到QA同學(xué)反饋后提交v1.1代碼生成節(jié)點(diǎn)C3,隨后切換到ft-1.0分支做bug修復(fù),修復(fù)完成后提交代碼生成節(jié)點(diǎn)C4,然后再切換到master分支并合并ft-1.0分支,到此我們就解決了上面提出的問題

        除此之外利用分支還可以做很多事情,比如現(xiàn)在有一個需求不確定要不要上線,但是得先做,此時可以單獨(dú)創(chuàng)建一個分支開發(fā)該功能,等到啥時候需要上線直接合并到主分支即可。分支適用的場景很多就不一一列舉了。

        注意點(diǎn)

        當(dāng)在某個節(jié)點(diǎn)創(chuàng)建一個分支后,并不會把該節(jié)點(diǎn)對應(yīng)的代碼復(fù)制一份出來,只是將新分支指向該節(jié)點(diǎn),因此可以很大程度減少空間上的開銷。一定要記著不管是HEAD還是分支它們都只是引用而已,量級非常輕

        53. 命令詳解

        3.1 提交相關(guān)

        前面我們提到過,想要對代碼進(jìn)行提交必須得先加入到暫存區(qū),Git中是通過命令 add 實(shí)現(xiàn)

        添加某個文件到暫存區(qū):

        git add 文件路徑
        復(fù)制代碼

        添加所有文件到暫存區(qū):

        git add .
        復(fù)制代碼

        同時Git也提供了撤銷工作區(qū)暫存區(qū)命令

        撤銷工作區(qū)改動:

        git checkout -- 文件名
        復(fù)制代碼

        清空暫存區(qū):

        git reset HEAD 文件名
        復(fù)制代碼

        提交:

        將改動文件加入到暫存區(qū)后就可以進(jìn)行提交了,提交后會生成一個新的提交節(jié)點(diǎn),具體命令如下:

        git commit -m "該節(jié)點(diǎn)的描述信息"
        復(fù)制代碼

        3.2 分支相關(guān)

        創(chuàng)建分支

        創(chuàng)建一個分支后該分支會與HEAD指向同一節(jié)點(diǎn),說通俗點(diǎn)就是HEAD指向哪創(chuàng)建的新分支就指向哪,命令如下:

        git branch 分支名
        復(fù)制代碼

        切換分支

        當(dāng)切換分支后,默認(rèn)情況下HEAD會指向當(dāng)前分支,即HEAD間接指向當(dāng)前分支指向的節(jié)點(diǎn)

        git checkout 分支名
        復(fù)制代碼

        同時也可以創(chuàng)建一個分支后立即切換,命令如下:

        git checkout -b 分支名
        復(fù)制代碼

        刪除分支

        為了保證倉庫分支的簡潔,當(dāng)某個分支完成了它的使命后應(yīng)該被刪除。比如前面所說的單獨(dú)開一個分支完成某個功能,當(dāng)這個功能被合并到主分支后應(yīng)該將這個分支及時刪除。

        刪除命令如下:

        git branch -d 分支名
        復(fù)制代碼

        3.3 合并相關(guān)

        關(guān)于合并的命令是最難掌握同時也是最重要的。我們常用的合并命令大概有三個merge、rebase、cherry-pick

        merge

        merge是最常用的合并命令,它可以將某個分支或者某個節(jié)點(diǎn)的代碼合并至當(dāng)前分支。具體命令如下:

        git merge 分支名/節(jié)點(diǎn)哈希值
        復(fù)制代碼

        如果需要合并的分支完全領(lǐng)先于當(dāng)前分支,如圖3-1所示

        由于分支ft-1完全領(lǐng)先分支ft-2ft-1完全包含ft-2,所以ft-2執(zhí)行了“git merge ft-1”后會觸發(fā)fast forward(快速合并),此時兩個分支指向同一節(jié)點(diǎn),這是最理想的狀態(tài)。但是實(shí)際開發(fā)中我們往往碰到是是下面這種情況:如圖3-2(左)

        這種情況就不能直接合了,當(dāng)ft-2執(zhí)行了“git merge ft-1”后Git會將節(jié)點(diǎn)C3、C4合并隨后生成一個新節(jié)點(diǎn)C5,最后將ft-2指向C5 如圖3-2(右)

        注意點(diǎn):

        如果C3C4同時修改了同一個文件中的同一句代碼,這個時候合并會出錯,因?yàn)镚it不知道該以哪個節(jié)點(diǎn)為標(biāo)準(zhǔn),所以這個時候需要我們自己手動合并代碼

        rebase

        rebase也是一種合并指令,命令行如下:

        git rebase 分支名/節(jié)點(diǎn)哈希值
        復(fù)制代碼

        merge不同的是rebase合并看起來不會產(chǎn)生新的節(jié)點(diǎn)(實(shí)際上是會產(chǎn)生的,只是做了一次復(fù)制),而是將需要合并的節(jié)點(diǎn)直接累加 如圖3-3

        當(dāng)左邊示意圖的ft-1.0執(zhí)行了git rebase master后會將C4節(jié)點(diǎn)復(fù)制一份到C3后面,也就是C4',C4C4'相對應(yīng),但是哈希值卻不一樣。

        rebase相比于merge提交歷史更加線性、干凈,使并行的開發(fā)流程看起來像串行,更符合我們的直覺。既然rebase這么好用是不是可以拋棄merge了?其實(shí)也不是了,下面我羅列一些mergerebase的優(yōu)缺點(diǎn):

        merge優(yōu)缺點(diǎn):

        • 優(yōu)點(diǎn):每個節(jié)點(diǎn)都是嚴(yán)格按照時間排列。當(dāng)合并發(fā)生沖突時,只需要解決兩個分支所指向的節(jié)點(diǎn)的沖突即可
        • 缺點(diǎn):合并兩個分支時大概率會生成新的節(jié)點(diǎn)并分叉,久而久之提交歷史會變成一團(tuán)亂麻

        rebase優(yōu)缺點(diǎn):

        • 優(yōu)點(diǎn):會使提交歷史看起來更加線性、干凈
        • 缺點(diǎn):雖然提交看起來像是線性的,但并不是真正的按時間排序,比如圖3-3中,不管C4早于或者晚于C3提交它最終都會放在C3后面。并且當(dāng)合并發(fā)生沖突時,理論上來講有幾個節(jié)點(diǎn)rebase到目標(biāo)分支就可能處理幾次沖突

        對于網(wǎng)絡(luò)上一些只用rebase的觀點(diǎn),作者表示不太認(rèn)同,如果不同分支的合并使用rebase可能需要重復(fù)解決沖突,這樣就得不償失了。但如果是本地推到遠(yuǎn)程并對應(yīng)的是同一條分支可以優(yōu)先考慮rebase。所以我的觀點(diǎn)是 根據(jù)不同場景合理搭配使用mergerebase,如果覺得都行那優(yōu)先使用rebase

        cherry-pick

        cherry-pick的合并不同于mergerebase,它可以選擇某幾個節(jié)點(diǎn)進(jìn)行合并,如圖3-4

        命令行:

        git cherry-pick 節(jié)點(diǎn)哈希值
        復(fù)制代碼

        假設(shè)當(dāng)前分支是master,執(zhí)行了git cherry-pick C3(哈希值),C4(哈希值)命令后會直接將C3C4節(jié)點(diǎn)抓過來放在后面,對應(yīng)C3'C4'

        3.4 回退相關(guān)

        分離HEAD

        在默認(rèn)情況下HEAD是指向分支的,但也可以將HEAD從分支上取下來直接指向某個節(jié)點(diǎn),此過程就是分離HEAD,具體命令如下:

        git checkout 節(jié)點(diǎn)哈希值
        //也可以直接脫離分支指向當(dāng)前節(jié)點(diǎn)
        git checkout --detach
        復(fù)制代碼

        由于哈希值是一串很長很長的亂碼,在實(shí)際操作中使用哈希值分離HEAD很麻煩,所以Git也提供了HEAD基于某一特殊位置(分支/HEAD)直接指向前一個前N個節(jié)點(diǎn)的命令,也即相對引用,如下:

        //HEAD分離并指向前一個節(jié)點(diǎn)
        git checkout 分支名/HEAD^
        復(fù)制代碼
        //HEAD分離并指向前N個節(jié)點(diǎn)
        git checkout 分支名~N
        復(fù)制代碼

        HEAD分離出來指向節(jié)點(diǎn)有什么用呢?舉個例子:如果開發(fā)過程發(fā)現(xiàn)之前的提交有問題,此時可以將HEAD指向?qū)?yīng)的節(jié)點(diǎn),修改完畢后再提交,此時你肯定不希望再生成一個新的節(jié)點(diǎn),而你只需在提交時加上--amend即可,具體命令如下:

        git commit --amend
        復(fù)制代碼

        回退

        回退場景在平時開發(fā)中還是比較常見的,比如你巴拉巴拉寫了一大堆代碼然后提交,后面發(fā)現(xiàn)寫的有問題,于是你想將代碼回到前一個提交,這種場景可以通過reset解決,具體命令如下:

        //回退N個提交
        git reset HEAD~N
        復(fù)制代碼

        reset相對引用很像,區(qū)別是reset會使分支HEAD一并回退。

        3.5 遠(yuǎn)程相關(guān)

        當(dāng)我們接觸一個新項(xiàng)目時,第一件事情肯定是要把它的代碼拿下來,在Git中可以通過clone從遠(yuǎn)程倉庫復(fù)制一份代碼到本地,具體命令如下:

        git clone 倉庫地址
        復(fù)制代碼

        前面的章節(jié)我也有提到過,clone不僅僅是復(fù)制代碼,它還會把遠(yuǎn)程倉庫的引用(分支/HEAD)一并取下保存在本地,如圖3-5所示:

        其中origin/masterorigin/ft-1為遠(yuǎn)程倉庫的分支,而遠(yuǎn)程的這些引用狀態(tài)是不會實(shí)時更新到本地的,比如遠(yuǎn)程倉庫origin/master分支增加了一次提交,此時本地是感知不到的,所以本地的origin/master分支依舊指向C4節(jié)點(diǎn)。我們可以通過fetch命令來手動更新遠(yuǎn)程倉庫狀態(tài)

        小提示:

        并不是存在服務(wù)器上的才能稱作是遠(yuǎn)程倉庫,你也可以clone本地倉庫作為遠(yuǎn)程,當(dāng)然實(shí)際開發(fā)中我們不可能把本地倉庫當(dāng)作公有倉庫,說這個只是單純的幫助你更清晰的理解分布式

        fetch

        說的通俗一點(diǎn),fetch命令就是一次下載操作,它會將遠(yuǎn)程新增加的節(jié)點(diǎn)以及引用(分支/HEAD)的狀態(tài)下載到本地,具體命令如下:

        git fetch 遠(yuǎn)程倉庫地址/分支名
        復(fù)制代碼

        pull

        pull命令可以從遠(yuǎn)程倉庫的某個引用拉取代碼,具體命令如下:

        git pull 遠(yuǎn)程分支名
        復(fù)制代碼

        其實(shí)pull的本質(zhì)就是fetch+merge,首先更新遠(yuǎn)程倉庫所有狀態(tài)到本地,隨后再進(jìn)行合并。合并完成后本地分支會指向最新節(jié)點(diǎn)

        另外pull命令也可以通過rebase進(jìn)行合并,具體命令如下:

        git pull --rebase 遠(yuǎn)程分支名
        復(fù)制代碼

        push

        push命令可以將本地提交推送至遠(yuǎn)程,具體命令如下:

        git push 遠(yuǎn)程分支名
        復(fù)制代碼

        如果直接push可能會失敗,因?yàn)榭赡艽嬖跊_突,所以在push之前往往會先pull一下,如果存在沖突本地解決。push成功后本地的遠(yuǎn)程分支引用會更新,與本地分支指向同一節(jié)點(diǎn)

        6綜上所述

        • 不管是HEAD還是分支,它們都只是引用而已,引用+節(jié)點(diǎn)是 Git 構(gòu)成分布式的關(guān)鍵
        • merge相比于rebase有更明確的時間歷史,而rebase會使提交更加線性應(yīng)當(dāng)優(yōu)先使用
        • 通過移動HEAD可以查看每個提交對應(yīng)的代碼
        • clonefetch都會將遠(yuǎn)程倉庫的所有提交、引用保存在本地一份
        • pull的本質(zhì)其實(shí)就是fetch+merge,也可以加入--rebase通過rebase方式合并
        來源:juejin.cn/post/6895246702614806542



        【我們談?wù)摂?shù)據(jù)科學(xué)】知識星球正在進(jìn)行新的系列課程:
        【實(shí)用主義Git課程】
        費(fèi)老師將從0到1,配合文字+視頻+案例+作業(yè),帶大家入門并掌握Git。
        課程主要包含如下內(nèi)容:
        1、學(xué)習(xí)掌握Git這個流行且強(qiáng)大的版本控制軟件的常用方法
        2、學(xué)會如何配合Github、Gitee等平臺方便地管理自己的遠(yuǎn)程倉庫
        3、學(xué)習(xí)流行的Git圖形化軟件GitKarken的用法,vscode中g(shù)it插件的用法
        4、學(xué)習(xí)日常如何加速Github訪問使用、自建Git服務(wù)器等實(shí)用技能

        為此,我們公眾號申請了一些優(yōu)惠券,可以掃碼進(jìn)入一起學(xué)習(xí)Git。

        瀏覽 113
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 末世淫辱校花h系列小说 | 鸡巴搞逼| 亚洲电影在线观看 | 国产精品无码久久 | 日逼91 |