接觸Git這麼久,談一談對Git以及相關事物的理解

1. Git的誕生以及相關歷史

1.1. Git的定義

​ Git 爲分佈式版本控制系統,是目前最早進的版本控制系統。javascript

思考:html

  1. 版本控制是啥意思?

    維基百科:java

    版本控制(英語:Version control)是維護工程藍圖的標準做法,能追蹤工程藍圖從誕生一直到定案的過程。此外,版本控制也是一種軟件工程技巧,藉此能在軟件開發的過程當中,確保由不一樣人所編輯的同一程序文件都獲得同步。git

    百度百科:程序員

    版本控制是指對軟件開發過程當中各類程序代碼、配置文件及說明文檔等文件變動的管理,是軟件配置管理的核心思想之一。github

    個人理解:版本控制是一種記錄一個或若干文件內容變化,以便未來查閱特定版本修訂狀況的系統。web

    通俗地說就是對一個或若干個文件的內容改動狀況按照特定的版本號進行保存,以便未來瀏覽者快速清晰瞭解文件的改動信息(內容變化信息,內容改動時間,做者等)算法

1.2. Git的創造者(爸爸)

​ 名稱:Linus Torvalds 林納斯 託瓦茲) 芬蘭人 現受聘于開放源代碼開發實驗(OSDL:Open Source Development Labs, Inc)數據庫

​ 自傳: 《樂者爲王》just for funvim

圖片加載失敗

1.3. 相關歷史
  • 1991年,Linus建立可謂統治服務器的操做系統-Linux系統,因爲它的快速發展Linux的代碼管理成爲一個大難題
  • 2002年之前,Linus其實都是經過手工方式合併世界各地開發者提交的源代碼
  • 2002年,名爲BitMover的這家公司出於人道主義精神免費提供BitKeeper商業版的版本控制系統的使用權
  • 2005年,但因爲Linux秀兒衆多,開發Samba的Andrew試圖破解BitKeeper的協議,被BitMover公司發現了,因而BitMover公司怒了,要收回Linux社區的無償使用權
  • 不讓用便本身搞一個,Linus便花費10天的時間用C語言開發了Git,日後時間,Linux的源碼都是用Git管理。
  • 2008年GitHub網站上線,爲開源的項目免費提供Git存儲。

2. 版本控制系統的分類與特徵

2.1 版本控制系統
  • 本地版本控制系統

    • 第一代版本控制系統被稱爲本地版本控制系統。經過加鎖將併發執行轉換成順序執行。 一次只能有一我的處理文件。具體流程以下:首先,應該把文件放在一個服務器上,方便使用者上傳或下載文件;其次,任何人想對文件修改時,須要先把這個文件加鎖,經過checkout指令,使得其餘人沒法修改;最後,當修改完成以後,須要釋放鎖,經過checkin指令,造成一個新的版本,存放到服務器端。第一代版本控制系統主要有 RCSRevision Control System )、SCCS。
    • 硬盤上(本地,local computer)保存補丁集(文件修訂先後的變化),經過全部的補丁,能夠計算出各個版本的文件內容,大多都是採用某種簡單的數據庫來記錄文件的歷次更新差別。

      圖片沒法加載

  • 集中式版本控制系統

    • 第二代版本控制系統被稱爲集中式版本控制系統(Centralized Version Control Systems,CVCS),其對同步修改更加寬容,但有一個明顯的限制,用戶必須在容許提交以前將當前修訂合併到他們的工做中。不便之處就是要聯網,若中央服務器發生單機故障,宕機了,那麼在這宕機期間誰都沒法提交更新,也就沒法協同工做,還有中央服務器丟失數據的可能等。
    • 由下圖可看到,在集中式版本控制系統中,若是服務器嗝屁了,那麼全部的開發者就只能乾瞪眼了!由於,SVN 對於項目的管理是依賴於服務器中的中心倉庫的!咱們的更改必需要提交到服務器中的中心倉庫。第二代版本控制系統主要有 CVSSubversion、SourceSafe、Team Foundation Server、SVK。

      圖片沒法加載

  • 分佈式版本控制系統

    • 第三代版本控制系統被稱爲分佈式式版本控制系統(Distributed Version Control Systems,DVCS),其容許合併和提交分開。在每一個使用者電腦上就有一個完整的數據倉庫,沒有網絡依然可使用。
    • 由下圖可看到,分佈式版本控制系統也能夠有個服務器端的倉庫,用來同步各開發者的私有倉庫。在分佈式版本控制系統中,每一個參與者的本地也會有一個完整的倉庫。及時服務器端崩潰,咱們仍然可使用 Git(僅在本地倉庫管理咱們的代碼),在網絡具有時,再和服務器進行同步便可!第三代版本控制系統主要有 Bazaar、Git、Mercurial、BitKeeper、Monotone。

