日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Git版本管理原理

發(fā)布時(shí)間:2024/4/13 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Git版本管理原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

?

Git工作區(qū)域

工作區(qū)間的關(guān)系

Git簡(jiǎn)介

版本管理

本地執(zhí)行

文件狀態(tài)

git內(nèi)部原理

Git對(duì)象

目錄樹(shù)

提交

引用

tag

HEAD

分支

.git 結(jié)構(gòu)說(shuō)明

版本演變

分支

創(chuàng)建分支

切換分支

遠(yuǎn)程分支

跟蹤分支

合并(merge)

快進(jìn)合并(fast-forward)

合并沖突

變基(rebase)

變基沖突

交互式變基(interactive)

變基 vs. 合并

應(yīng)用提交(cherry-pick)

儲(chǔ)藏(stash)

參考


Git工作區(qū)域

1、工作目錄(Working Directory)

存放項(xiàng)目代碼的地方

2、暫存區(qū)(Stage/Index)

用于臨時(shí)存放改動(dòng),事實(shí)上它只是一個(gè)文件,保存即將提交到文件列表信息

3、資源庫(kù)(Repository或Git Directory)

倉(cāng)庫(kù)區(qū)(或本地倉(cāng)庫(kù)),就是安全存放數(shù)據(jù)的位置,這里面有提交的所有版本的數(shù)據(jù)。其中HEAD指向最新放入倉(cāng)庫(kù)的版本

4、遠(yuǎn)程的git倉(cāng)庫(kù)(Remote Directory)

遠(yuǎn)程倉(cāng)庫(kù),托管代碼的服務(wù)器。

?

工作區(qū)間的關(guān)系

Git簡(jiǎn)介

版本管理

Git與其他版本管理工具最重要的不同點(diǎn)是:其他工具記錄下文件的變化情況(delta-based),而git是基于快照(snapshots),每次變更都會(huì)是存儲(chǔ)文件的快照。

delta-based方式:

快照流方式:

只有被修改過(guò)的文件才會(huì)在對(duì)應(yīng)版本產(chǎn)生出新的快照。所以每次提交所產(chǎn)生的快照不是整個(gè)文件系統(tǒng),而是被修改過(guò)的那部分文件。(上圖虛線(xiàn)圈出的文件表示沒(méi)有生成新的快照)

本地執(zhí)行

Git在每個(gè)用戶(hù)機(jī)器上都有一份完整的版本庫(kù),所以在集中式版本控制系統(tǒng)通常所做的提交代碼、比較代碼、分支合并等工作在本地就可以完成,而且速度極快。但是不同開(kāi)發(fā)者之間的代碼協(xié)作,還是需要通過(guò)網(wǎng)絡(luò)連接遠(yuǎn)程倉(cāng)庫(kù)進(jìn)行交換的。

文件狀態(tài)

Git管理的文件存在三個(gè)狀態(tài):

  • 已修改(modified):已修改表示修改了文件,但還沒(méi)保存到數(shù)據(jù)庫(kù)中
  • 已暫存(staged):? 已暫存表示對(duì)一個(gè)已修改文件的當(dāng)前版本做了標(biāo)記,使之包含在下次提交的快照中
  • 已提交(committed):已提交表示數(shù)據(jù)已經(jīng)安全的保存在本地?cái)?shù)據(jù)庫(kù)中

git內(nèi)部原理

在git版本庫(kù)中,git維護(hù)兩個(gè)主要數(shù)據(jù)結(jié)構(gòu):對(duì)象庫(kù)(object store),索引(index)。

Git對(duì)象

對(duì)象庫(kù)是git版本庫(kù)實(shí)現(xiàn)的心臟,包含四種類(lèi)型:

  • 塊(blob,binary lare object)
  • 目錄樹(shù)(tree)
  • 提交(commit)

為了有效的利用磁盤(pán)空間和網(wǎng)絡(luò)帶寬名,git把對(duì)象壓縮并存儲(chǔ)在打包文件(pack file)里,這些文件也在對(duì)象庫(kù)里。

