git詳細教程

1 版本控制系統

版本控制系統,VCS(Version Control System),是一種記錄一個或若干文件內容變化,以便將來查閱特定版本修訂情況的系統。歷史上版本控制系統的演進又以下三種:

1.1 本地版本控制系統

採用某種簡單的數據庫或硬盤來記錄文件的歷次更新差異。RCS就是代表性的本地版本控制系統。

在這裏插入圖片描述

1.2 集中化版本控制系統

爲了讓不同系統上的開發者協同工作,集中化版本控制系統(Centralized Version Control Systems,簡稱CVCS)應運而生。

代表產品CVS、Subversion 、 Perforce 以及當下使用廣泛的SVN。

集中化版本控制系統有一個單一的集中管理的服務器,保存所有文件的修訂版本,而協同工作的人們都通過客戶端連到這臺服務器,取出最新的文件或者提交更新。

優點:特別是相較於老式的本地 VCS 來說,CVCS允許多人協同工作,而管理員也可以輕鬆掌控每個開發者的權限,並且管理一個 CVCS 要遠比在各個客戶端上維護本地數據庫來得輕鬆容易。

缺點:依賴中央服務器,用戶本地只有自己以前所同步的版本,每次都需要聯網拿到服務器的最新版本,如果中央服務器出現單點故障,就會造成數據丟失。

在這裏插入圖片描述

1.3 分佈式版本控制系統

分佈式版本控制系統(Distributed Version Control System,簡稱 DVCS)解決了集中式版本控制系統的弊端。客戶端並不只提取最新版本的文件快照,而是把代碼倉庫完整地鏡像下來。 這麼一來,任何一處協同工作用的服務器發生故障,事後都可以用任何一個鏡像出來的本地倉庫恢復。 因爲每一次的克隆操作,實際上都是一次對代碼倉庫的完整備份。用戶在本地倉庫做版本控制,需要與其他用戶交互時才聯網push到服務器。

代表產品有Mercurial、Bazaar 、 Darcs 以及Git

分佈式版本控制系統功能強大,不可避免地增加了本地存儲空間的佔用,邏輯較爲複雜。

在這裏插入圖片描述

1.4 git的優缺點

優點:

  • 適合分佈式開發,強調個體。
  • 公共服務器壓力和數據量都不會太大。
  • 速度快、靈活。
  • 任意兩個開發者之間可以很容易的解決衝突。
  • 離線工作。

缺點:

  • 模式上比SVN更加複雜。
  • 代碼保密性差。

2 git相關術語

  1. 倉庫(Repository):受版本控制的所有文件修訂歷史的共享數據庫
  2. 工作空間(Workspace) :本地硬盤上的文件
  3. 工作樹/區(Working tree):工作區中包含了倉庫的工作文件
  4. 暫存區(Staging area):用來暫存Workspace文件commit之前的變化,通過git add命令添加到暫存區。
  5. 索引(Index):即暫存區
  6. 本地倉庫(Local Repository):本地完整的文件版本倉庫
  7. 歷史庫(History):即本地倉庫
  8. 遠程倉庫(Remote Repository):服務器的文件版本倉庫
  9. 跟蹤(track):將本地文件賦予git版本控制功能
  10. 簽出(Checkout):從倉庫中將文件的最新修訂版本複製到工作空間
  11. 提交(Commit):對各自文件的工作副本做了更改,並將這些更改提交到倉庫,提交可以是名詞,代表提交的倉庫版本
  12. 推送(Push):將本地倉庫的版本推送到遠程倉庫
  13. 衝突(Conflict):多人對同一文件的工作副本進行更改,並將這些更改提交到倉庫
  14. 分支(Branch):從主線上分離開的副本,默認分支叫master
  15. 頭(HEAD):頭是一個象徵性的參考,最常用以指向當前選擇的分支。
  16. 修訂(Revision):表示代碼的一個版本狀態。Git通過用SHA1 hash算法表示的ID來標識不同的版本。
  17. 標記(Tags):標記指的是某個分支某個特定時間點的狀態。通過標記,可以很方便的切換到標記時的狀態。
  18. 鎖(Lock):獲得修改文件的專有權限。

3 git配置

3.1 git三個配置文件