圖片沒法加載

思考:

  1. 怎麼理解分佈式與集中式?(廖雪峯老師給出的理解)

    • 集中式:版本庫是集中存放在中央服務器的,而幹活的時候,用的都是本身的電腦,因此要先從中央服務器取得最新的版本,而後開始幹活,幹完活了,再把本身的活推送給中央服務器。中央服務器就比如是一個圖書館,你要改一本書,必須先從圖書館借出來,而後回到家本身改,改完了,再放回圖書館。
    • 分佈式:分佈式版本控制系統根本沒有「中央服務器」,每一個人的電腦上都是一個完整的版本庫,這樣,你工做的時候,就不須要聯網了,由於版本庫就在你本身的電腦上。
2.2 SVN與Git的對比

SVN的優缺點:

  • [優] 採用集中式,易於管理,保證安全性
  • [優] 管理方便,邏輯明確,理念符合常規思惟
  • [優] 代碼的一致性高,適合人數很少的項目開發
  • [優] 支持二進制文件,更容易處理大文件,支持空目錄
  • [優] 容許一個文件有任意多的可命名屬性,會關注全部的文件類型
  • [缺] 服務器壓力太大,數據庫容量暴增
  • [缺] 必須鏈接在服務器上,不然基本不能工做、提交、對比、還原等
  • [缺] 不適合開源開發

Git的優缺點:

  • [優] 適合分佈式開發,強調個體,公共的服務器壓力和數量都不會太大。
  • [優] 速度快, 成熟的架構,開發靈活;任意兩個開發者之間能夠很容易的解決衝突。
  • [優] 離線工做,管理代碼成本低,不須要依賴服務器。
  • [優] 部署方便。基本上下個命令就能夠用。
  • [優] 良好的分支機制,可讓主幹代碼保持乾淨。
  • [缺] 不符合常規思惟;資料少,學習成本比較大,學習週期比較長,要求人員素質比較高。
  • [缺] 代碼保密性差,一旦開發者把整個庫克隆下來就能夠徹底公開全部代碼和版本信息。

    SVN與Git的最主要的區別:

  • SVN的存儲須要依賴一個服務器,而git全部的東西是放在線上的。節約成本,省時省力。
  • git 是分佈式的,svn 不是。
  • git 按照源數據的方式存儲內容,svn 是按照文件的形式存儲。
  • git 和 svn 中的分支不一樣 。
  • git 沒有全局版本號,svn 有。
  • git 內容的完整性優於 svn。

SVN與GIT的特性對比:

