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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Git版本管理原理

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

目錄

?

Git工作區(qū)域

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

Git簡介

版本管理

本地執(zhí)行

文件狀態(tài)

git內(nèi)部原理

Git對象

目錄樹

提交

引用

tag

HEAD

分支

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

版本演變

分支

創(chuàng)建分支

切換分支

遠(yuǎn)程分支

跟蹤分支

合并(merge)

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

合并沖突

變基(rebase)

變基沖突

交互式變基(interactive)

變基 vs. 合并

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

儲藏(stash)

參考


Git工作區(qū)域

1、工作目錄(Working Directory)

存放項目代碼的地方

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

用于臨時存放改動,事實上它只是一個文件,保存即將提交到文件列表信息

3、資源庫(Repository或Git Directory)

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

4、遠(yuǎn)程的git倉庫(Remote Directory)

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

?

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

Git簡介

版本管理

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

delta-based方式:

快照流方式:

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

本地執(zhí)行

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

文件狀態(tài)

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

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

git內(nèi)部原理

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

Git對象

對象庫是git版本庫實現(xiàn)的心臟,包含四種類型:

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

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

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

目錄樹

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

提交

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

從提交流角度來看,提交對象會包含一個指向上次提交對象(父對象)的指針。

引用

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

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

tag

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

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

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

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

分支

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

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

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

版本演變

分支

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

創(chuàng)建分支

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

切換分支

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

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

遠(yuǎn)程分支

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

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

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

跟蹤分支

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

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

跟蹤分支信息一般保存在local級別的配置文件當(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)分叉提交的分支整合在一起時,可以使用合并(merge)操作來完成。

Git 會使用兩個分支的末端所指的快照以及這兩個分支的工作祖先,做一個簡單的三方合并。

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

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

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

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

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

合并沖突

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

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

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

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

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

變基(rebase)

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

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

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

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

不要對在你的倉庫外有副本的分支執(zhí)行變基。

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

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

變基沖突

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

我們在基底分支和補(bǔ)丁分支修改了同一個文件時就要手動進(jìn)行沖突處理。

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

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

交互式變基(interactive)

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

我們通常會在完成一個功能時,合并雜亂的提交從而使提交樹更加簡潔。

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

變基 vs. 合并

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

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

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

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

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

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

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

儲藏(stash)

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

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

?

?

參考

Git 分支 - 變基

總結(jié)

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

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