Git概念及工作原理總結

I'm the one.發表於2020-11-25

Git是分散式版本控制系統。Github和華為等均使用Git作為程式碼管理工具。之前在工作中比較常用到的是克隆、程式碼提交拉取、解決回合衝突、程式碼回滾等。在實際的工作中,可能回合時衝突及版本回退的情況較多,下文將著重介紹這兩點。本文不涉及Git的安裝等,主要以介紹概念及原理為主。
個人感覺使用Idea內建的git比通過Git Bash使用Git命令要方便且易操作。

一、Git基本概念

  1. 工作拷貝(工作目錄):用於存放產品開發資料本地工作目錄。
  2. 索引(Index):用於存放待提交資料的快取區。
  3. 本地庫:遠端庫的一個完整的拷貝,包括所有檔案的修改記錄,分支等。
  4. 遠端庫:本地庫clone來源。
  5. 中心庫:遠端庫的一種,公司級存放某個專案所有產品資料的倉庫。
  6. 快照(snapshot):版本庫某個時間點所有檔案集合。
  7. 全球版本號(commitID):Git庫的版本號是用過SHA-1演算法根據庫中的所有內容計算出一個40位的雜湊值,這個雜湊值是全球唯一的,基本只要前六位就可以唯一標識了。
  8. 檔案狀態介紹
    1. Untracked files:未被跟蹤的檔案,一般指新新增的檔案。
    2. Change not staged for commit:已修改的檔案,包括modified和deleted狀態。
    3. Change to be commit:已緩衝的檔案,即已add的檔案,包括modified、deleted和new file狀態。
    4. Nothing to commit:已提交的檔案,即已commit的檔案。

二、Git概念及基本操作詳解

Git分為工作區、暫存區、本地倉庫和遠端分支。
在這裡插入圖片描述
1、工作區:本地電腦上的某專案工程的程式碼資料夾就是工作區。
2、暫存區:工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。Git的版本庫裡存了很多的東西,其中最重要的就是成為stage(或者叫index)的暫存區,還有Git為我們自動建立的第一個分支master,以及指向master的一個指標叫HEAD。
在這裡插入圖片描述
我們把檔案往Git版本庫裡新增的時候是分兩步執行的;
第一步是用git add把檔案新增進去,實際上就是把檔案修改新增到暫存區;
在這裡插入圖片描述
第二步:是用git commit提交更改,實際上就是把暫存區的所有內容提交到本地倉庫。
在這裡插入圖片描述
需要提交的檔案修改統統放到暫存區,然後一次性提交暫存區的所有修改。
3、本地倉庫
本地倉庫就是上圖的本地版本庫,克隆自遠端倉庫。從下圖可以看到,工作區、暫存區、本地倉庫都是在本地計算機上的。
4、遠端分支
git push命令能將本地倉庫的程式碼上傳到遠端分支,但是必須經過committer確認之後才能合入遠端分支。託管在網路上的專案倉庫,Git的遠端倉庫是分散式的,能夠極大保證程式碼的安全性。

三、使用Git clone專案庫的兩種方式

  1. 命令列克隆($git clone +程式碼庫地址)
  2. 小烏龜(TortoiseGit)克隆
    1. 使用命令列clone程式碼
    1. 第一步:複製程式碼庫地址——copy Address
    2. 第二步:開啟Git Bash,輸入: git clone +程式碼庫地址
    2. 第二步:開啟Git Bash,輸入: git clone +程式碼庫地址
    1. 第一步:複製程式碼庫地址。
    2. 第二步:開啟想要克隆到的本地資料夾,右鍵單擊,選擇“git clone”命令。
    3. 第三步:配置好複製地址及目標地址,點選OK即可。

四、合併衝突

因為自己的遠端fork庫一般只有自己一個分支(master),即一個人一個倉,所以在自己名下的程式碼庫基本不會產生衝突。目前產生合併衝突只有兩種可能性。
1、原生程式碼進行了一些修改,遠端fork庫同步了遠端中心庫(Merge),然後本地clone庫從遠端fork庫更新程式碼(pull)。
在這裡插入圖片描述
2、原生程式碼進行了一些修改,併成功push到遠端fork庫。但是合入遠端中心庫時,因為其他人比你先合了程式碼,你的fork庫並沒有拉取到這個更改。因此在ISource上請求合併時,如果你們更改了同樣的程式碼,就會提示,存在衝突,無法發起合併請求。
在這裡插入圖片描述