特性 SVN GIT
架構模式 集中式 分佈式
安全性 較差,按期備份 高,開發者本地電腦就是一個完整的版本庫
適用性 文檔管理, 代碼管理,
易用性 簡單上手,對新手友好 上手困難,學習成本高但效率搞
靈活性 較低,易發生單點故障,拉取分支 高,單機本地操做,多個備份,本地新建分支
權限管理 擁有嚴格的權限管理 尚無嚴格權限管理,有帳號角色劃分
3. 代碼託管平臺
  • GitHub

    • GitHub是什麼?

      • 百度百科上的定義是:面向開源以及私有軟件項目的代碼託管平臺,只支持git 做爲惟一的版本庫格式進行託管,故名GitHub。
      • GitHub是一個代碼託管雲服務網站,幫助開發者存儲和管理其項目源代碼,且可以追蹤、記錄並控制用戶對其代碼的修改。甚至能夠把它看成存儲代碼等的網盤,用來存儲任何東西。
    • Github與Git的關係?

      • GitHub不等同於Git,兩者徹底是不一樣物,不能搞混,相似地,捋一捋java與javascript、周杰與周杰倫的關係,或許你能從中領悟到一些真諦。
      • Git只是一個命令行工具,一個分佈式版本控制系統。正是它在背後管理和跟蹤你的代碼歷史版本,比如一個時光機,讓你在代碼出錯時不至於手忙腳亂,能快速回退以前的歷史版本。
      • GitHub是一個代碼託管網站,背後使用Git做爲版本管理工具(而非svn)。主要服務是將你的項目代碼託管到雲服務器上,而非存儲在本身本地硬盤上。
    • GitHub能作什麼?

      • 託管代碼,管理項目的歷史版本
      • 查找查看開源項目的介紹及源碼等
      • 使用GitHub Pages更能,可以搭建屬於本身的我的博客
      • 分享技術心得、項目等,在線交流,提高本身的影響力
  • Gitlab

    • Gitlab是什麼?

      + GitLab 是一個用於倉庫管理系統的開源項目,使用Git做爲代碼管理工具,並在此基礎上搭建起來的web服務(在線代碼倉庫管理軟件)。
    • Gitlab與GitHub的區別?查看對比

      • GitHub上存放的項目是面向世界開源的,若想存放私人倉庫,得交錢,交錢使你的項目變得更隱私
      • GitHub是在線代碼倉庫,全世界只有GitHub一家,你們把代碼存儲在人家的服務器上
      • GitLab比較私密,用於企業、學校或者我的的代碼託管庫
      • Gitlab至關於小型的GitHub,你能夠在本地搭建一個屬於你本身的相似GitHub倉庫,讓小夥伴把代碼存儲在上面,這樣代碼只有大家幾我的能看見,可是你要存在GitHub上,全世界都能看見
    • Gitlab能爲咱們作什麼?

      • Git倉庫管理、代碼審查、問題跟蹤、動態訂閱、wiki等功能,GitHUb能作的Gitlab也能作(99%)。
  • 國內代碼託管平臺

4. Git的工做原理

​ 咱們使用Git來記錄每一次文件內容的變動,版本的更新,清晰地比較出不一樣版本的內容差別;可使用Git在項目的歷史版本自如地進行切換;還可使用Git從當前項目的更改中撤銷一些操做,能夠新建分支,合併分支甚相當聯遠程服務器倉庫等,這一切的背後都是怎麼實現的?瞭解Git的思想以及基本原理這些操做也就略知一二了。

4.1Git的分區
  • workspace: 工做區 直接編輯的地方,開發者可見具體的項目,能夠直接操做項目文件
  • index(stage): 暫存區 數據暫存的地方
  • repository: 本地倉庫 存放已提交的數據
  • remote: 遠程倉庫 在遠程服務器上存放本地倉庫的數據

    圖片沒法加載