文件的每一個(gè)版本表示為一個(gè)塊。一個(gè)blob被視為一個(gè)存儲(chǔ)任意數(shù)據(jù),且內(nèi)部結(jié)構(gòu)被程序忽略的變量或文件的黑盒。一個(gè)blob保存一個(gè)文件的數(shù)據(jù),但不包含任何關(guān)于這個(gè)文件的元數(shù)據(jù)(Metadata,描述數(shù)據(jù)的數(shù)據(jù))。

目錄樹(shù)

一個(gè)目錄樹(shù)對(duì)象代表一層目錄信息。它記錄blob標(biāo)識(shí)符、路徑名和在一個(gè)目錄里所有文件的元數(shù)據(jù)。它也可以遞歸引用其他目錄樹(shù)或子樹(shù)對(duì)象,從而建立一個(gè)包含文件和子目錄的完整層次結(jié)構(gòu)。

提交

一個(gè)提交對(duì)象保存版本庫(kù)中每一次變化的元數(shù)據(jù),每一個(gè)提交對(duì)象指向一個(gè)目錄樹(shù)對(duì)象,這個(gè)樹(shù)對(duì)象在一張完整的快照中捕獲提交時(shí)版本庫(kù)的狀態(tài)。

從提交流角度來(lái)看,提交對(duì)象會(huì)包含一個(gè)指向上次提交對(duì)象(父對(duì)象)的指針。

引用