Git 自帶一個 git config 的工具來幫助設置控制 Git 外觀和行爲的配置變量。 這些變量存儲在三個不同的位置,分別代表三個不同級別的配置,系統配置、用戶配置、當前倉庫配置:

  • /etc/gitconfig 文件: (windows系統該文件在git安裝目錄/Git/mingw64/etc/gitconfig),包含系統上每一個用戶及他們倉庫的通用配置。 如果使用帶有 --system 選項的 git config 時,它會從此文件讀寫配置變量。例如,打開git bash工具,鍵入:

    git config --system user.name 張三
    
  • ~/.gitconfig~/.config/git/config 文件:(windows系統該文件在用戶目錄/gitconfig),只針對當前用戶。 可以傳遞 --global 選項讓 Git 讀寫此文件。

    git config --global user.name 張三
    
  • 當前使用倉庫的 Git 目錄中的 config 文件(就是 .git/config):針對該倉庫。

    git config --local user.name 張三
    

當三個配置文件有配置項重複時,每一個級別覆蓋上一級別的配置,當前倉庫配置覆蓋用戶配置,用戶配置覆蓋系統配置。

*git bash是個shell命令工具,可以在windows上敲各種bash shell命令,還可以使用vim哦

相關命令

查看所有配置項(相同配置項按文件級別覆蓋):

git config -l

查看指定配置項(以用戶名爲例,下同)

git config --get user.name

查看配置項,使用正則表達式匹配

git config --get-regexp user.*

刪除配置項

git config [--local|--global|--system] --unset user.name

爲git命令設置別名

git config [--local|--global|--system] alias.ci commit #用ci代替commit

更多用法鍵入git config會顯示help

3.2 .gitignore文件

在工作空間中有些文件不需要納入git版本控制,比如編譯生成的.class文件,IDE相關的文件(.ipr、.idea、.setting等)、數據庫相關文件等等。

此時可以在主目錄下建立".gitignore"文件,然後在裏面配置需要忽略的文件,文件內容規則如下圖:

在這裏插入圖片描述

.gitignore文件定義的文件將不受git版本控制管理,執行git add .時這些忽略的文件不會添加到暫存區。

4 git文件操作

4.1 git工作原理

在進行提交操作時,Git 會保存一個提交對象(commit object)。使用git log可以查看每一個commit object的對象信息。

Git會在暫存操作時使用SHA-1哈希算法爲每一個要暫存文件計算校驗和,然後會把當前版本的文件快照保存到 Git 倉庫中(Git 使用 blob 對象來保存它們),最終將校驗和加入到暫存區域等待提交。

當使用 git commit 進行提交操作時,Git 會先計算每一個子目錄(本例中只有項目根目錄)的校驗和,然後在 Git 倉庫中這些校驗和保存爲樹對象。 隨後,Git 便會創建一個提交對象,它除了包含上面提到的那些信息外,還包含指向這個樹對象(項目根目錄)的指針。如此一來,Git 就可以在需要的時候重現此次保存的快照。

提交完成後,Git 倉庫中有五個對象:三個 blob 對象(保存着文件快照)、一個樹對象(記錄着目錄結構和 blob 對象索引)以及一個提交對象(包含着指向前述樹對象的指針和所有提交信息)。

4.2 git工作區

Git本地有三個工作區域:工作目錄(Workspace)、暫存區(Stage/Index)、本地資源庫(Repository或History)。加上遠程的git倉庫(Remote Repository)一共四個工作區域。文件在這四個區域之間的轉換關係如下:

在這裏插入圖片描述

4.3 git文件狀態

根據文件保存到工作區的不同,就有四種文件狀態:

  • Untracked: 未跟蹤,此文件不受git版本控制. 通過git add filename命令狀態變爲Staged,通過git clean -df filename命令可刪除未跟蹤文件。
  • Unmodify: 文件已經入庫, 未修改, 即版本庫中的文件快照內容與文件夾中完全一致. 這種類型的文件有兩種去處, 如果它被修改, 而變爲Modified. 如果使用git rm移出版本庫, 則成爲Untracked文件
  • Modified: 文件已修改, 僅僅是修改, 並沒有進行其他的操作. 這個文件也有兩個去處, 通過git add可進入暫存staged狀態, 使用git checkout 則丟棄修改過, 返回到unmodify狀態, 這個git checkout即從庫中取出文件, 覆蓋當前修改
  • Staged: 暫存狀態. 執行git commit則將修改同步到庫中, 這時庫中的文件和本地文件又變爲一致, 文件爲Unmodify狀態. 執行git reset HEAD filename取消暫存, 文件狀態爲Modified