4.2Git數據庫
  • Git本質上是一個內容尋址文件系統(就是根據文件內容的hash碼來定位文件。 這就意味着一樣內容的文件,在這個文件系統中會指向同一個位置,不會重複存儲。)Git 的核心部分是一個簡單的鍵值對數據庫,能夠向該數據庫插入任意類型的內容,它會返回一個鍵值,經過該鍵值能夠在任意時刻再次檢索(retrieve)該內容
  • Git 保存的不是文件的變化或者差別,而是一系列不一樣時刻的文件快照。在進行提交操做時,Git 會保存一個提交對象(commit object)。該提交對象會包含一個指向暫存內容快照的指針。 但不只僅是這樣,該提交對象還包含了做者的姓名和郵箱、提交時輸入的信息以及指向它的父對象的指針。
  • git經過一種安全散列算法1(SHA-1)能夠獲得任意文件的SHA-1哈希值(40位的字符),也就是commit ID,而後經過文件哈希值存取數據,存取的數據都位於objects目錄,SHA-1哈希值的前兩個字符做爲子目錄名稱,後 38 個字符則做爲子目錄內文件的名稱
  • Gi的數據存儲原理

    • Git對象

      • 數據對象(blob object) 存儲的是一個文件的具體內容
      • 樹對象(tree object) 存儲的文件的目錄,一大坨指針,指向子級tree,或者blob
      • 提交對象(commit object) 存儲做者信息,提交者信息,註釋,指向一個 big tree 的指針
      • 標籤對象(tag object)它包含一個標籤建立者信息、一個日期、一段註釋信息,以及一個指針。
  • Git的底層命令、高層命令

    • Git經常使用命令共有30多個,可運行git help查看;但Git總共有130多個命令,能夠經過git help -a查看,這些命令能夠分爲高層命令和底層命令,底層命令被設計成unix風格,不經常使用

      圖片沒法加載

      • 往Git數據庫存入數據
      • 往Git數據庫取出數據
      • 首次提交 testA.txt文件
      • 第二次提交,修改了test.txt文件內容
      • 第三次提交,增長一個新文件 testB.txt ,一個新目錄 lib ,lib 裏增長一個文件 testC.txt
      • 第四次提交,新建一個分支 branchB,而且在新分支中作了一次 commit
      • 第五次提交, 合併一分支
  • Git的引用(reference或refs)

    瀏覽完整的提交歷史,但爲了能遍歷那段歷史從而找到全部相關對象,須要記住最後提交的SHA-1值。咱們須要一個文件來保存 SHA-1 值,並給文件起一個簡單的名字,而後用這個名字指針來替代原始的 SHA-1 值。文件被稱爲「引用(references,或縮寫爲 refs)」,使用git branch (branchname) 這樣的命令時,Git 實際上會運行 update-ref 命令,取得當前所在分支最新提交對應的 SHA-1 值,並將其加入你想要建立的任何新引用中。

    • HEAD引用

      • 分支和標籤都是指向提交對象的指針,全部的本地分支都存儲在 git/refs/heads 目錄下,每個分支對應一個文件
      • Git 分支的本質:一個指向某一系列提交之首的指針或引用
    • 遠程引用

      • 若是你添加了一個遠程版本庫並對其執行過推送操做,Git 會記錄下最近一次推送操做時每個分支所對應的值,並保存在 refs/remotes 目錄下
    • 標籤引用

Git的對象模型

5. .git文件夾
  • .git下的文件夾

    • hooks 文件夾則存放項目的客戶端或服務端鉤子腳本
    • info 文件夾下的exclude文件包含項目全局忽略匹配模式,與.gitignore文件互補

      • exculd 文件
    • logs 保存全部更新的引用記錄

      • refs
      • HEAD # 最後一次的提交信息
    • objects 文件夾存儲着Git數據庫的全部內容,存儲全部Git的對象

      • info 記錄對象存儲的附加信息
      • pack 以壓縮形式(.pack)存儲許多對象的文件,附帶索引文件(.idx)以容許它們被隨機訪問
    • refs 文件夾存儲着全部分支指向各自提交對象的指針;本地分支,遠端分支,標籤等

      • heads 記錄commit分支的樹根

        • master 標識了本地項目中的master分支指向的當前commit的哈希值
      • remotes 記錄從遠程倉庫copy來的commit分支的樹根(只讀)

        • origin

          • HEAD
          • master 標識了遠端項目中的master分支指向的當前commit的哈希值。
      • tags 記錄任何對象名稱(不必定是提交對象或指向提交對象的標籤對象)
  • .git下的文件

    • HEAD 文件指向當前分支, 包含了一個分支的引用,經過這個文件Git能夠獲得下一次commit的parent,能夠理解爲指針
    • index 文件存儲着暫存區的內容信息
    • config 文件包含項目的配置信息
    • description 存儲着倉庫的描述信息,主要給gitweb等git託管系統使用
    • packed-refs 打包標頭和標籤以便高效的存儲庫訪問
    • FETCH_HEAD 是一個版本連接,指向着目前已經從遠程倉庫取下來的分支的末端版本
    • ORIG_HEAD 記錄的是在進行危險(drastic)操做(如合併merge,回退reset等)時,此操做以前HEAD所指向的位置,便於咱們在發生毀滅性失誤時進行回退
    • COMMIT_EDITMSG 保存最新的commit message,Git系統不會用到這個文件,只是給用戶一個參考

      image.png