引用指的是對(duì)提交記錄的引用,提交記錄用哈希值(SHA-1唯一標(biāo)識(shí),每個(gè)引用用一個(gè)文件表示,文件中保存其引用的提交記錄的哈希值,文件名為引用的名稱(chēng)。本地分支名稱(chēng)、遠(yuǎn)程跟蹤分支名稱(chēng)和標(biāo)簽名都是引用。

heads目錄下有個(gè)名為master的文件,內(nèi)容為:1defc8eb6a0fb360438c9672cb31bbc2e46d621e

tag

Git 使用兩種主要類(lèi)型的標(biāo)簽:輕量標(biāo)簽(lightweight)與附注標(biāo)簽(annotated)

一個(gè)輕量標(biāo)簽很像一個(gè)不會(huì)改變的分支 - 它只是一個(gè)特定提交的引用

附注標(biāo)簽是存儲(chǔ)在 Git 數(shù)據(jù)庫(kù)中的一個(gè)完整對(duì)象。 它們是可以被校驗(yàn)的;其中包含打標(biāo)簽者的名字、電子郵件地址、日期時(shí)間;還有一個(gè)標(biāo)簽信息;并且可以使用 GNU Privacy Guard (GPG)簽名與驗(yàn)證

  • 對(duì)應(yīng).git/refs/tags/目錄中的文件
  • 不可變, 除非刪除后重新創(chuàng)建, 否則總是指向特定的提交記錄
  • 每個(gè)git倉(cāng)庫(kù)可以有多個(gè)tag
  • 對(duì)應(yīng).git/HEAD 。里面存儲(chǔ)的內(nèi)容:? ref: refs/heads/master
  • 可變
    • 通常指向某個(gè)本地分支,即引用的引用
    • 也可以直接指向某個(gè)提交記錄,稱(chēng)為HEAD detached, 即分離頭指針狀態(tài)
    • 也可以指向tag,git將這種情況也處理成HEAD detached
    • 也可以指向遠(yuǎn)端分支, git將這種情況也處理成HEAD detached
  • 每個(gè)git倉(cāng)庫(kù)只有一個(gè)HEAD
  • 表示當(dāng)前工作區(qū)檢出的文件(或者說(shuō)文件在修改之前)是屬于哪個(gè)提交記錄的
  • git checkout 指令,就是在改變HEAD的指向
    • git checkout 本地分支名
    • git checkout 提交記錄哈希值, detached
    • git checkout 遠(yuǎn)端分支名, detached
    • git checkout tag名, detached

分支

  • 可變, 在不同的時(shí)刻可以指向不同的提交記錄
  • 本地分支
    • 對(duì)應(yīng).git/refs/heads/<branchname>
    • 每個(gè)本地倉(cāng)庫(kù)有多個(gè)本地分支
  • 遠(yuǎn)程分支
    • 對(duì)應(yīng).git/refs/remotes/<遠(yuǎn)端倉(cāng)庫(kù)名>/<branchname>
    • 每個(gè)本地倉(cāng)庫(kù)可以對(duì)應(yīng)多個(gè)遠(yuǎn)端倉(cāng)庫(kù), 同時(shí)每個(gè)遠(yuǎn)端倉(cāng)庫(kù)可以有多個(gè)遠(yuǎn)端分支

.git 結(jié)構(gòu)說(shuō)明

  • HEAD 指示目前被檢出的分支
  • index 保存暫存區(qū)信息
  • config* 包含項(xiàng)目特有的配置選項(xiàng)
  • description 僅供gitweb程序使用,用戶(hù)一般不需要關(guān)注。
  • hooks 包含客戶(hù)端和服務(wù)端的鉤子
  • info 包含全局排除(global excude)文件,存放那些不希望被記錄在.gitignore中的忽略模式
  • objects 存儲(chǔ)所有數(shù)據(jù)內(nèi)容
  • refs 存儲(chǔ)指向數(shù)據(jù)(分支)的提交對(duì)象的指針

版本演變

分支

Git僅有一個(gè)提交樹(shù)。而Git 的分支其實(shí)本質(zhì)上僅僅是指向提交對(duì)象的可變指針。 Git 的默認(rèn)分支名字是?master。 在多次提交操作之后,你其實(shí)已經(jīng)有一個(gè)指向最后那個(gè)提交對(duì)象的?master?分支。 它會(huì)在每次的提交操作中自動(dòng)向前移動(dòng)

創(chuàng)建分支

?創(chuàng)建分支只是創(chuàng)建了一個(gè)可以移動(dòng)的新的指針HEAD指向當(dāng)前分支。

切換分支

切換分支就是將HEAD指針指向另一個(gè)本地分支。

從一次提交創(chuàng)建不同分支,之后又分別在這些分支上做出了新的提交。這時(shí)項(xiàng)目將會(huì)產(chǎn)生分叉提交歷史,多個(gè)提交將指向同一個(gè)父提交。這些分叉如果想要最終合并回原來(lái)的分支,就要通過(guò)合并或變基操作來(lái)解決。

遠(yuǎn)程分支

遠(yuǎn)程引用是對(duì)遠(yuǎn)程倉(cāng)庫(kù)的引用(指針),包括分支、標(biāo)簽等等。

遠(yuǎn)程跟蹤分支是遠(yuǎn)程分支狀態(tài)的引用。 它們是你不能移動(dòng)的本地引用,當(dāng)你做任何網(wǎng)絡(luò)通信操作時(shí),它們會(huì)自動(dòng)移動(dòng)。 遠(yuǎn)程跟蹤分支像是你上次連接到遠(yuǎn)程倉(cāng)庫(kù)時(shí),那些分支所處狀態(tài)的書(shū)簽。

它們以 (remote)/(branch) 形式命名。 例如,如果你想要看你最后一次與遠(yuǎn)程倉(cāng)庫(kù) origin 通信時(shí) master
分支的狀態(tài),你可以查看 origin/master 分支。

跟蹤分支

從一個(gè)遠(yuǎn)程跟蹤分支檢出(check out)一個(gè)本地分支會(huì)自動(dòng)創(chuàng)建一個(gè)叫做 “跟蹤分支”(有時(shí)候也叫做 “上游分支”)。 跟蹤分支是與遠(yuǎn)程分支有直接關(guān)系的本地分支。 如果在一個(gè)跟蹤分支上輸入?git pull或git push,Git 能自動(dòng)地識(shí)別去哪個(gè)服務(wù)器上抓取、合并到哪個(gè)分支。

當(dāng)克隆一個(gè)倉(cāng)庫(kù)時(shí),它通常會(huì)自動(dòng)地創(chuàng)建一個(gè)跟蹤?origin/master?的?master?分支。 然而,如果你愿意的話(huà)可以設(shè)置其他的跟蹤分支 - 其他遠(yuǎn)程倉(cāng)庫(kù)上的跟蹤分支,或者不跟蹤?master?分支。

跟蹤分支信息一般保存在local級(jí)別的配置文件當(dāng)中

branch.master.remote=origin

branch.master.merge=refs/heads/master

branch.dev_5.2.remote=origin

branch.dev_5.2.merge=refs/heads/dev_5.2

合并(merge)

我們想將出現(xiàn)分叉提交的分支整合在一起時(shí),可以使用合并(merge)操作來(lái)完成。

Git 會(huì)使用兩個(gè)分支的末端所指的快照以及這兩個(gè)分支的工作祖先,做一個(gè)簡(jiǎn)單的三方合并。

和之前將分支指針向前推進(jìn)所不同的是,Git 將此次三方合并的結(jié)果做了一個(gè)新的快照并且自動(dòng)創(chuàng)建一個(gè)新的提交指向它。 這個(gè)被稱(chēng)作一次合并提交,它的特別之處在于他有不止一個(gè)父提交。

Git 會(huì)自行決定選取哪一個(gè)提交作為最優(yōu)的共同祖先,并以此作為合并的基礎(chǔ)。可以將合并理解為,從分叉提交中提取全部快照整合在一起,最后做一次新的提交。并且新提交擁有多個(gè)父提交。

快進(jìn)合并(fast-forward

當(dāng)試圖合并兩個(gè)分支時(shí),如果順著一個(gè)分支走下去能夠到達(dá)另一個(gè)分支,那么 Git 在合并兩者的時(shí)候,只會(huì)簡(jiǎn)單的將指針向前推進(jìn)(指針右移),因?yàn)檫@種情況下的合并操作沒(méi)有需要解決的分歧——這就叫做 “快進(jìn)(fast-forward)”。

master只要向前推進(jìn)就可以完成與iss53的合并,所以會(huì)使用快進(jìn)合并。

合并沖突

有時(shí)候合并操作不會(huì)如此順利。 如果在兩個(gè)不同的分支中,對(duì)同一個(gè)文件的同一個(gè)部分進(jìn)行了不同的修改,Git 就沒(méi)法干凈的合并它們。在合并它們的時(shí)候就會(huì)產(chǎn)生合并沖突。

此時(shí) Git 做了合并,但是沒(méi)有自動(dòng)地創(chuàng)建一個(gè)新的合并提交。 Git 會(huì)暫停下來(lái),等待你去解決合并產(chǎn)生的沖突。等你手動(dòng)解決之后,Git 會(huì)詢(xún)問(wèn)剛才的合并是否成功。 如果你回答是,Git 會(huì)暫存那些文件以表明沖突已解決。

如果你對(duì)結(jié)果感到滿(mǎn)意,并且確定之前有沖突的的文件都已經(jīng)暫存了,這時(shí)你可以輸入?git commit?來(lái)完成合并提交。 從而產(chǎn)生一次新的合并提交。

與無(wú)沖突合并的區(qū)別主要有:

  • 1、需要手動(dòng)解決沖突并標(biāo)記已解決。
  • 2、需要自己提交新的合并提交。

變基(rebase)

在 Git 中整合來(lái)自不同分支的修改主要有兩種方法:merge?以及?rebase

你可以提取在一個(gè)分支中引入的補(bǔ)丁和修改,然后在另一個(gè)分支的基礎(chǔ)上應(yīng)用一次。 在 Git 中,這種操作就叫做?變基。 你可以使用變基將提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一樣。

它的原理是首先找到這兩個(gè)分支(即當(dāng)前分支、變基操作的目標(biāo)基底分支)的最近共同祖先,然后對(duì)比當(dāng)前分支相對(duì)于該祖先的歷次提交,提取相應(yīng)的修改并存為臨時(shí)文件,然后將當(dāng)前分支指向目標(biāo)基底, 最后以此將之前另存為臨時(shí)文件的修改依序應(yīng)用。

變基也并非完美無(wú)缺,要用它得遵守一條準(zhǔn)則:

不要對(duì)在你的倉(cāng)庫(kù)外有副本的分支執(zhí)行變基。

如果你遵循這條金科玉律,就不會(huì)出差錯(cuò)。 否則,人民群眾會(huì)仇恨你,你的朋友和家人也會(huì)嘲笑你,唾棄你。

(也就是說(shuō)已經(jīng)推送到遠(yuǎn)程分支的內(nèi)容就不要進(jìn)行變基了,否則會(huì)對(duì)別人的造成困擾)

變基沖突

我們知道合并時(shí)有可能產(chǎn)生沖突,而變基時(shí)仍然有可能產(chǎn)生沖突問(wèn)題。

我們?cè)诨追种Ш脱a(bǔ)丁分支修改了同一個(gè)文件時(shí)就要手動(dòng)進(jìn)行沖突處理。