五、程式碼回滾

git reset和git revert都用來撤銷程式碼倉庫中某些更改。
git reset在原生程式碼庫,add或commit以後發現提交的程式碼有問題,刪除自己個人分支上還沒合入主線的提交。用於個人庫。
顧名思義,重置分支,將當前的分支重設(reset)到指定的或者HEAD(如果不顯示指定commit)預設是HEAD,即最新的一次提交。有三個引數可供選擇。
1、–hard
快取區和工作區都同步到你指定的提交,重置檔案索引,自指定提交以來在工作區中的任何改變都被丟棄,並將版本庫重置為指定提交(commit)。
2、–mixed
快取區同步到你指定的提交,重置檔案索引,但是程式碼的改動仍留在工作區中,不會被丟棄。並將版本庫重置為指定提交(commit)。
3、–soft
工作區、快取區、檔案索引都不會改變,僅僅將版本庫重置為指定提交(commit)。
其作用域如下圖所示:
在這裡插入圖片描述
git revert 程式碼已經push上庫,同時回滾本地和線上程式碼到指定版本,用一個新提交來消除一個歷史提交所做的任何修改。用於版本庫。
1、如果已經push到遠端fork庫,reset刪除指定commit以後,gitpush可能導致一大堆衝突,但是revert並不會。
2、reset是在正常的commit歷史中,刪除了指定的commit,這是HEAD是向後移動了,而revert是在正常的commit歷史中再commit一次,只不過是反向提交,他的HEAD是一直向前的。
3、git revert也有可能會重寫檔案。所以,Git會在你執行revert之前要求你提交或者快取你工作目錄中的更改。
六、Git基本語法

語法功能說明
git clone克隆版本庫
git pull拉回遠端版本庫的提交
git push推送至遠端版本庫
git add新增至暫存區
git add -interactive互動式新增
git apply應用補丁
git am應用郵箱格式補丁
git annotate同義詞,等同於git blame
git bisect二分查詢
git blame檔案逐行追溯
git blame +檔名顯示檔案的每一行是在哪個版本最後修改
git branch分支管理
git cat -file版本庫物件研究工具
git checkout檢出到工作區,切換或建立分支
git cherry -pick提交揀選
git citool圖形化提交,相當於git gui命令
git clean清除工作區未跟蹤檔案
git commit提交
git config查詢和修改配置
git describe通過里程碑直觀地顯示提交ID
git diff差異比較
git difftool呼叫圖形化差異比較工具
git fetch獲取遠端版本庫的提交
git format -patch建立郵箱格式的補丁工具
git grep檔案內容搜尋定位工具
git gui基於cl/TK的圖形化工具,側重提交等操作
git help幫助
git init版本庫初始化
git init -db同義詞,等同於git init
git log顯示提交日誌
git log - - pretty = oneline顯示每個版本都修改了哪些檔案與git show (commit id),不過每個修改版本都包含了
git merge分支合併
git mergetool圖形化衝突解決
git mv重新命名
git push origin HEAD --force回退個人遠端
git rebase分支變基
git rebase -interactive互動式分支變基
git reflog分支等引用變更記錄管理
git repo -config同義詞,等同於git config
git reset重置改變分支,“遊標”指向
git reset --softcommitID原生程式碼回退到某一版本
git rev -parse將各種引用表示法轉換為雜湊值等
git revert反轉提交
git rm刪除檔案
git show顯示各種型別的物件
git show (commit id)顯示某個版本的修改詳情
git show +檔名顯示某個版本的某個檔案修改情況
git stage同義詞,等同於git add
git stash儲存和恢復進度
git status顯示工作區檔案狀態
git tag里程碑管理
git whatchanged +檔名顯示某個檔案的每個版本提交資訊,提交日期,提交人員,版本號,提交備註(沒有修改細節)

