Git相關

最怕万一见温柔發表於2024-03-10
  • 宣告:本部落格內容完全來自於Git官網, 總結整理學習個人所需知識

  • 基礎

    • 本質

    • 從根本上來講 Git 是一個內容定址(content-addressable)檔案系統,並在此之上提供了一個版本控制系統的使用者介面。

    • Git 的核心部分是一個簡單的鍵值對資料庫(key-value data store)。 你可以向該資料庫插入任意型別的內容,它會返回一個鍵值,通過該鍵值可以在任意時刻再次檢索(retrieve)該內容。

    • Git 以一種類似於 UNIX 檔案系統的方式儲存內容,但作了些許簡化。 所有內容均以樹物件和資料物件的形式儲存,其中樹物件對應了 UNIX 中的目錄項,資料物件則大致上對應了 inodes 或檔案內容。 一個樹物件包含了一條或多條樹物件記錄(tree entry),每條記錄含有一個指向資料物件或者子樹物件的 SHA-1 指標,以及相應的模式、型別、檔名資訊。

    • 狀態

    • 工作目錄下的每一個檔案都不外乎這兩種狀態:已跟蹤或未跟蹤。 已跟蹤的檔案是指那些被納入了版本控制的檔案,在上一次快照中有它們的記錄,在工作一段時間後,它們的狀態可能處於未修改,已修改或已放入暫存區。 工作目錄中除已跟蹤檔案以外的所有其它檔案都屬於未跟蹤檔案,它們既不存在於上次快照的記錄中,也沒有放入暫存區。 初次克隆某個倉庫的時候,工作目錄中的所有檔案都屬於已跟蹤檔案,並處於未修改狀態。

    • 儲存修改

    • 編輯過某些檔案之後,由於自上次提交後你對它們做了修改,Git 將它們標記為已修改檔案。 我們逐步將這些修改過的檔案放入暫存區,然後提交所有暫存了的修改,如此反覆。

    • 請記住,提交時記錄的是放在暫存區域的快照。 任何還未暫存的仍然保持已修改狀態,可以在下次提交時納入版本管理。 每一次執行提交操作,都是對你專案作一次快照,以後可以回到這個狀態,或者進行比較 。

    • Git 儲存的不是檔案的變化或者差異,而是一系列不同時刻的檔案快照。在進行提交操作時,Git 會儲存一個提交物件(commit object)。該提交物件會包含一個指向暫存內容快照的指標。 但不僅僅是這樣,該提交物件還包含了作者的姓名和郵箱、提交時輸入的資訊以及指向它的父物件的指標。首次提交產生的提交物件沒有父物件,普通提交操作產生的提交物件有一個父物件,而由多個分支合併產生的提交物件有多個父物件

    • 暫存操作會為每一個檔案計算校驗和(使用 SHA-1 雜湊演算法),然後會把當前版本的檔案快照儲存到 Git 倉庫中(Git 使用 blob 物件來儲存它們),最終將校驗和加入到暫存區域等待提交。

    • 使用 git commit 進行提交操作時,Git 會先計算每一個子目錄(本例中只有專案根目錄)的校驗和,然後在 Git 倉庫中這些校驗和儲存為樹物件。 隨後,Git 便會建立一個提交物件,它除了包含上面提到的那些資訊外,還包含指向這個樹物件(專案根目錄)的指標。如此一來,Git 就可以在需要的時候重現此次儲存的快照。

    • 分支

    • Git 的分支,其實本質上僅僅是指向提交物件的可變指標。 Git 的預設分支名字是 master。 在多次提交操作之後,你其實已經有一個指向最後那個提交物件的 master 分支。 它會在每次的提交操作中自動向前移動。 注意:Git 的 “master” 分支並不是一個特殊分支。 它就跟其它分支完全沒有區別。 之所以幾乎每一個倉庫都有 master 分支,是因為 git init 命令預設建立它,並且大多數人都懶得去改動它。

    • 分支切換會改變你工作目錄中的檔案,在切換分支時,一定要注意你工作目錄裡的檔案會被改變。 如果是切換到一個較舊的分支,你的工作目錄會恢復到該分支最後一次提交時的樣子。 如果 Git 不能幹淨利落地完成這個任務,它將禁止切換分支。

    • Git 的分支實質上僅是包含所指物件校驗和(長度為 40 的 SHA-1 值字串)的檔案,所以它的建立和銷燬都異常高效。 建立一個新分支就相當於往一個檔案中寫入 41 個位元組(40 個字元和 1 個換行符)

    • 切換分支時,要留意你的工作目錄和暫存區裡那些還沒有被提交的修改,它可能會和你即將檢出的分支產生衝突從而阻止 Git 切換到該分支。 最好的方法是,在你切換分支之前,保持好一個乾淨的狀態。

    • 如果你在兩個不同的分支中,對同一個檔案的同一個部分進行了不同的修改,Git 就沒法乾淨的合併它們。 如果你對 #53 問題的修改和有關 hotfix 的修改都涉及到同一個檔案的同一處,在合併它們的時候就會產生合併衝突,遇到衝突時的分支合併時,合理修改衝突檔案

    • 遠端分支

    • 遠端引用是對遠端倉庫的引用(指標),包括分支、標籤等等。 你可以通過 git ls-remote (remote) 來顯式地獲得遠端引用的完整列表,或者通過 git remote show (remote) 獲得遠端分支的更多資訊。 然而,一個更常見的做法是利用遠端跟蹤分支。

    • 遠端跟蹤分支是遠端分支狀態的引用,它們以 (remote)/(branch) 形式命名。 例如,如果你想要看你最後一次與遠端倉庫 origin 通訊時 master 分支的狀態,你可以檢視 origin/master 分支。 你與同事合作解決一個問題並且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支;但是在伺服器上的分支會指向 origin/iss53 的提交。

    • 例子: 假設你的網路裡有一個在 git.ourcompany.com 的 Git 伺服器。 如果你從這裡克隆,Git 的 clone 命令會為你自動將其命名為 origin,拉取它的所有資料,建立一個指向它的 master 分支的指標,並且在本地將其命名為 origin/master。 Git 也會給你一個與 origin 的 master 分支在指向同一個地方的本地 master 分支,這樣你就有工作的基礎。

    • 推送

    • 當你想要公開分享一個分支時,需要將其推送到有寫入許可權的遠端倉庫上。 本地的分支並不會自動與遠端倉庫同步 - 你必須顯式地推送想要分享的分支。 這樣,你就可以把不願意分享的內容放到私人分支上,而將需要和別人協作的內容推送到公開分支。

    • 如果希望和別人一起在名為 serverfix 的分支上工作,你可以像推送第一個分支那樣推送它。 執行 git push (remote) (branch) : git push origin lyy(將lyy分支推送到origin所代表的遠端伺服器中)

    • 當推送時,會讓輸入賬號和密碼,如果不想每次都輸入賬號和密碼,設定”憑證儲存“:https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%87%AD%E8%AF%81%E5%AD%98%E5%82%A8#r_credential_caching

    • 跟蹤分支

    • 從一個遠端跟蹤分支檢出一個本地分支會自動建立一個叫做 “跟蹤分支”(有時候也叫做 “上游分支”)。 跟蹤分支是與遠端分支有直接關係的本地分支。 如果在一個跟蹤分支上輸入 git pull,Git 能自動地識別去哪個伺服器上抓取、合併到哪個分支。

    • 當首次克隆一個倉庫時,它通常會自動地建立一個跟蹤 origin/master 的 master 分支。

    • 拉取

    • 當 git fetch 命令從伺服器上抓取本地沒有的資料時,它並不會修改工作目錄中的內容。 它只會獲取資料然後讓你自己合併。 然而,有一個命令叫作 git pull 在大多數情況下它的含義是一個 git fetch 緊接著一個 git merge 命令。

    • 如果有一個像之前章節中演示的設定好的跟蹤分支,不管它是顯式地設定還是通過 clone 或 checkout 命令為你建立的,git pull 都會查詢當前分支所跟蹤的伺服器與分支,從伺服器上抓取資料然後嘗試合併入那個遠端分支。

    • 變基(vs 合併)

    • 變基可以使得提交歷史更加整潔。

    • 無論是通過變基,還是通過三方合併,整合的最終結果所指向的快照始終是一樣的,只不過提交歷史不同罷了。 變基是將一系列提交按照原有次序依次應用到另一分支上,可能會清楚一部分提交歷史,而合併是把最終結果合在一起,不會清除部分提交歷史。

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

    • 詳情:https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA

    • 總流程圖(其中:Workspace:工作區   Index / Stage:暫存區  Repository:倉庫區(或本地倉庫) Remote:遠端倉庫

  • 命令

    • git init :初始化專案(在專案目錄下才可)

    • git add file_name :  將file_name新增到git管理中 或者 把已跟蹤的檔案放到暫存區(執行了 git add 之後又作了修訂的檔案,需要重新執行 git add 把最新版本重新暫存起來)

    • git commit -m 'message' : 提交檔案到本地倉庫  備註資訊message     

      • git commit : 會啟動一個vim編輯器填寫提交說明資訊   

      • git commit -a -m "test" :不使用暫存區,將所有修改提交

      • git commit --amend : 會將暫存區中的檔案提交,如果自上次提交以來你還未做任何修改(例如,在上次提交後馬上執行了此命令),那麼快照會保持不變,所修改的只是提交資訊。

        • 例如,你提交後發現忘記了暫存某些需要的修改,可以像下面這樣操作:

        • $ git commit -m 'initial commit'

        • $ git add forgotten_file

        • $ git commit --amend

    • git clone https://gitee.com/dreamyy/zheng.git :克隆遠端倉庫裡面的專案

    • git status  :顯示檔案當前狀態   git status -s  : 緊湊形式輸出

    • echo  'My Project' >  README : 建立README檔案

    • vim .gitignore :建立.gitignore檔案    官網所給不同語言的規範:https://github.com/github/gitignore

      • 檔案 .gitignore 的格式規範如下:

      • * 所有空行或者以 # 開頭的行都會被 Git 忽略。

      • * 可以使用標準的 glob 模式匹配。

      • * 匹配模式可以以(/)開頭防止遞迴。

      • * 匹配模式可以以(/)結尾指定目錄。

      • * 要忽略指定模式以外的檔案或目錄,可以在模式前加上驚歎號(!)取反。

      • 所謂的 glob 模式是指 shell 所使用的簡化了的正規表示式。 星號(*)匹配零個或多個任意字元;[abc] 匹配任何一個列在方括號中的字元(這個例子要麼匹配一個 a,要麼匹配一個 b,要麼匹配一個 c);問號(?)只匹配一個任意字元;如果在方括號中使用短劃線分隔兩個字元,表示所有在這兩個字元範圍內的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的數字)。 使用兩個星號(*) 表示匹配任意中間目錄,比如`a/**/z` 可以匹配 a/z, a/b/z 或 `a/b/c/z`等。

    • git diff :檢視尚未暫存的檔案更新了哪些部分(注意,git diff 本身只顯示尚未暫存的改動,而不是自上次提交以來所做的所有改動)

    • git diff --staged :檢視已暫存的將要新增到下次提交裡的內容

    • git rm file_name : 刪除git跟蹤的檔案,注意,本地也會刪除!!  git rm --cached file_name : 使檔案脫離git追蹤,本地不刪除

      • 命令後面可以列出檔案或者目錄的名字,也可以使用 glob 模式

      • 注意到星號 * 之前的反斜槓 \, 因為 Git 有它自己的檔案模式擴充套件匹配方式,所以我們不用 shell 來幫忙展開。 此命令刪除 log/ 目錄下副檔名為 .log 的所有檔案。 類似的比如:

      • $ git rm \*~

      • 該命令為刪除以 ~ 結尾的所有檔案。

    • git log :檢視提交歷史 

      • 引數:一個常用的選項是 -p,用來顯示每次提交的內容差異。 你也可以加上 -2 來僅顯示最近兩次提交。

      • 每次提交的簡略的統計資訊,你可以使用 --stat 選項

      • --pretty 這個選項可以指定使用不同於預設格式的方式展示提交歷史。 

      • --oneline 將每個提交放在一行顯示,檢視的提交數很大時非常有用。 另外還有 short,full 和 fuller 可以用,展示的資訊或多或少有些不同

      • 詳情:https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%9F%A5%E7%9C%8B%E6%8F%90%E4%BA%A4%E5%8E%86%E5%8F%B2

    • git reset HEAD file_name : 取消暫存檔案,提交時不提交該檔案(在提交時不使用-a引數的情況下)

    • git checkout -- file_name :此命令非常危險,會撤銷你對該檔案的所有修改!

    • 遠端倉庫相關:

    • git  remote : 檢視遠端倉庫 -v引數:顯示需要讀寫遠端倉庫使用的 Git 儲存的簡寫與其對應的 URL。

      • git remote add <shortname> <url> :(git remote add lyy http:....)新增遠端倉庫   後,現在你可以在命令列中使用字串 <shortname>來代替整個 URL

    • git fetch remote_name ;  從遠端資料庫中拉取  例如:git fetch lyy;

      • 如果你使用 clone 命令克隆了一個倉庫,命令會自動將其新增為遠端倉庫並預設以 “origin” 為簡寫。 所以,git fetch origin 會抓取克隆(或上一次抓取)後新推送的所有工作。 必須注意 git fetch 命令會將資料拉取到你的本地倉庫 - 它並不會自動合併或修改你當前的工作。 當準備好時你必須手動將其合併入你的工作。

    • git push [remote-name] [branch-name] : 推送專案

      • $ git push origin master : 將 master 分支推送到 origin 伺服器時(再次說明,克隆時通常會自動幫你設定好那兩個名字),那麼執行這個命令就可以將你所做的備份到伺服器

      • 注意:只有當你有所克隆伺服器的寫入許可權,並且之前沒有人推送過時,這條命令才能生效。 當你和其他人在同一時間克隆,他們先推送到上游然後你再推送到上游,你的推送就會毫無疑問地被拒絕。 你必須先將他們的工作拉取下來並將其合併進你的工作後才能推送。

    • git tag :列出已有的標籤

      • git tag -a v1.4 -m 'my version 1.4' :(附註標籤)為最後一次提交打標籤,名字:v1.4  資訊: my version 1.4

      • git show v1.4 :顯示該標籤的所有資訊(包括commit資訊)

      • git tag v1.5  :(輕量標籤) 輕量標籤本質上是將提交校驗和儲存到一個檔案中 - 沒有儲存任何其他資訊。如果在標籤上執行 git show,你不會看到額外的標籤資訊。 命令只會顯示出提交資訊

      • git tag -a v1.2  9fceb02 :(後期打標籤 )假設在 v1.2 時你忘記給專案打標籤,也就是在 “updated rakefile” 提交。 你可以在之後補上標籤。 要在那個提交上打標籤,你需要在命令的末尾指定提交的校驗和(或部分校驗和)

      • git push origin [tagname] :git push 命令並不會傳送標籤到遠端倉庫伺服器上。 在建立完標籤後你必須顯式地推送標籤到共享伺服器上。 這個過程就像共享遠端分支一樣 - 你可以執行 git push origin [tagname]。

    • alias (別名)

      • 在建立你認為應該存在的命令時這個技術會很有用。 例如,為了解決取消暫存檔案的易用性問題,可以向 Git 中新增你自己的取消暫存別名:

        • $ git config --global alias.unstage 'reset HEAD --'

      • 這會使下面的兩個命令等價:

        • $ git unstage fileA

        • $ git reset HEAD -- fileA

    • 分支相關

    • git branch :獲得所有分支列表,前面帶”*“的為當前指向的分支

      • git branch -v :顯示每個分支的最後一次提交

      • --merged 與 --no-merged 這兩個有用的選項可以過濾這個列表中已經合併或尚未合併到當前分支的分支。

      • git branch lyy :建立一個分支,但不會自動切換到該分支

      • git checkout -b lyy2 :建立一個分支使用-b引數,並自動切換的到該分支

    • git log --oneline --decorate  :檢視各個分支當前所指的物件   

      • --online是一個提交資料顯示在一行的意思

      • -- decorate引數:是所用引數

      • 不使用decorate 引數,預設也顯示。。。

    • git checkout lyy : 切換到該分支

    • git checkout master  - 》 git merge hotfix  :兩個命令,第一個命令是切換到你想要合併到的哪個分支,第二個命令將hotfix分支合併到第一個命令所切換到的分支中。注意:並不是非要合併到master分支,合併到任何分支都可以。

    • git branch -d liyy2  :使用-d引數刪除lyy2分支。 注意:如果當前所處的分支為所刪除的分支,則不可以刪除,需切換到別的分支。

      • -D :使用該引數代替 -d引數,表示強制刪除該分支,即使該分支有未合併的修改。

    • 推送

    • git push (remote) (branch)  例如:git push origin lyy(將lyy分支推送到origin所代表的遠端伺服器中.

      • git push origin lyy:lyy2 來將本地的 lyy分支推送到遠端倉庫上的 lyy2分支。

    • 跟蹤分支

    • git checkout --track origin/serverfix :為origin/serverfix建立一個本地跟蹤分支serverfix , 現在,本地分支 serverfix會自動從 origin/serverfix 拉取。

      • git checkout -b lyymas lyy/master :使用-b引數,建立一個不同名字的跟蹤分支。

      • git branch -vv : 檢視設定的所有跟蹤分支

    • 拉取

    • git pull : 在伺服器上拉取對應分支的資料(根據本地所處分支所跟蹤的分支)。

      • git push origin --delete lyy : 在遠端伺服器origin上刪除lyy分支。 注意:Git 伺服器通常會保留資料一段時間直到垃圾回收執行,所以如果不小心刪除掉了,通常是很容易恢復的。

  • 其他

    • Git 作為一個系統,是以它的一般操作來管理並操縱(HEAD\index\Working Directory)三棵樹的

      • HEAD 

        • HEAD 是當前分支引用的指標,它總是指向該分支上的最後一次提交。 這表示 HEAD 將是下一次提交的父結點。 通常,理解 HEAD 的最簡方式,就是將它看做 你的上一次提交的快照。

      • index

        • 索引是你的 預期的下一次提交。 我們也會將這個概念引用為 Git 的 “暫存區域”,這就是當你執行 git commit 時 Git 看起來的樣子。

        • Git 將上一次檢出到工作目錄中的所有檔案填充到索引區,它們看起來就像最初被檢出時的樣子。 之後你會將其中一些檔案替換為新版本,接著通過 git commit 將它們轉換為樹來用作新的提交。

      • Working Directory

        • 最後,你就有了自己的工作目錄。 另外兩棵樹以一種高效但並不直觀的方式,將它們的內容儲存在 .git 資料夾中。 工作目錄會將它們解包為實際的檔案以便編輯。 你可以把工作目錄當做 沙盒。在你將修改提交到暫存區並記錄到歷史之前,可以隨意更改。

    • 打標籤

      • 像其他版本控制系統(VCS)一樣,Git 可以給歷史中的某一個提交打上標籤,以示重要。 比較有代表性的是人們會使用這個功能來標記釋出結點(v1.0 等等)。

      • Git 使用兩種主要型別的標籤:輕量標籤(lightweight)與附註標籤(annotated)。

      • 輕量標籤很像一個不會改變的分支 - 它只是一個特定提交的引用。

      • 附註標籤是儲存在 Git 資料庫中的一個完整物件。 它們是可以被校驗的;其中包含打標籤者的名字、電子郵件地址、日期時間;還有一個標籤資訊;並且可以使用 GNU Privacy Guard (GPG)簽名與驗證。 通常建議建立附註標籤,這樣你可以擁有以上所有資訊;但是如果你只是想用一個臨時的標籤,或者因為某些原因不想要儲存那些資訊,輕量標籤也是可用的。

    • git分支案例

    • 分支新建與合併的例子

      • 實際工作中你可能會用到類似的工作流。 你將經歷如下步驟:

        • 1. 開發某個網站。

        • 2. 為實現某個新的需求,建立一個分支。

        • 3. 在這個分支上開展工作。

      • 正在此時,你突然接到一個電話說有個很嚴重的問題需要緊急修補。 你將按照如下方式來處理:

        • 1. 切換到你的線上分支(production branch)。

        • 2. 為這個緊急任務新建一個分支,並在其中修復它。

        • 3. 在測試通過之後,切換回線上分支,然後合併這個修補分支,最後將改動推送到線上分支。

        • 4. 切換回你最初工作的分支上,繼續工作。

    • 分支三方合併案例

    • 分支開發工作流建議分支

    • 長期分支

    • 因為 Git 使用簡單的三方合併,所以就算在一段較長的時間內,反覆把一個分支合併入另一個分支,也不是什麼難事。 也就是說,在整個專案開發週期的不同階段,你可以同時擁有多個開放的分支;你可以定期地把某些特性分支合併入其他分支中。

    • 許多使用 Git 的開發者都喜歡使用這種方式來工作,比如只在 master 分支上保留完全穩定的程式碼——有可能僅僅是已經發布或即將釋出的程式碼。 他們還有一些名為 develop 或者 next 的平行分支,被用來做後續開發或者測試穩定性——這些分支不必保持絕對穩定,但是一旦達到穩定狀態,它們就可以被合併入 master 分支了。 這樣,在確保這些已完成的特性分支(短期分支,比如之前的 iss53 分支)能夠通過所有測試,並且不會引入更多 bug 之後,就可以合併入主幹分支中,等待下一次的釋出。

    • 特性分支

    • 特性分支對任何規模的專案都適用。 特性分支是一種短期分支,它被用來實現單一特性或其相關工作。

    • 伺服器上的 Git - GitLab

      • 雖然 GitWeb 相當簡單。 但如果你正在尋找一個更現代,功能更全的 Git 伺服器,這裡有幾個開源的解決方案可供你選擇安裝。 因為 GitLab 是其中最出名的一個,我們將它作為示例並討論它的安裝和使用。 這比 GitWeb 要複雜的多並且需要更多的維護,但它的確是一個功能更全的選擇。

      • 安裝使用詳情:https://git-scm.com/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-GitLab

      • 如果不想設立自己的 Git 伺服器,你可以選擇將你的 Git 專案託管到一個外部專業的託管網站。 這帶來了一些好處:一個託管網站可以用來快速建立並開始專案,且無需進行伺服器維護和監控工作。 即使你在內部設立並且執行了自己的伺服器,你仍然可以把你的開原始碼託管在公共託管網站 - 這通常更有助於開源社群來發現和幫助你。

    • 其他分散式git ,git工具 ,自定義git ,內部原理等詳細資訊,請移步Git官網:https://git-scm.com/book/zh/v2