如果在變基時(shí)發(fā)現(xiàn)沖突,git會(huì)停止變基操作要求手動(dòng)解決沖突。

手動(dòng)解決沖突后,git會(huì)使用手動(dòng)解決沖突的文件重新建立補(bǔ)丁提交。

交互式變基(interactive)

交互式變基主要用于將多次提交合并成一次提交。

我們通常會(huì)在完成一個(gè)功能時(shí),合并雜亂的提交從而使提交樹(shù)更加簡(jiǎn)潔。

交互式變基允許我們自由的選擇提交,并且重新編輯提交說(shuō)明。

變基 vs. 合并

總的原則是,只對(duì)尚未推送或分享給別人的本地修改執(zhí)行變基操作清理歷史,從不對(duì)已推送至別處的提交執(zhí)行變基操作。

應(yīng)用提交(cherry-pick)

cherry-pick允許我們提取一個(gè)或多個(gè)現(xiàn)有的提交,并使用這些提交的快照來(lái)創(chuàng)建新的提交。

也就是說(shuō)我們能夠提取某一次提交的變更,應(yīng)用在其他分支當(dāng)中。

這個(gè)功能在處理生產(chǎn)bug時(shí)將會(huì)非常有用。如果我們?cè)陂_(kāi)發(fā)分支正在進(jìn)行開(kāi)發(fā)時(shí)出現(xiàn)了一個(gè)生產(chǎn)bug,就需要創(chuàng)建一個(gè)bug分支。但是bug分支即要合并到開(kāi)發(fā)分支進(jìn)行測(cè)試,又要合并到生產(chǎn)分支解決問(wèn)題,顯然使用分支合并方式無(wú)法完美的解決這個(gè)問(wèn)題。

