漫談Git和Github

image.png

上期漫談版本控制系統中我們談到了版本控制系統的四個演進過程,即悲觀鎖版本 -> 樂觀鎖版本 -> 多分支版本 -> 分佈式版本,目前我們使用最多的是分佈式版本,本期我們就來介紹下分佈式版本控制系統的具體實現GitGitHub

Git基礎

Git不用於其他版本控制系統主要體現在以下幾點:1. Git對待數據的方法,直接記錄快照,而非差異比較;2. 暫存區;3.高效的分支模型。
- 直接記錄快照,而非差異比較
CVS、Subversion等版本控制系統會以文件變更列表的方式存儲信息,即以增量形式存儲信息,如下圖所示。而Git全量方式存儲信息,同時爲了減少空間使用,當文件沒有修改時,最新版本中並不會存儲該文件的全量信息,而是保留一個鏈接指向之前存儲的文件。譬如File A在version2發生了修改,因此全量存儲文件信息,而在version3並沒有修改,因此保留一個鏈接指向A1。

CVS、Subversion等版本控制系統存儲文件方式

Git文件存儲方式

  • 工作目錄、暫存區、本地倉庫
    Git引入三個工作區域的概念:工作目錄(Working Directory)、暫存區(Staging Area)、本地倉庫,尤其是暫存區具有獨創性。工作目錄是對項目的某個版本提取出來的內容存放到磁盤中;暫存區只是一個文件,保存下次提交的文件列表信息;本地倉庫是Git用來保存項目的元數據和對象數據庫的地方,當進行克隆倉庫時,拷貝的就是這裏的數據。數據在三者之間的基本交互流程:1.在工作目錄中修改文件;2.暫存文件,將文件的快照存放到暫存區域;3.提交更新,找到暫存區域的文件,將快照永久性存儲到Git倉庫中。

image.png
- 高效的分支模型
在很多版本控制系統中,創建一個分支意味着需要完全創建一個源代碼目錄的副本,對於大型項目來說,這樣的過程會耗費大量時間,而這對於Git來說是非常輕便的。上文我們已經提到Git對待數據的方法,即直接記錄快照,同時,Git在進行提交操作時,它會保存一個提交對象(commit object),該對象會包含一個指向暫存內容快照的指針,提交者的姓名、郵箱、輸入信息和指向它的父對象的指針。注意:首次提交的提交對象沒有父對象。
爲了幫助大家更好地理解,假設有一個工作目錄,包含三個將要被暫存和提交的文件。暫存操作爲每個文件計算校驗和,然後把當前版本的文件快照保存到Git倉庫中(Git使用blob對象保存它們)。當使用git commit 進行提交操作時,會計算每一個子目錄的校驗和,然後在Git倉庫中將這些校驗和保存爲樹對象,隨後,Git便會創建一個提交對象,它除了包含上面提到的那些信息外,還包含指向這個樹對象的指針。如下圖所示,現在Git倉庫包含五個對象:三個blob對象(保存着文件快照)、一個樹對象(記錄着目錄結構和blob對象索引)以及一個提交對象。

image.png

安裝

  • Windows系統 
    可以通過cmder中的choco install git,也可以通過普通安裝完成
  • Mac系統 
    brew install git
  • Linux系統 
    yum install git
  • 檢查安裝是否成功 
    git --version

初次運行Git前的配置

用戶信息
當安裝完Git之後應該做的第一件事就是設置你的用戶名稱和郵件地址,這樣做很重要,因爲每一次Git提交都會使用這些信息。

git config --global user.name "mukedada"
git config --global user.email mukedada@126.com

注意--global選項表示全局設置。
檢查配置信息
通過git config --list命令列出所有Git當前能找到的配置,還可以通過git config <key>來檢查某一項配置,例如:git config user.name,結果:

$ git config user.name
mukedada

獲取Git倉庫

目前有兩種方式獲取Git項目倉庫的方法。第一種方法是把現有目錄下的所有文件導入到Git中;第二種方法是一個服務器克隆一個現有的Git倉庫。
在現有目錄中初始化倉庫

$ cd test
$ git init

在test目錄下創建一個名爲.git的子目錄。
克隆現有的倉庫
克隆倉庫的命令格式是git clone [url]。比如,要克隆木可大大的code倉庫,可以用下面的命令:

$ git clone git@github.com:mukedada/code.git

這回在當前目錄下創建一個名爲”code”的目錄,並在這個目錄下初始化一個.git文件夾。

記錄每次更新到倉庫

test目錄下的每個文件都不外乎兩個狀態:已跟蹤或未跟蹤。已跟蹤的文件是指那些被納入了版本控制的文件,在上一次快照中有它們的記錄,在工作一段時間後,它們的狀態可能處於未修改或已修改或一放入暫存區。test目錄下除了已跟蹤的文件以外,剩下的文件都屬於未跟蹤的文件,它們既不存在於上次快照的記錄中,也沒有放入暫存區。初次克隆的test倉庫,此時該工作目錄中的所有文件都屬於已跟蹤文件,並處於未修改狀態。編輯過某些文件之後,由於自上次提交後我們對它們做了修改,Git將它們標記爲已修改文件。我們逐步將這些修改過的文件放入暫存區,然後提交所有暫存區中的修改,如此反覆。
image.png

檢查當前文件狀態

