Git-基本概念-2

讀懂 diff

  • diff 的輸出格式,能夠分爲:正常格式,上下文格式,合併格式.這裏只介紹合併格式.經過 -u 選項指定了 diff 的輸出爲合併格式.如: linux

$ cat f1
a
a
a
b
a
a
a
$ cat f2
a
a
a
a
a
a
a
$ diff f1 f2 -u
--- f1  2014-06-03 00:47:10.859206823 +0800
+++ f2  2014-06-03 00:47:06.319206762 +0800
@@ -1,7 +1,7 @@
 a
 a
 a
-b 
+a 
 a
 a
 a

  • diff -u 的輸出能夠分爲三個部分,其中第一部分以下:git

--- f1  2014-06-03 00:47:10.859206823 +0800
+++ f2  2014-06-03 00:47:06.319206762 +0800
# --- 表示改動前的文件.+++ 表示改動後的文件.

  • 第2部分以下:shell

@@ -1,7 +1,7 @@
# @@ ... @@ 指明瞭一個改動位置.
# -1,7 中;'-'表示 --- 指向的文件,即改動前的文件.'1' 表示第1行,'7'表示連續7行.
# +1,7 中;'+'表示 +++ 指向的文件,即改動後的文件.'1' 表示第1行,'7'表示連續7行.
# @@ ... @@ 的總的意思就是文件 f1 的[1,8)行通過以下改動後變爲 f2 的[1,8)行.

  • 第3部分就是改動的詳細內容:工具

 a
 a
 a
-b  # '-' 表示移除該行.
+a  # '+' 表示新增該行.
 a
 a
 a

智能協議/啞協議

  • 智能協議,會話的兩個版本庫會打開輔助程序進行數據傳輸,直觀感覺: 具備進度顯示,按需傳輸速度快.測試

  • 啞協議,會話的兩個版本庫不會打開輔助程序,直觀感覺: 不具備進度顯示,速度慢.fetch

快進式推動

  • 遠程版本庫相應分支的最新提交是本地版本庫相應分支最新提交的祖先,則此時 git push 爲快進式推動.ui

.git/logs

  • 日誌空間,該目錄下全部文件均是日誌.url

  • 每個引用文件在 .git/logs 下都有對應的日誌文件,用於記錄引用文件內容的變動,即當引用文件內容發生變化時,就將新的內容追加在它對應的日誌文件的末尾.如:spa

$ cat .git/refs/heads/master        # 顯示 master 引用文件的內容
485499
$ cat .git/logs/refs/heads/master   # 顯示 master 對應日誌文件的內容
000000 f3e91c       commit (initial): 初始化   
f3e91c 236aa5       commit: * get_modify_args.c
236aa5 4f7bff       merge 重作: Fast-forward
4f7bff 11176b       commit: 添加了 unmap 子命令
11176b e137ac       commit: 新增 protect 子命令
e137ac 49a5d7       commit (amend): 新增 protect 子命令
49a5d7 485499       commit (amend): 新增 protect 子命令

$ git commit -m"測試"  --allow-empty  # 建立一個空的提交.
[master 903b0f] 測試

$ cat .git/refs/heads/master         # master 引用文件內容變化,指向着最新提交. 
903b0f
$ cat .git/logs/refs/heads/master    # master 對應日誌文件內容也變化 
000000 f3e91c       commit (initial): 初始化
f3e91c 236aa5       commit: * get_modify_args.c
236aa5 4f7bff       merge 重作: Fast-forward
4f7bff 11176b       commit: 添加了 unmap 子命令
11176b e137ac       commit: 新增 protect 子命令
e137ac 49a5d7       commit (amend): 新增 protect 子命令
49a5d7 485499       commit (amend): 新增 protect 子命令
485499 903b0f       commit: 測試

.git/objects

  • 該目錄用於存放全部的 git object.即 commit object,tag object,blob object,tree object.3d

  • 若一個 git object 的 SHA1 值爲 XYXXX...YYY,則其在 .git/objects 下的路徑爲: XY/XXX...YYY.如 commit object 903b0f4f9ad3d1f59a9cd12eb63ab6f21dbec1b9 的路徑爲:

$ ls -l .git/objects/90/3b0f4f9ad3d1f59a9cd12eb63ab6f21dbec1b9 
-r--r--r--  .git/objects/90/3b0f4f9ad3d1f59a9cd12eb63ab6f21dbec1b9

.git/index 暫存區

  • .git/index 能夠認爲就是一個 tree object,存放着暫存區目錄樹的信息.

  • 當使用git status.

    • 若一個文件僅在工做區或者暫存區中存在,則輸出相應的提示信息.

    • 不然一個文件在工做區,暫存區中均存在,此時:

// 在 tree object 中保存着文件的最後一次修改時間
if(文件在工做區的最後一次修改時間 == 文件在暫存區中的最後一次修改時間){
    說明文件沒有通過改動;
    略過該文件,繼續下一個文件;
}else{
    比較文件的內容;
    // 在 tree object 中存在着保存文件內容的 blob object 的 SHA1 值.
    if(文件內容沒有通過改變)
        更新文件在暫存區中的最後一次修改時間;
        // 這樣下一次調用 git status 就沒必要要讀取文件內容.
    else
        輸出相應的提示信息,代表文件通過改動.
}

  • 當使用 git diff 時,與 git status 相似,只不過當文件內容通過改動時,輸出改動信息.

  • 當使用 git add 時:

if(文件在暫存區中不存在 || 文件通過改動){
    新建一個 blob object,將改動後的文件信息寫入該 blob object 中;
    更新文件在暫存區的文件狀態信息,以及對應 blob object 的 SHA1 值;
    // 參考 tree object 的結構.
}else 直接返回.

標籤

  • 存放着 .git/refs/tags/ 下,也是引用文件,經過對 commit object/tag object 的引用來代表當前提交具備'里程碑'的意義. 

  • 輕量級標籤,僅是經過 commit object 的引用來代表當前提交具備里程碑的意義,並無新建一個 tag object.輕量級標籤不能夠帶有註釋,以及不能夠被簽名.

  • 重量級標籤,是對 tag object 的引用,即經過新建一個 tag object 來代表當前提交具備里程碑的意義,能夠帶有註釋,以及能夠被簽名.如:

$ git tag Qing   # 建立一個輕量級標籤
$ git tag -m"註釋" Zhong # 建立一個重量級標籤
$ ls -l .git/refs/tags/
總用量 8
-rw-r--r-- 1 root root 41  6月  1 13:12 Qing
-rw-r--r-- 1 root root 41  6月  1 13:12 Zhong
$ git cat-file -t $(cat .git/refs/tags/Zhong) # 重量級標籤是對 tag object 的引用.
tag
$ git cat-file -t $(cat .git/refs/tags/Qing)  # 輕量級標籤是對 commit object 的引用
commit

git push/git fetch 與 標籤

  • 當使用 git push 時,默認是不會上傳標籤的,即 tag object 與 .git/refs/tags/ 下的內容不會被上傳.除非顯式上傳,如使用 --tags 選項,或者在 git push 時使用引用表達式.

  • 當使用 git pull 時,默認會下載當前遠程分支上的 tag ,而不會獲取其餘分支.

    • 當本地已有同名 tag ,則默認不會下載對應的 tag ,除非顯式使用引用表達式!

    • 此時下載下來的 tag 引用並非存放在 .git/refs/remote/<遠程版本庫名>/tags 中,而是統一存放在 .git/refs/tags 下.

    • 當使用 git branch -d -r 刪除遠程分支時,並不會刪除關聯的 tag object.

工做區,暫存區,版本庫

  • git init 建立的 .git 目錄就被成爲 git 版本庫;.git 目錄所處的目錄爲工做區.

  • 工做區,也至關於一個 tree object,保存着位於工做區的文件,目錄信息.

裸版本庫

  • 裸版本庫,也即沒有工做區的版本庫,此時 core.bare==true.如:

$ git clone --bare Test/ Git_bare
克隆到裸版本庫 'Git_bare'...
完成。
Checking connectivity... done
$ cd Git_bare/
$ ls  # 裸版本庫沒有工做區,
branches  config  description  HEAD  hooks  info  objects  packed-refs  refs
$ git config core.bare 
true  # 而且 core.bare 爲真

分支

  • 分支,就是由若干個 commit object 組成的一條鏈.從應用的角度,分支能夠分爲:

  • 發佈分支,待補充

  • 特性分支,待補充

  • 賣主分支,待補充

git 配置

  • git 配置文件是由一系列名值對組成,而且使用''的概念將這些名值對組織在一塊兒,如:

$ cat .git/config 
[core]                   # 就是一個節,
        repositoryformatversion = 0
        filemode = true  # 經過 core.filemode 來訪問該選項.
        bare = false     
        logallrefupdates = true
[remote "origin"]   
        url = git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
        fetch = +refs/heads/*:refs/remotes/origin/*  # 經過 remote.origin.fetc 來訪問該選項.
[branch "master"]
        remote = origin  # 經過 branch.master.remote 來訪問該項
        merge = refs/heads/master

  • 注意,對配置項的訪問方式. 

配置文件的層次

級別名稱

文件位置

訪問/修改

優先級別

系統級別

/etc/gitconfig

git config --system

最低

用戶級別

~/.gitconfig

git config --global

中等

項目級別

項目目錄/.git/config

git config

最高

  • 優先級高的會覆蓋優先級低的

經常使用配置

color

  • ui   true/false,若 color.ui 爲真,則在 git 的輸出中會開啓顏色顯示.

core


  • logAllRefUpdates true/false 若爲 true,代表啓用引用日誌功能,即每當引用文件(.git/HEAD,.git/refs/heads/*.*,.git/refs/stash)改變時,就將改變信息記錄在 .git/logs/ 指定的文件中.裸版本庫不會將該屬性設置爲 true,因此如有必要,應該手動設置.



receive


  • denyNonFastForwards true/false 若未真,則總會拒絕其餘版本庫的非快進式提交.

  • denyDeletes true/false 若爲真,則禁止其餘版本庫經過 git push :remote-ref 來刪除本地引用,效果以下:

    A$ git branch  # 版本庫 A 當前分支.
      b1
      b2
    * master
    A$ git config receive.denyDeletes  
    true 
    B$ git push origin :refs/heads/b1 # 在 B 中試圖刪除 A 的 b1 分支.
    remote: error: denying ref deletion for refs/heads/b1
    To /root/CCProject/A
     ! [remote rejected] b1 (deletion prohibited)
    error: 沒法推送一些引用到 '/root/CCProject/A'
    # 因爲在 A 中 receive.denyDeletes==true,因此刪除失敗
    A$ git branch -D b1 # denyDeletes 只是禁止其餘版本庫刪除,而不是本地版本庫
    已刪除分支 b1(曾爲 787d106).
    A$ git config receive.denyDeletes false
    B$ git push origin :refs/heads/b2
    To /root/CCProject/A
     - [deleted]         b2
    # 因爲 receive.denyDeletes==false,因此在 B 中刪除 A 的 b1 分支成功.
    A$ git branch
    * master

merge

  • tool 配置了調用 git mergetool 時啓用的工具.若配置的工具不被 git 內部支持,則還須要配置 merge.<tool>.path(肯定路徑) merge.<tool>.cmd(調用該工具時的命令),不過通常下 git 支持不少種工具,包括: kdiff3,meld.

  • conflictstyle merge/diff3

    # 若其值爲 merge,則會在衝突文件使用'<<<<<<<','=======','>>>>>>>'對衝突內容標識,如:
        <<<<<<< #本地修改的版本
        ========
        >>>>>>> #他人修改的版本  
    # 若其值爲 diff3,則會在衝突文件下使用'<<<','|||','>>>','==='對衝突內容進行標識,如:
        <<<<<<<#本地修改的版本
        |||||||#祖先版本
        =======#他人修改的版本
        >>>>>>>
相關文章
相關標籤/搜索