四種狀態的轉換如下圖:

在這裏插入圖片描述

使用git status命令查看文件狀態。

4.4 git文件操作命令

  1. init:在當前目錄初始化一個版本庫,會生成.git文件夾。之後可以關聯遠程分支

    #初始化版本庫
    $ git init
    
  2. clone:克隆遠程倉庫到本地,完成之後工作區文件狀態都是Unmodified

    #克隆遠程倉庫到本地
    $ git clone https://github.com/yozzs/xxx.git
    
  3. add:將untracked或modefied狀態的文件添加到暫存區

    # 添加指定文件到暫存區
    $ git add [file1] [file2] ...
    
    # 添加指定目錄到暫存區,包括子目錄
    $ git add [dir]
    
    # 添加當前目錄的所有文件到暫存區
    $ git add .
    
  4. commit:將暫存區或工作空間(-a)提交到本地倉庫

    # 提交暫存區到倉庫區,message是提交的信息,用戶自己寫。如果不用-m選項,則會跳轉到vi頁面編寫提交信息,寫完:wq保存退出,如果不寫提交信息直接退出則提交失敗
    $ git commit -m [message]
    
    # 提交暫存區的指定文件到倉庫區,在分支衝突的狀態下不能指定文件提交
    $ git commit [file1] [file2] ... -m [message]
    
    # 提交工作區自上次commit之後的變化,直接到倉庫區,跳過add,對新文件無效
    $ git commit -a
    
    # 提交時顯示所有diff信息
    $ git commit -v
    
    # 使用一次新的commit,替代上一次提交,如果代碼沒有任何新變化,則用來改寫上一次commit的提交信息
    $ git commit --amend -m [message]
    
    # 重做上一次commit,幷包括指定文件的新變化
    $ git commit --amend [file1] [file2] ...
    
  5. revert:撤銷提交

    # 把指定的提交的所有修改回滾,並同時生成一個新的提交
    $ git revert <commit-id>
    
  6. push:將指定本地分支推送到指定的遠程主機

    # 上傳本地指定分支到遠程倉庫,remote默認爲origin
    $ git push [remote] [localbranch]:[remotebranch]
    
    # 強行推送當前分支到遠程倉庫,即使有衝突
    $ git push [remote] --force
    
    # 推送所有分支到遠程倉庫
    $ git push [remote] --all
    
  7. pull:拉取遠程倉庫的版本,並與本地分支合併,可以理解爲git fetch+git merge

    # 拉取遠程倉庫指定分支的變化,並與指定本地分支合併,remote爲遠程主機名,默認origin
    $ git pull [remote] [remotebranch]:[localbranch]
    
    # 如果合併到當前分支,省略本地分支名
    $ git pull [remote] [remotebranch]
    
    # 如果當前分支已指定追蹤遠程分支,可省略遠程分支名
    $ git pull [remote] 
    
    # 如果當前分支只有一個追蹤分支,連遠程主機名都可以省略
    $ git pull
    

    注意,分支推送順序的寫法是<來源地>:<目的地>,所以git pull是<遠程分支>:<本地分支>,而git push是<本地分支>:<遠程分支>。

  8. fetch:獲取遠程倉庫的變動到本地倉庫,不合並本地分支

    # 獲取遠程倉庫所有更新,但不自動合併當前分支
    $ git fetch [remote]
    
  9. remote:操作遠程倉庫

    # 簡單查看單個倉庫名
    $ git remote
    
    # 顯示所有遠程倉庫
    $ git remote -v
    
    # 顯示某個遠程倉庫的信息
    $ git remote show [remote]
    
    # 增加一個新的遠程倉庫,並命名
    $ git remote add [shortname] [url]
    
    # 修改遠程倉庫
    $ git remote rename [oldname] [newname]
    
    # 刪除遠程倉庫
    $ git remote rm [remote-name]
    
  10. log:查看提交日誌,會vi進入log文件。會顯示每一次提交的commit_id、分支、作者、日期信息。

       # 查看提交記錄
       $ git log  #可通過管道和其他shell命令操作,獲得想要的統計結果
       
       # 查看提交記錄,顯示最近5次提交
       $ git log -5
       
       # 以圖形化的方式顯示提交歷史的關係,可以直觀地看到分支合併情況
       $ git log --graph
       
       # 查看這個倉庫中所有的分支的所有更新記錄,包括已經撤銷的更新
       $ git reflog
    
  11. rm:刪除版本庫或暫存區的文件

    # 只刪除暫存區文件,工作空間和倉庫不變
    $ git rm --cached <file>
    
    # 刪除本地倉庫文件,會同時刪除工作空間和暫存區該文件
    $ git rm -f <file>
    
  12. clean:清理工作區未跟蹤狀態文件(不會清除.gitignore指定文件)

    # 刪除工作區未跟蹤狀態文件
    $ git clean -df  #-d表示包含目錄,-f表示強制清除
    
    # 刪除指定未跟蹤狀態文件
    $ git clean -f <file>
    
  13. reset:回退文件的本次修改,resetgit rm --cache的區別是前者重寫本地倉庫的版本,效果可以是回退添加或修改,後者是刪除暫存區文件。

    # 將本地倉庫指定文件的版本重寫到暫存區
    $ git reset HEAD <file> #HEAD表示HEAD指向的提交
    
    # 放棄工作區和index的改動,同時HEAD指針指向前一個commit對象,一個commit對象實際就是一個倉庫的版本。效果就是撤銷提交。HEAD~1也可以改爲HEAD~n,n表示前n個提交
    $ git reset --hard HEAD~1
    
    #功能同上,一個^表示前一次提交,^^表示前兩次提交
    $ git reset --hard HEAD^
    
    #將HEAD,index(暫存區)和workspace全部重置爲指定某次提交的目錄樹
    $ git reset --hard <commit_id>
    
    #只將HEAD重置爲指向指定某次提交的目錄樹,不重置工作區和暫存區
    $ git reset --soft <commit_id>
    
    #只將HEAD和index重置爲指向指定某次提交的目錄樹,不充值工作區
    $ git reset --mixed <commit_id>
    
  14. checkout:簽出,用暫存區或倉庫的目錄樹替換工作區目錄樹。會修改工作空間,所以很危險。但是也很常用。

    # 用暫存區目錄樹替換工作空間。此操作會刪除本地未暫存的modified文件,慎用
    $ git checkout .
    
    # 用暫存區目錄樹指定文件替換工作空間該文件。
    $ git checkout -- <file>
    
    # 用HEAD指向的分支(默認是master)倉庫目錄樹指定文件替換工作空間該文件。
    $ git checkout HEAD -- <file>
    
    # 檢出branch分支,更新HEAD以指向branch分支,然後用branch分支指向的樹指定文件替換工作空間該文件。
    $ git checkout <branch> -- <file>
    
    # 用某個提交(commit_id)目錄樹指定文件替換工作空間該文件。
    $ git checkout commit_id -- <file>
    
  15. diff:顯示WorkSpace中的文件和暫存區文件的差異,會顯示文件內容的差異

    # 比較工作空間和暫存區
    $ git diff [file]
    
    # 比較兩個提交對象的差異
    $ git diff <commit_id1> <commit_id2>
    
  16. ls-files:查看文件列表

    # 查看所有緩存的文件
    $ git ls-files
    
    # 查看所有未被跟蹤的文件,包括.gitignore的文件
    $ git ls-files -o
    
    # 查看modified狀態的文件
    $ git ls-files -modified
    
    # 查看暫存區的文件詳細信息
    $ git ls-files -s
    