上面這種情況使用cherry-pick正合適。在bug分支修改完之后,我們可以將修復(fù)bug的提交分別cherry-pick到生產(chǎn)和開(kāi)發(fā)分支。由于使用cherry-pick創(chuàng)建的提交標(biāo)識(shí)名都是一致的,在生產(chǎn)上線(xiàn)時(shí)執(zhí)行變基操作并不會(huì)產(chǎn)生沖突,會(huì)完美的合并成一次提交。

需要注意的是如果我們對(duì)cherry-pick的提交進(jìn)行了交互式變基,那么在合并的時(shí)候就無(wú)法確認(rèn)兩次提交的關(guān)系,會(huì)要求我們手動(dòng)合并。所以如果考慮到將來(lái)要將cherry-pick的兩個(gè)分支進(jìn)行合并的話(huà),最好還是不要在cherry-pick提交上進(jìn)行交互式變基操作。

儲(chǔ)藏(stash)

有時(shí),當(dāng)你在項(xiàng)目的一部分上已經(jīng)工作一段時(shí)間后,所有東西都進(jìn)入了混亂的狀態(tài),而這時(shí)你想要切換到另一個(gè)分支做一點(diǎn)別的事情。 問(wèn)題是,你不想僅僅因?yàn)檫^(guò)會(huì)兒回到這一點(diǎn)而為做了一半的工作創(chuàng)建一次提交。 針對(duì)這個(gè)問(wèn)題的答案是?git stash?命令。

儲(chǔ)藏會(huì)處理工作目錄的臟的狀態(tài) - 即,修改的跟蹤文件與暫存改動(dòng) - 然后將未完成的修改保存到一個(gè)棧上,而你可以在任何時(shí)候重新應(yīng)用這些改動(dòng)。

?

?

參考

Git 分支 - 變基

總結(jié)

以上是生活随笔為你收集整理的Git版本管理原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。