6. Git的經常使用命令
  • 簡單命令

    圖片沒法加載

  • 高級命令

    • HEAD

      • 老是指向當前分支最新的一次提交commit
      • git diff HEAD 顯示工做區與當前最新commit之間的差別
    • commit

      • git commit --amend -m [message] 修改上一次提交
    • branch

      • git branch --track remote-branch 新建一個分支,與指定的遠程分支創建追蹤關係
      • git branch --set-upstream-to=origin/[remote branch] 將remote設置爲當前分支的上游分支
    • merge 合併指定分支

      • git merge branch 合併其餘分支到當前分支

        圖片加載失敗

    • rebase 衍合指定分支
      圖片沒法加載
    • reset 重置
    • revert 撤銷,回滾到指定的特定版本
    • cherry-pick 選擇合併某次提交的commit到當前分支
    • reflog 查看HEAD的全部移動軌跡

思考:

git merge 與 git rebase 的區別是?

  • rebase會合並該分支與其餘分支的commit history,可能會獲得一個新的commit history
  • rebase獲得更簡潔的項目歷史,去掉了merge commi,若是合併出現代碼問題不容易定位,由於re-write了commit history
  • merge會建立新的commit,包括每一個分支的commit 詳情
  • 每次merge會自動產生一個merge commit,特別是commit比較頻繁時,看到分支很雜亂。
  • 想要獲得一個乾淨的,沒有merge commit的線性commit歷史記錄,選擇git rebase
  • 想要獲得一個完整的commit歷史記錄,且想避重寫commit歷史記錄的風險,選擇git merge

git reset 與 git rebase的區別?

  • git revert會生成一個新的提交來撤銷某次提交,這次提交以前的commit都會被保留,也就是說對於項目的版本歷史來講是往前走的。
  • git reset 則是回到某次提交,相似於穿越時空。
7. Git Flow
  • gitflow工做流約定使用的分支簡介

    • master分支爲項目的核心分支,也是最終對外發布的分支,惟一且穩定。僅提供可讀,不可在該分支上直接修改代
    • develop分支是項目的開發主幹分支,惟一。僅提供可讀,不可在該分支上直接修改代碼。新功能的開發需從該分支拉取新的分支展開。develop分支應該包含項目完整的所有歷史記錄。
    • featrue分支項是目的需求開發分支,可多個,從develop分支或其餘featrue分支拉取。程序員的多人分工協做即經過featrue來實現,是代碼具體實現的一線程序員接觸最多的分支。需求開發完成後,要合併回develop分支。
    • release分支爲預發佈分支,一般被叫作測試分支,主要用於開發階段的測試及bug修復。當feature分支開發完畢後會合併回develop分支,而後再從develop分支拉取release分支提測。測試並修復後的release分支要合併回develop分支以及master分支,並打上合適的tag標記(包含必要的releaseNote)。
    • hotfix分支爲緊急線上修復分支,即當對外發布的master分支出現重大bug,影響線上使用時,從master分支拉取hotfix分支進行緊急修復。修復後的hotfix分支要合併回master分支和develop分支。

      圖片沒法加載

  • GitFlow工做流程

    圖片沒法加載

