簡單地說,Git 究竟是怎樣的一個系統(tǒng)呢?請注意接下來的內(nèi)容非常重要,若你理解了 Git 的思想和基本工作原理,用起來就會知其所以然,游刃有余。在學(xué)習(xí) Git 時,請盡量理清你對其它版本管理系統(tǒng)已有的認(rèn)識,如 CVS、Subversion 或 Perforce, 這樣能幫助你使用工具時避免發(fā)生混淆。盡管 Git 用起來與其它的版本控制系統(tǒng)非常相似, 但它在對信息的存儲和認(rèn)知方式上卻有很大差異,理解這些差異將有助于避免使用中的困惑。
執(zhí)行完成了 git init 命令,究竟做了什么呢?執(zhí)行完成如下命令之后,我們可以得到下圖所示的內(nèi)容,右側(cè)的就是 Git 為我們創(chuàng)建的代碼倉庫,其中包含了用于版本管理所需要的內(nèi)容。# 左邊執(zhí)行
$ mkdir git-demo
$ cd git-demo && git init
$ rm -rf .git/hooks/*.sample
# 右邊執(zhí)行
$ watch -n 1 -d find .
我們這里可以一起看下生成的 .git 目錄的結(jié)構(gòu)如何:? tree .git
.git
├── HEAD
├── config
├── description
├── hooks
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
.git/config - 當(dāng)前代碼倉庫本地的配置文件本地配置文件(.git/config)和全局配置文件(~/.gitconfig)
通過執(zhí)行如下命令,可以將用戶配置記錄到本地代碼倉庫的配置文件中去
git config user.name "demo"
git config user.email "[email protected]"
? cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[user]
name = demo
email = [email protected]
.git/objects - 當(dāng)前代碼倉庫代碼的存儲位置
# 均無內(nèi)容
? ll .git/objects
total 0
drwxr-xr-x 2 escape staff 64B Nov 23 20:39 info
drwxr-xr-x 2 escape staff 64B Nov 23 20:39 pack
? ll .git/objects/info
? ll .git/objects/pack
.git/info - 當(dāng)前倉庫的排除等信息? cat ./.git/info/exclude
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
.git/hooks - 當(dāng)前代碼倉庫默認(rèn)鉤子腳本./.git/hooks/commit-msg.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/pre-commit.sample
./.git/hooks/applypatch-msg.sample
./.git/hooks/fsmonitor-watchman.sample
./.git/hooks/pre-receive.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/post-update.sample
./.git/hooks/pre-merge-commit.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/pre-push.sample
./.git/hooks/update.sample
.git/HEAD - 當(dāng)前代碼倉庫的分支指針? cat .git/HEAD
ref: refs/heads/master
.git/refs - 當(dāng)前代碼倉庫的頭指針# 均無內(nèi)容
? ll .git/refs
total 0
drwxr-xr-x 2 escape staff 64B Nov 23 20:39 heads
drwxr-xr-x 2 escape staff 64B Nov 23 20:39 tags
? ll .git/refs/heads
? ll .git/refs/tags
.git/description - 當(dāng)前代碼倉庫的描述信息? cat .git/description
Unnamed repository; edit this file 'description' to name the repository.
執(zhí)行完成了 git add 命令,究竟做了什么呢?執(zhí)行完成如下命令之后,我們可以得到下圖所示的內(nèi)容,我們發(fā)現(xiàn)右側(cè)新增了一個文件,但是 Git 目錄里面的內(nèi)容絲毫沒有變化。這是因為,我們現(xiàn)在執(zhí)行的修改默認(rèn)是放在工作區(qū)的,而工作區(qū)里面的修改不歸 Git 目錄去管理。而當(dāng)我們執(zhí)行 git status 命令的時候,Git 又可以識別出來現(xiàn)在工作區(qū)新增了一個文件,這里怎么做到的呢?—— 詳見[理解 blob 對象和 SHA1]部分而當(dāng)我們執(zhí)行 git add 命令讓 Git 幫助我們管理文件的時候,發(fā)現(xiàn)右側(cè)新增了一個目錄和兩個文件,分別是 8d 目錄、index 和 0e41.. 文件。# 左邊執(zhí)行
$ echo "hello git" > helle.txt
$ git status
$ git add hello.txt
# 右邊執(zhí)行
$ watch -n 1 -d find .
我們這里重點看下,生成的 8d 這個目錄以及下面的文件。而其名稱的由來是因為 Git 對其進(jìn)行了一個叫做 SHA1 的 Hash 算法,用于將文件內(nèi)容或者字符串變成這么一串加密的字符。# 查看 objects 的文件類型
$ git cat-file -t 8d0e41
blob
# 查看 objects 的文件內(nèi)容
$ git cat-file -p 8d0e41
hello git
# 查看 objects 的文件大小
$ git cat-file -s 8d0e41
10
# 拼裝起來
blob 10\0hello git
現(xiàn)在我們就知道了,執(zhí)行 git add 命令將文件從工作區(qū)添加到暫存區(qū)里面,Git 會把幫助我們生成一些 Git 的對象,它存儲的是文件的內(nèi)容和文件類型并不存儲文件名稱。為了驗證我們上述的說法,我們可以添加同樣的內(nèi)容到另一個文件,然后進(jìn)行提交,來觀察 .git 目錄的變化。我們發(fā)現(xiàn),右側(cè)的 objects 目錄并沒有新增目錄和文件。這就可以證明,blob 類型的 object 只存儲的是文件的內(nèi)容,如果兩個文件的內(nèi)容一致的話,則只需要存儲一個 object 即可。話說這里 object 為什么沒有存儲文件名稱呢?這里因為 SHA1 的 Hash 算法計算哈希的時候,本身就不包括文件名稱,所以取什么名稱都是無所謂的。那問題來了,就是文件名的信息都存儲到哪里去了呢?—— 詳見[理解 blob 對象和 SHA1]部分# 左邊執(zhí)行
$ echo "hello git" > tmp.txt
$ git add tmp.txt
# 右邊執(zhí)行
$ watch -n 1 -d find .
了解 Git 的 blob 對象和 SHA1 之前的關(guān)系和對應(yīng)計算!Hash 算法是把任意長度的輸入通過散列算法變化成固定長度的輸出,根據(jù)算法的不同,生成的長度也有所不同。MD5 - 128bit - 不安全 - 文件校驗
SHA1 - 160bit(40位) - 不安全 - Git 存儲
SHA256 - 256bit- 安全 - Docker 鏡像
SHA512 - 512bit - 安全
但是,當(dāng)我們使用工具對上述文件內(nèi)容進(jìn)行 SHA1 計算的時候,會發(fā)現(xiàn)并沒有我們在 .git 目錄里面看到的那樣,這是為什么呢?? echo "hello git" | shasum
d6a96ae3b442218a91512b9e1c57b9578b487a0b -
這里因為 Git 工具的計算方式,是使用類型 長度 \0 內(nèi)容的方式進(jìn)行計算的。這里,我們算了下文件內(nèi)容只有九位,但是這里是十位,這里因為內(nèi)容里面有換行符的存在導(dǎo)致的?,F(xiàn)在我們就可以使用 git cat-file 命令來拼裝 Git 工具存儲的完整內(nèi)容了。? ls -lh hello.txt
-rw-r--r-- 1 escape staff 10B Nov 23 21:12 hello.txt
? echo "blob 10\0hello git" | shasum
8d0e41234f24b6da002d962a26c2495ea16a425f -
# 拼裝起來
blob 10\0hello git
當(dāng)我們使用 cat 命令來查看 object 對象里面的內(nèi)容的時候,發(fā)現(xiàn)看著像是一串亂碼。其實這是 Git 工具將文件的原始內(nèi)容進(jìn)行一個壓縮,然后再存儲到 object 對象里面。奇怪的是,我們發(fā)現(xiàn)壓縮之后的內(nèi)容反而比原始內(nèi)容還大!這是因為其進(jìn)行了壓縮,存儲了一些壓縮相關(guān)的信息。上例所示的比原始文件大,是因為我們創(chuàng)建的內(nèi)容實在是太小了。當(dāng)我們常見一個比較大的文件時,就會看到壓縮之后的文件大小遠(yuǎn)小于原始文件的。? cat .git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
xKOR04`HWH,6A%
? ls -lh .git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
-r--r--r-- 1 escape staff 26B Nov 23 21:36 .git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
? file .git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f
.git/objects/8d/0e41234f24b6da002d962a26c2495ea16a425f: VAX COFF executable not stripped - version 16694
其實,我們這里也是可以通過 Python 代碼來獲取二進(jìn)制 object 對象的內(nèi)容的。import zlib
contents = open('0e41234f24b6da002d962a26c2495ea16a425f', 'rb').read()
zlib.decompress(contents)
聊聊工作區(qū)和暫存區(qū),以及文件如何在工作區(qū)和緩存區(qū)之間同步的問題。之前的章節(jié)我們也聊到了,當(dāng)我們執(zhí)行 git status 命令的時候,Git 工具怎么知道我們有一個文件沒有追蹤,以及文件名的信息都存儲到哪里去了?這一切的答案,都要從工作區(qū)和索引區(qū)講起。Git 根據(jù)其存儲的狀態(tài)不同,將對應(yīng)狀態(tài)的“空間”分為工作區(qū)、暫存區(qū)(也可稱為索引區(qū))和版本區(qū)三類。具體示例,可以參考下圖。而更加深層次的理解,就要從執(zhí)行 git add 命令后生成相關(guān)的 object 對象,但是其存儲的是文件的類容、大小和內(nèi)容,并不包含文件名稱的信息。而文件名稱相關(guān)的信息就包含在生成的 index 文件(索引文件)里面。當(dāng)我們直接查看 index 文件里面的內(nèi)容,發(fā)現(xiàn)使我們無法理解的亂碼,但是通過基本的輸出,我們可以看到其文件名稱。要想查看 index 文件的內(nèi)容,可以通過 Git 提供的相關(guān)命令進(jìn)行查看。# 左邊執(zhí)行
$ echo "file1" > file1.txt
$ git add file1.txt
$ cat .git/index
$ git ls-files # 列出當(dāng)前暫存區(qū)的文件列表信息
$ git ls-files -s # 列出當(dāng)前暫存區(qū)文件的詳細(xì)信息
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
當(dāng)添加文件的時候,文件或目錄會從工作區(qū)流向暫存區(qū),加之一些其他操作,會導(dǎo)致工作區(qū)和暫存區(qū)是會有一定差別的。這就會導(dǎo)致,當(dāng)我們執(zhí)行 git status 的結(jié)果就是兩者的差別。經(jīng)過如下操作,會使工作區(qū)和暫存區(qū)和的內(nèi)容不一致了,通過命令我們也是可以查看區(qū)別的。當(dāng)我們使用 add 命令將新文件添加到暫存區(qū)的時候,會發(fā)現(xiàn)這下就一致了。# 左邊執(zhí)行
$ git status
$ echo "file2" > file2.txt
$ git ls-files -s
$ git status
$ git add file2.txt
$ git ls-files -s
$ git status
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
如果我們這里去修改一個文件的話,很顯然這個時候我們的工作區(qū)和暫存區(qū)又不一致了。當(dāng)我們使用命令去查看文件狀態(tài)的時候,發(fā)現(xiàn)一個文件被修改了,而 Git 是怎么知道的呢?咳咳,就是通過查找 index 文件的內(nèi)容,找到對應(yīng)文件名稱以及其內(nèi)部引用的 object 對象,與工作區(qū)的文件內(nèi)容進(jìn)行對比而來的。# 左邊執(zhí)行
$ git ls-files -s
$ echo "file.txt" > file1.txt
$ git status
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
而這個時候,我們再使用 git add 命令將其修改內(nèi)容保存至?xí)捍鎱^(qū)的話,會發(fā)現(xiàn)對應(yīng)文件的 object 的 blob 對象的引用值發(fā)生改變了。這時可以發(fā)現(xiàn),objects 目錄下面有三個對象了,其中 file1.txt 占了兩個,但是文件卻只有兩個。通過命令查看對應(yīng) blob 對象的內(nèi)容,發(fā)現(xiàn)各有不同。# 左邊執(zhí)行
$ git ls-files -s
$ git add file1.txt
$ git ls-files -s
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
執(zhí)行完成了 git commit 命令,究竟做了什么呢?Git 倉庫中的提交記錄保存的是你的目錄下所有文件的快照,就像是把整個目錄復(fù)制,然后再粘貼一樣,但比復(fù)制粘貼優(yōu)雅許多!Git 希望提交記錄盡可能地輕量,因此在你每次進(jìn)行提交時,它并不會盲目地復(fù)制整個目錄。條件允許的情況下,它會將當(dāng)前版本與倉庫中的上一個版本進(jìn)行對比,并把所有的差異打包到一起作為一個提交記錄。Git 還保存了提交的歷史記錄。這也是為什么大多數(shù)提交記錄的上面都有父節(jié)點的原因。當(dāng)我們使用 add 命令將工作區(qū)提交到暫存區(qū),而暫存區(qū)其實保存的是當(dāng)前文件的一個狀態(tài),其中包括有哪些目錄和文件,以及其對應(yīng)的大小和內(nèi)容等信息。但是我們最終是需要將其提交到代碼倉庫(本地)的,而其命令就是 git commit 了。而當(dāng)我們執(zhí)行 git commit 命令的時候,究竟都發(fā)生了什么呢?可以看到當(dāng)提交之后,.git 目錄中生成了兩個信息的 object 對象,其中 logs 和 refs 目錄都有新的文件生成。通過如下操作,我們可以查看到其提交的類型和對應(yīng)內(nèi)容。# 左邊執(zhí)行
$ git commit -m "1st commit"
$ git cat-file -t 6e4a700 # 查看 commit 對象的類型
$ git cat-file -p 6e4a700 # 查看 commit 對象的內(nèi)容
$ git cat-file -t 64d6ef5 # 查看 tree 對象的類型
$ git cat-file -p 64d6ef5 # 查看 tree 對象的內(nèi)容
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
這樣我們就理解了,當(dāng)我們執(zhí)行 git commit 命令之后,會生成一個 commit 對象和一個 tree 對象。commit 對象內(nèi)容里面包含了一個 tree 對象和相關(guān)提交信息,而 tree 對象里面則包含了這次我們提交版本里面的文件狀態(tài)(文件名稱和 blob 對象),這樣我們就知道了這次提交的變動了。我們這次提交之后,處理 objects 目錄發(fā)生變動之外,還有一些其他的變化。比如 logs 和 refs 的目錄有所變化。我們查看 refs 目錄里面的內(nèi)容,發(fā)現(xiàn)其指向了 6e4a70 這個 commit 對象,即當(dāng)前 master 分支上面最新的提交就是這個 6e4a70 了。而這個 6e4a70 這個 commit 對象,有一個 HEAD 的指向,就是 .git 目錄下的 HEAD 文件。其實質(zhì)就是一個指針,其永遠(yuǎn)指向我們當(dāng)前工作的分支,即這里我們工作在 master 分支上。當(dāng)我們切換分支的時候,這個文件的指向也會隨機(jī)改變的。# 左邊執(zhí)行
$ cat .git/refs/heads/master
$ cat .git/HEAD
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
執(zhí)行完成了 git commit 命令,究竟做了什么呢?當(dāng)我們再次對 file2.txt 文件的內(nèi)容進(jìn)行變更、添加以及提交之后,發(fā)現(xiàn)在提交的時候,查看的 commit 對象的內(nèi)容時,其包含有父節(jié)點的 commit 信息。而對于理解的話,可以看看下面的這個提交流程圖。# 左邊執(zhí)行
$ echo "file2.txt" > file2.txt
$ git status
$ git add file2.txt
$ git ls-files -s
$ git cat-file -p 0ac9638
$ git commit -m "2nd commit"
$ git cat-file -p bab53ff
$ git cat-file -p 2f07720
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
在 Git 中空文件夾是不算在追蹤范圍內(nèi)的,而且添加文件夾并不會增加 object 對象。當(dāng)我們查看 index 內(nèi)容的時候,會發(fā)現(xiàn)文件名稱是包含相對路徑的。而當(dāng)我們通過 commit 命令提交之后,會發(fā)現(xiàn)生成了三個 object 對象,因為 commit 操作不會生成 blob 對象,所以分別是一個 commit 對象和兩個 tree 對象。可以發(fā)現(xiàn),tree 對象里面有包含了一個目錄的 tree,其里面包含對象文件內(nèi)容。下圖所示的文件狀態(tài),可以體會到 Git 中版本的概念。即 commit 對象指向一個該版本中的文件目錄樹的根(tree),然后 tree 在指向 blob 對象(文件)和 tree 對象(目錄),這樣就可以無限的往復(fù)下去形成一個完整的版本。# 左邊執(zhí)行
$ mkdir floder1
$ echo "file3" > floder1/file3.txt
$ git add floder1
$ git ls-files -s
$ git commit -m "3rd commit"
$ git cat-file -p 1711e01
$ git cat-file -p 9ab67f8
# 右邊執(zhí)行
$ watch -n 1 -d tree .git
總結(jié)一下,Git 里面的文件狀態(tài)和如何切換。現(xiàn)在,我們已經(jīng)基本理解了文件如何在工作區(qū)、暫存區(qū)以及代碼倉庫之間進(jìn)行狀態(tài)的跟蹤和同步。在 Git 的操作中,文件的可能狀態(tài)有哪些,以及如何進(jìn)行狀態(tài)切換的,我們這里一起總結(jié)一下!
執(zhí)行完成了 git branch 命令,究竟做了什么呢?到底什么是分支?分支切換又是怎么一回事?我們通過查看 Git 的官方文檔,就可以得到,分支就是一個有名字的(master/dev)指向 commit 對象的一個指針。我們在初始化倉庫的時候,提供會默認(rèn)給我們分配一個叫做 master 的分支(在最新的版本默認(rèn)倉庫已經(jīng)變更為 main 了),而 master 分支就是指向最新的一次提交。為什么需要給分支起名字呢?就是為了方便我們使用和記憶,可以簡單理解為 alias 命令的意義一致。有了上述基礎(chǔ),我們就需要考慮下,分支到底是如何實現(xiàn)和工作的。要實現(xiàn)一個分支,我們最基本需要解決兩個問題,第一個就是需要存儲每一個分支指向的 commit,第二個問題就是在切換分支的時候幫助我們標(biāo)識當(dāng)前分支。在 Git 中,它有一個非常特殊的 HEAD 文件。而 HEAD 文件是一個指針,其有一個特性就是總會指向當(dāng)前分支的最新的一個 commit 對象。而這個 HEAD 文件正好,解決了我們上面提出的兩個問題。當(dāng)我們從 master 切換分支到 dev 的時候,HEAD 文件也會隨即切換,即指向 dev 這個指針。設(shè)計就是這么美麗,不愧是鬼才,好腦袋。# 左邊執(zhí)行
$ cat .git/HEAD
$ cat .git/refs/heads/master
$ git cat-file -t 1711e01
# 右邊執(zhí)行
$ glo = git log
執(zhí)行完成了 git branch 命令,究竟做了什么呢?這里我們可以看到分支切換之后,HEAD 指向發(fā)生變動了。# 左邊執(zhí)行
$ git branch
$ git branch dev
$ ll .git/refs/heads
$ cat .git/refs/heads/master
$ cat .git/refs/heads/dev
$ cat .git/HEAD
$ git checkout dev
$ cat .git/HEAD
# 右邊執(zhí)行
$ glo = git log
這里需要注意的是,即使我們刪除了分支,但是該分支上一些特有的對象并不會被刪除的。這些對象其實就是我們俗稱的垃圾對象,還有我們多次使用 add 命令所產(chǎn)生的也有垃圾對象,而這些垃圾對象怎么清除和回收呢?后續(xù),我們會涉及到的。# 左邊執(zhí)行
$ echo "dev" > dev.txt
$ git add dev.txt
$ git commit -m "1st commit from dev branch"
$ git checkout master
$ git branch -d dev
$ git branch -D dev
$ git cat-file -t 861832c
$ git cat-file -p 861832c
$ git cat-file -p 680f6e9
$ git cat-file -p 38f8e88
# 右邊執(zhí)行
$ glo = git log
我們一起聊一聊,checkout 和 commit 的操作!我們執(zhí)行 checkout 命令的時候,其不光可以切換分支,而且可以切換到指定的 commit 上面,即 HEAD 文件會指向某個 commit 對象。在 Git 里面,將 HEAD 文件沒有指向 master 的這個現(xiàn)象稱之為 detached HEAD。這里不管 HEAD 文件指向的是分支名稱也好,是 commit 對象也罷,其實本質(zhì)都是一樣的,因為分支名稱也是指向某個 commit 對象的。# 左邊執(zhí)行
$ git checkout 6e4a700
$ git log
# 右邊執(zhí)行
$ glo = git log
當(dāng)我們切換到指定的 commit 的時候,如果需要在對應(yīng)的 commit 上繼續(xù)修改代碼提交的話,可以使用上述圖片中提及的 swtich 命令創(chuàng)建新分支,再進(jìn)行提交。但是,通常我們都不會著玩,都會使用 checkout 命令來創(chuàng)建新分支的。$ git checkout -b tmp
$ git log
即使可以這樣操作,我們也很少使用。還記得我們上一章節(jié)創(chuàng)建的 dev 分支嗎?我們創(chuàng)建了該分支并有了一個新的提交,但是沒有合并到 master 分支就直接刪除了?,F(xiàn)在再使用 log 命令查看的話,是看不到了。實際,真的看不到了嗎?大家要記住,在 Git 里面任何的操作,比如分支的刪除。它只是刪除了指向某個特定 commit 的指針引用而已,而那個 commit 本身并不會被刪除,即 dev 分支的那個 commit 提交還是在的。那我們怎么找到這個 commit 呢?找到之后,我們就可以在上面繼續(xù)工作,或者找到之前的文件數(shù)據(jù)等。
# 左邊執(zhí)行
$ git reflog
$ git checkout 9fb7a14
$ git checkout -b dev
# 右邊執(zhí)行
$ glo = git log
當(dāng)我們執(zhí)行 diff 命令之后,Git 的邏輯它們是怎么對比出來的呢?就在本節(jié)中中,我們使用上節(jié)的倉庫,修改文件內(nèi)容之后,看看 diff 命令都輸出了哪些內(nèi)容呢?我們這里一起來看看,研究研究!$ echo "hello" > file1.txt
$ git diff
$ git cat-file -p 42d9955
$ git cat-file -p ce01362
# 下述命令原理也是一樣的
$ git diff --cached
$ git diff HEAD
如何將我們本地的倉庫和遠(yuǎn)程服務(wù)器上面的倉庫關(guān)聯(lián)起來呢?$ git init
$ git add README.md
$ git commit -m "first commit"
當(dāng)我們使用上述命令來關(guān)聯(lián)遠(yuǎn)程服務(wù)器倉庫的時候,我們本地 .git 目錄也是會發(fā)生改變的。通過命令查看 .git/config 文件的話,可以看到配置文件中出現(xiàn)了 [remote] 字段。# 關(guān)聯(lián)遠(yuǎn)程倉庫
$ git remote add origin [email protected]:escapelife/git-demo.git
? cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = [email protected]:escapelife/git-demo.git
fetch = +refs/heads/*:refs/remotes/origin/*
當(dāng)我們執(zhí)行如下命令,將本地 master 分支推送到遠(yuǎn)程 origin 倉庫的 master 分支。之后,我們登陸 GitHub 就可以看到推送的文件及目錄內(nèi)容了。推送分支內(nèi)容的時候,會列舉推送的 objects 數(shù)量,并將其內(nèi)容進(jìn)行壓縮,之后推送到我們遠(yuǎn)程的 GitHub 倉庫,并且創(chuàng)建了一個遠(yuǎn)程的 master 分支(origin 倉庫)。# 推送本地分支
$ git push -u origin master
推送之后,我們可以發(fā)現(xiàn),本地的 .git 生成了一些文件和目錄,它們都是什么呢?如下所示,會新增四個目錄和兩個文件,皆為遠(yuǎn)程倉庫的信息。當(dāng)我們通過命令查看 master 這個文件的內(nèi)容時,會發(fā)現(xiàn)其也是一個 commit 對象。此時與我們本地 master 分支所指向的一致。而其用于表示遠(yuǎn)程倉庫的當(dāng)前版本,用于和本地進(jìn)行區(qū)別和校對的。? tree .git
├── logs
│ ├── HEAD
│ └── refs
│ ├── heads
│ │ ├── dev
│ │ ├── master
│ │ └── tmp
│ └── remotes # 新增目錄
│ └── origin # 新增目錄
│ └── master # 新增文件
└── refs
├── heads
│ ├── dev
│ ├── master
│ └── tmp
├── remotes # 新增目錄
│ └── origin # 新增目錄
│ └── master # 新增文件
└── tags
使用 GitLab 來了解遠(yuǎn)程倉庫的服務(wù)器到底是如何存儲,我們的代碼的!當(dāng)我們編寫完代碼之后,將其提交到對應(yīng)的遠(yuǎn)程服務(wù)器上面,其存儲結(jié)構(gòu)和我們地址是一模一樣的。如果我們仔細(xì)想想的話,不一樣的話才見怪了。Git 本來就是代碼的分發(fā)平臺,無中心節(jié)點,即每個節(jié)點都是主節(jié)點,所以其存儲的目錄結(jié)構(gòu)都是一直的。這樣,不管哪一個節(jié)點的內(nèi)容發(fā)生丟失或缺失的話,我們都可以通過其他節(jié)點來找到。而 Git 服務(wù)器就是一個可以幫助我們,實時都可以找到的節(jié)點,而已。原文鏈接:https://www.escapelife.site/posts/da89563c.html