七、Git基本操作

1、配置基本資訊

  $git config --global user.name XXX

  $git config --global user.email XXX

2、克隆中心庫到本地

  $ git clone +中心庫地址

3、新增和修改檔名

  $ git add +檔名

  注:將需要新增的檔案拷貝到工作目錄或直接建立,此操作只是將需要新增的檔案轉移至快取
  區,如果需快取當前目錄下的所有非受控檔案,則可以通過“git add.”命令來完成已在快取區但
  不需提交的檔案怎麼辦?

  $echo “first” >>>first

  $git add first

  提交:$git commit

  注:此操作是將所有快取區的修改提交到本地版本庫

在這裡插入圖片描述
4、取消已快取的修改(回退)

(1)$ git rest -hard HEAD+檔名

(2)$ git rest HEAD+檔名

 注:此操作將修改的檔案從緩衝區內刪除,不影響本地內容

5、刪除檔案

 $ git rm 檔名

 注:此操作只是刪除檔案並將刪除的資訊轉移至快取區,要想刪除庫上的檔案需要執行commit操
 作,同樣適用git reset恢復

 eg: $ git rm second

 $ git commit

6、取消本地檔案的修改,包括刪除的檔案

(1)$ git checkout(HEAD/commitID)

 注:此操作將取消本地檔案(未提交)已做的但未提交的修改,如果需回退當前目錄下的所有修改
 檔案,則可以通過“git checkout .”命令來完成各成。

 eg:$ git checkout -first

 (2) $ git clean -f

 注:清除本地未被跟蹤的所有檔案,使用時需要注意是否確定需要清除

7、重新命名檔案或目錄

  $ git mv 原檔名 新檔名

  注:重新命名或者移動本地檔案或目錄,mv後直接到快取區,需要執行commit操作

  eg:$ git mv first first_new

8、檢視檔案狀態

 注:檢視本地庫中所有檔案的狀態,包括未受控的、已修改、已快取。衝突檔案的狀態也表現為已
 修改的。

9、比較檔案

 $ git diff OldcommitID NewcommitID(前6位)

 注:比較檔案/目錄下所有檔案修改前後的不同,不加CommitID,則比較本地的與快取或快取的與
 庫中最新的。

 新新增的檔案使用git diff的時候不能顯示

 git diff和 git diff -cached的不同

10、檢視修改日誌

    $ gitk --all

   注:此操作將調出git日誌的圖形化介面,在相關的版本號上右擊選擇“Create new branch”
   來建立基於此項的新分支,需要執行Xming

   $ git log

   注:在命令列中檢視log資訊

   注意:檢視日誌資訊只能看到本地的修改日誌和已經獲取到本地的遠端修改日誌,不能看到遠端
   還沒有獲取到本地的修改日誌。

11、建立私有分支

   $ git branch 分支名 commitID

   $ git checkout -b 分支名 commitID

   注:此操作是基於commitID即某一個全球版本號拉出新分支,如果沒有則基於當前分支的HEAD
   拉出新分支。$ git checkout -b +分支名 commitID=$ git branch 分支名commitID +
   $ git checkout 分支名

12、合併分支

    (1)直接合並$ git merge +分支名

      注:此操作是將“分支名”指示的分支合併到當前所在的分支,所以合併前必須切換到目標
      分支。

    (2)揀選合併 $ git cherry -pick commitID

      注:將某次特定提交合併到當前分支,首先合併前必須切換到目標分支。

13、檢視分支

   $ git branch

  注:檢視當前git庫中的所有分支,“-r”是檢視git庫中對應的遠端分支參照。

14、檢查分支是否合併到當前分支

   $ git branch -mergerd

  注:檢視已經合併到當前分支的所有分支。

  $ git branch -no -merged

 注:檢視還沒有合併到當前分支的所有分支。

15、刪除私有分支

   $ git branch -d/-D 分支名

   注:此操作“-d”刪除分支前會檢查分支中的內容是否都已經合併到其他分支,如果 沒有,則命
   令不執行;“-D”不進行檢查,直接刪除分支。