首先,完成中央倉庫的初始化,將新項目搭建起框架後的工程代碼或要轉gitflow的項目代碼上傳至git中央倉庫。項目負責人克隆中央倉庫到本地造成master分支,並拉取develop分支(步驟①)推送至服務器。通常的實際場景,開發團隊中只有項目負責人有權限操做master分支,拉取develop分支,並將develop分支的代碼合併到master分支中。

  而後,開發團隊中的其餘人克隆中央倉庫的develop分支到本地,造成全體成員統一的惟一的develop分支軌跡。以後,按照需求及成員各自的分工,各個成員能夠從develop分支拉取出各自的featrue分支(步驟②)進行獨立的開發;若涉及到多人合做開發同一分支,拉取的分支要及時推送至服務器,便於各成員共享。

  當各成員完成各自的功能開發後,需將完成後的代碼提交到featrue分支,而後合併到develop分支(步驟③)。代碼合併後,featrue分支能夠再也不保留。

  功能累積足夠且穩定或到達約定的提測週期時,項目負責人應當從develop分支拉取出release分支(步驟④),打包提交相應的版本給測試人員進行部署測試,測試中提交的bug所有在該release分支完成修改。

  測試結束並完成bug修復後,release分支應該合併回develop分支和master分支(步驟⑤),代碼合併後,release分支能夠再也不保留。合併後的master分支,應由項目負責人及時推送到中央倉庫(步驟⑥)。同時全體成員要及時同步本身develop分支。

  有上線需求時,直接從master分支打包提交應用版本進行部署。當線上版本出現重大bug,項目負責人需從master分支拉取hotfix分支(步驟⑦),進行線上的緊急修復。

  最後,修復後的hotfix分支要合併回develop分支和master分支(步驟⑧)。並推送到中央倉庫(步驟⑨)。

8. 實踐操做
  • 獲取Git倉庫

    • 現有文件目錄使用git init初始化倉庫
    • 從遠程服務器上克隆git clone一個倉庫
  • 合併其它分支的代碼

    • git merge
    • git rebase
  • 撤銷合併merge/rebase

    • git reset --hard [commit] 工做區、暫存區撤回到制定的commit版本
    • git reset --merge [commit] 或者 git reset --merge HEAD^ 撤回到合併前的commit
  • 修改某次的commit

    • git commit -amend -m 'comment' 替換上一次的commit
    • git rebase -i HEAD~[數字n] 進入vim編輯模式,並顯示最近n條最新的commit記錄
  • 撤銷某次的commit

    • git revert HEAD 產生新一次commit來抵消上一次提交
    • git revert commit_id 撤銷中間某次commit
    • git revert -m commit_id 撤銷其餘分支合過來的commit
    • git revert --no-commit commit1..commit5 撤銷commit1(不包括)至commit5之間的連續commit

      git revert的參數:

      --no-edit:執行時不打開默認編輯器,直接使用 Git 自動生成的提交信息。

      --no-commit:只抵消暫存區和工做區的文件變化,不產生新的提交。

  • 丟棄某次commit

    • git reset [last good SHA] 丟棄掉某個提交以後的全部提交,在提交歷史中完全消失
    • git reset --hard [last good SHA] --hard參數可讓工做區裏面的文件也回到之前的狀態
  • 查看提交歷史記錄

    • git log
  • 查看文件的改動

    • git diff 對比工做區與暫存區的同文件, 未添加至暫存區的文件改動
    • git diff --staged/cached查看添加至暫存區全部文件的內容修改
    • git state 顯示工做目錄和暫存區的狀態
  • 暫存文件的改動

    • git stash 臨時保存和恢復工做區文件的改動
  • 撤銷文件的改動

    • `
      git checkout -- [filename]
      `
  • 撤銷暫存區的文件

    • git rm --cache [filename]

Git深刻學習連接:
相關文章
相關標籤/搜索