4.5 文件操作命令示意圖

在這裏插入圖片描述

5 git分支

5.1 分支概念

Git 的分支模型是它的“必殺技特性”,也正因爲這一特性,使得 Git 從衆多版本控制系統中脫穎而出。git官網有一句介紹:Git 保存的不是文件的變化或者差異,而是一系列不同時刻的文件快照。這也正是git實現分支模型及分佈式版本控制的基石。

Git 分支,本質上僅僅是指向提交對象的可變指針。創建分支時就是在當前的提交上創建了一個新的可移動的指針。然後git有一個特殊的指針:HEAD,指向當前所在的本地分支。每一個分支指向一個提交對象。HEAD指針指向當前本地分支。我們所說的本地倉庫,實際上就是HEAD指針指向的本地分支所指向的提交對象。

由於 Git 的分支實質上僅是包含所指提交對象校驗和(長度爲 40 的 SHA-1 值字符串)的文件,所以它的創建和銷燬都異常高效。

5.2 分支操作

  1. 新建testing分支

    git branch testing
    

    在這裏插入圖片描述


  1. 切換到testing分支

    git checkout testing  
    

    在這裏插入圖片描述

​ 此時master分支和testing分支指向同一個提交,所以工作空間看起來並沒有變化。接下來修改工作空間文件,然後提交。

  1. 使用testing分支提交

    #修改文件後
    git commit -a -m testing分支提交
    

    在這裏插入圖片描述

    此時testing分支指針向新的提交對象前進,master分支還是指向原來的提交對象。

  2. 切回到master分支

    git checkout master
    

    在這裏插入圖片描述

    此時工作空間的文件會變爲master所指向的提交對象的狀態。

  3. master分支提交

    # 修改文件後
    git commit -a -m master分支提交
    

    在這裏插入圖片描述

    此時分支出現分叉,使用git log --graph命令可以圖形化(字符圖形)查看分支提交歷史。

  4. 分支合併

    #當前分支爲master
    git merge testing
    

    合併之後會將testing分支指向的commit object的修改內容添加到master指向的commit object,並生成一次新的提交。然後就可以刪除被合併的testing分支。

  5. 刪除分支

    git branch -d testing
    
  6. 發生衝突的合併

    如果合併的兩個分支都修改了同一份文件,git將無法成功完成合並生成一個新的提交,此時Git 會暫停下來,等待你去解決合併產生的衝突。分支狀態變爲合併中,衝突文件狀態變爲both modified。衝突將在下一節具體復現。

  7. 其他分支操作

    # 查看所有本地分支
    $ git branch
    
    # 查看所有遠程分支
    $ git branch -r
    
    # 查看所有本地和遠程分支
    $ git branch -a
    
    # 新建分支並將其指向某個提交對象
    $ git branch [branch] [commit_id]
    
    # 新建一個分支,與指定的遠程分支建立追蹤關係
    $ $ git branch --track [branch] [remote-branch]
    
    # 刪除本地分支,-D表示強制刪除
    $ git branch -d [branch] 
    
    # 查看所有本地分支
    $ git branch
    
    # 刪除遠程分支,remote表示遠程主機名,默認origin
    $ git push origin --delete [branch-name]
    $ git branch -dr [remote/branch]
    