16、重新命名分支

    $ git branch -m oldbranch newbranch

   注:此操作是將“oldbranch”分支的名稱改成“newbranch”。如果需要拉出分株,並同時切換到
   新分支可以用“git checkout -b branch1 branch2”。

17、上傳修改到遠端(fork)庫

   $ git push 遠端庫名稱 本地分支名稱:遠端分支名稱

   注:此操作是將本地庫的修改同步到中心庫,如果本地分支的名稱和遠端分支的名稱相同,則遠
   程分支名稱可忽略。

   eg:$ git push origin new :new -br

18、更新當前模組

    $ git fetch 遠端庫名稱(獲取遠端庫的更新到本地庫)

    $ git fetch origin

    $ git merge 遠端庫名稱/分支名稱(將中心庫的更新合併到本地工作目錄中)

    $ git merge origin/new -br

19、修改提交資訊

   $git commit -m “新的提交資訊” -amend

   注:此操作只能修改最新的一次提交,之前的提交無法修改。

20、回退某一歷史版本,然後提交到本地庫

    $ git revert 全球版本號

   注:此操作將回退記錄到歷史的某一節點,並作為一次新的提交到庫中。

21、暫存本地修改

    $ git stash

    注:此操作是將本地未提交的修改暫存起來,並將檔案狀態恢復到HEAD,如果要恢復暫存的修
    改,執行“ git stash pop”即可,非常適合臨時插入的緊急bug修改。

22、二分法定位錯誤

   $ git bisect start

   $ git bisect bad CommitID

   $ git bisect good CommitID

   注:此操作用於定位問題引入的點,輸入如上命令後,git會自動切換到中間的狀態,經過測試
   輸入測試結果“git bisect good/bad”,重複以上,直接定位出出錯的提交,然後通過
   “git bisect reset”退出。

23、解決衝突

   合併分支或者合併庫上的更新到本地均會產生衝突。Git的衝突產生是由於同一檔案的同一行
   內容。

   哪些情況會出現衝突:1.修改了同一個檔案的同一行;2.檔案被重新命名為不同的名字;3.在一個
   分支上檔案被刪除在另一個分支上該檔案被修改。

24、變基

   $ git rebase 目標分支 原分支

   注:此操作將原分支變基到目標分支HEAD上。

在這裡插入圖片描述
從主專案pull拉最新程式碼到本地,如果有衝突在本地解決衝突的成本比在合併的時候再解決要低很多,所以建議在合併到主專案之前,先pull一下主專案的最新程式碼後在提交合並請求。在這裡,你可以用“pull”命令把“origin”分支上的修改拉下來,並且和你的修改合併,結果看起來就像一個新的“合併的提交”(merge commit)。但是,如果你想讓“mywork”分支歷史看起來像沒有經歷過任何合併一樣,你也許可以用 git rebase。

  $ git checkout mywork

  $ git rebase origin

 這些命令會把你的“mywork”分支裡的每個提交(commit)取消掉,並且把它們臨時儲存為補
 丁(patch)(這些補丁放到“git / rebase”目錄中),然後把“mywork”分支更新到最新的
 “origin”分支,最後把儲存的這些補丁應用到“mywork”分支上。

24、忽略某些檔案

   在git倉工作的根目錄下面,建立gitignore檔案,檔案內容如下例項,同樣gitignore檔案也
   可以上傳到庫上,這樣每次下載都可以記錄忽略規則,如果將某個已經忽略的檔案新增,使用
   $ git add -f檔名即可。

   * .a #忽略所有.a結尾的檔案

   ! lib.a #但lib.a除外

   /TODO #僅僅忽略專案根目錄下的TODO檔案,不包括subdir/TODO

   build/ #忽略build/目錄下的所有檔案

   doc/*.txt #會忽略build/目錄下的所有檔案

   doc/*.txt #會忽略doc/notes.txt但不包括 doc/server/arch.txt

25、使用GUI圖形化操作介面

   $ git gui

   新增修改,刪除檔案時,可以直接通過“git gui”命令,調出圖形介面,通過“stage changed”
   快取檔案(新新增的檔案只能通過git add命令快取),在提交資訊處輸入“提交資訊”,然後
   通過“commit” 提交。