使用git status名稱查看當前文件處於什麼狀態。

$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

nothing to commit,working tree clean說明當前工作目錄中所有已跟蹤的文件在上次提交之後沒有修改過;On branch master說明當前處於master分支。

現在,我們在test項目下創建text.txt文件,再使用git status命令。

$ echo 'my project' > test.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        test.txt

nothing added to commit but untracked files present (use "git add" to track)

從中我們可以發現,test.txt在Untracked files下面,這就意味着該文件並未在之前的快照中,如果我們想讓該文件納入到Git的跟蹤範圍內,需要使用git add命令。

跟蹤新文件

git add + 文件或目錄,如果是目錄,則將遞歸跟蹤該目錄下所有的文件。

$ git add test.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   test.txt

只要出現Changes to be committed說明test.txt已經進入暫存區。

暫存已修改文件

現在我們修改test.txt,發現該文件既出現在Changes to be committed下面,又出現在Changes not staged for commit下面,前一句說明該文件在暫存區,而後一句說明該文件在非暫存區,這怎麼可能呢?其實,文件在暫存區是因爲暫存區保存的是我們上一次運行git add命令時的版本,接着我們沒有運行git commit命令,而是對文件進行修改,所以出現了Changes not staged for commit,因此,我們需要對修改後的文件重新運行git add命令把最新版本重新暫存起來。

$ vim test.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   test.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   test.txt

查看已暫存和未暫存的區別

通過上面代碼我們知道我們對已暫存的test.txt進行了修改,還沒有執行git add命令,但是我們不知道具體修改了什麼內容,此時,我們就可以用git diff命令來查看修改的內容。

$ git diff
diff --git a/test.txt b/test.txt
index a159320..b3b1c1b 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
 hello 'my project'
+haha~

提交更新

使用 git commit -m "備註"命令提交存放在暫存區的快照,-m選項表示提交時備註信息。

跳過使用暫存區域

git commit加上-a選項表示跳過git add步驟直接將文件保存到暫存區。

打標籤

  • 列出標籤
    輸入git tag命令:
$ git tag
v0.1
  • 創建標籤
$ git tag -a v1.0 -m 'my version 1.0'
$ git tag
v0.1
v1.0

分支

Git分支,本質上就是指向提交對象的可變指針。每當提交一次,都會生成一個新的提交對象,它包含一個指向上次提交對象的指針,如下圖所示。
image.png
分支創建
通過使用git branch命令創建分支,譬如:

$ git branch testing

image.png
當有兩個指向相同提交歷史的分支,Git怎麼知道當前在哪一個分支上呢?Git有一個特殊指針HEAD,它指向當前所在的本地分支。
image.png
分支切換
通過使用git checkout命令進行分支切換,譬如:我們切換到新創建的testing分支上:

$ git checkout testing

此時,HEAD就指向testing分支。
image.png

分支合併
目前Git分支合併主要有兩種方法:mergerebase
- merge:把兩個分支的最新快照和以及兩者最近的共同祖先進行三方合併,合併的結果是生成一個新的快照,並提交,如果沒有衝突的話。舉個栗子,首先將hotfix branch合併到master分支上,由於當前master分支所指向的提交是hotfix分支的之間上游,因此Git知識簡單的將指針向前移動,這就是快進(fast-forward)

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

image.png
image.png
由於master分支和hotfix分支指向同一個位置,我們可以使用git branch -d指令刪除分支

$ git branch -d hotfix

接下來,我們繼續在iss53工作,最後一個提交對象是C5,此時,如何合併iss53分支和C5分支?
image.png

我們需要將HEAD指向master,然後執行git merge命令:

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

這和之前合併hotfix分支看起來有些不同,Git會使用兩個分支的末端所指的快照(C4C5)以及這兩個分支的工作祖先(C2),做一個簡單的三方合併。
image.png

  • rebase ,中文名”變基”,即將某一分支上的所有修改都移植到另一分支上,就好像”重新播放”一樣。爲了加深大家的印象,對C4分支和C3分支進行合併,首先提取C4的修改,然後在C3上重新播放一遍。
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

執行完上述代碼之後,形成如下結構。

對於上述結構,我們還需要進行一次合併。

$ git checkout master
$ git merge experiment

image.png

  • 注意:當兩個不同的分支中,對同一個文件的同一個部分進行不同的修改,Git就沒法乾淨的合併它們,此時需要我們手動解決衝突。

GitHub

目前,GitHub是最大的Git版本庫託管商,大部分開源項目都託管在Github,因此學習Github就比不可少了。
- 賬戶的創建和配置
訪問GitHub官網,填寫相關信息完成註冊。
image.png
- 配置SSH
首先需要生成本機公鑰,如果是Window,使用指令ssh-keygen -t rsa -C "[email protected]"生成主機的公私密鑰對,如果是Mac,則使用ssh-keygen命令上。注意:運行上述指令時,不要輸入任何信息,只需按enter就可以,成功之後,公私鑰文件會存放於當前用戶目錄的.ssh目錄下,例如C:\Users\kwy\.ssh。接着,將生成出的公鑰放到github中。
image.png
- 創建倉庫
image.png
- 克隆遠程倉庫到本地:git clone [email protected]:mukedada/artical.git


image

歡迎關注微信公衆號:木可大大,所有文章都將同步在公衆號上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章