5.3 合併衝突解決方案

前面說到如果合併的兩個分支都修改了同一份文件,合併會產生衝突。具體情景:

創建test1分支,在test1分支修改testconflict.txt文件並提交:

在這裏插入圖片描述

切換到master分支,master分支也修改testconflict.txt文件並提交,

然後合併master分支和test1分支,發生衝突

在這裏插入圖片描述

查看衝突文件,發現git有記錄衝突內容的格式。衝突文件狀態爲both modified,且分支狀態爲master|MERGING。解決衝突的方式是手動修改文件改正衝突內容後重新提交

在這裏插入圖片描述

重新提交。分支狀態變爲正常的master

在這裏插入圖片描述


git的分支是分佈式版本控制的核心概念,功能強大,也比較難以理解。可以查看官網資料學習,https://git-scm.com/book/en/v2

6 總結

作爲一套內容尋址文件系統,Git 不僅僅是一個版本控制系統,它同時是一個非常強大且易用的工具。git已經是開發人員必備技能,也是世界上最先進的分佈式版本控制系統,許多公司普遍使用基於git的代碼託管網站。有名的代碼託管網站有github、gitlab、bitbucket、gitee(碼雲)。各種git圖形化工具也是層出不窮,eclipse、idea等IDE軟件也都集成了git插件,但是使用圖形化工具的同時,也必須理解git命令及git版本控制原理。

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