?Welcome to 9ilk's Code World
? ? ? ?
(??? ? ???)?個人主頁:? ? ? ?9ilk
(??? ? ???)?文章專欄:? ? ?Git?
本篇我們來初步認識Git企業級應用是什么,有什么用以及Git基本操作。
🏠 初始Git
提出問題
? ?在日常生活中,我們進行軟件開發或日常文檔維護,可能遇到以下問題:我們對文檔進行多次修改,形成多個版本v1 v2 v3 v4... 長此以往我們的文檔副本越來越多,每個版本都有各自內容,但最終只有一份會被我們采用,但我們想從不同版本汲取優點,面對這么多版本,我們是不清楚之前的每個版本的修改內容的,這并不方便我們進行維護,影響我們的開發效率。有什么解決方案嗎?
解決方案
? ? 面對上面的問題,我們急需一個能記錄每次修改以及版本迭代的管理系統,這就需要引出版本控制器的概念,我們的Git就是當前主流的版本控制器。版本控制器,通俗講就是能讓你了解到一個文件的歷史,以及它的發展過程的系統,即一個可以記錄工程的每一次改動和版本迭代的管理系統,同時也方便多人協同作業。
? ? 我們的主角Git是當前最主流的版本控制器,它可以控制電腦上所有格式的文件,例如doc execl dwg dgn等等。對于我們開發人員來說,Git最重要的就是可以幫助我們管理軟件開發項目中的源代碼文件!
🏠 Git 安裝
Centos:
git --version
sudo yum install git -y
Ubuntu:
sudo apt-get remove git -y
git --version
sudo apt-get install git -y
🏠 Git基本操作
本地倉庫創建
如果想使用Git管理文件,我們必須把這些文件放在Git倉庫中,倉庫是進?版本控制的?個?件?錄。我們要想對?件進?版本控制,就必須先創建?個倉庫出來
先創建一個目錄做測試:
mkdir gitcode
創建Git本地倉庫(注意命令要在?件?錄下執行):
git init
當創建成功我們可以看到以下提示:
使用ls -a 命令我們發現,我們當前目錄下多了個.git的隱藏目錄,它是Git用來跟蹤管理倉庫的,不要手動修改這個目錄里面的文件,不然亂改會把Git倉庫給破壞了
本地倉庫配置
將本地倉庫創建好之后,我們最好對兩個配置項email name進行配置。
git config [--global] user.name "Your Name"
git config [--global] user.email "email@example.com"
# 把 Your Name 改成你的昵稱
# 把 email@example.com 改成郵箱的格式,只要格式正確即可
- --global是一個可選項,如果使用該選項,表示這臺機器上所有的Git倉庫都會使用這個配置。如果你希望在不同倉庫中使用不同的name或e-mail,可以不要--global選項,但注意的是,執行命令時必須要在倉庫里。
查看配置:
git config -l
重置某個配置:
git config [--global] --unset user.name
- 注意對于設置了--global選項的配置項,unset時需要帶上--global
認識工作區,暫存區,版本庫
zhuang@VM-8-14-ubuntu:~/gitcode$ touch ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ ls
ReadMe
思考以下問題:當我們在gitcode下創建文件時,這個文件就會受到版本管理了嗎?如果放在.git目錄下呢?
答案是無論放在它們兩哪個都不會受到版本管理,而且我們之前也說過不允許在.git下手動修改,誤操作可能會導致整個本地倉庫出錯。
面對這個問題我們需要了解三個區域:
- 工作區:是在電腦上你要寫代碼或文件的目錄。對應我們的gitcode目錄。
- 暫存區:英文叫stage或index。一般存放在.git目錄下的index文件(.git/index)中,我們
把暫存區有時也叫作索引(index)。 - 版本庫:又名倉庫,英文名repository。工作區有一個隱藏目錄錄.git,它不算工作區,而
是Git的版本庫。這個版本庫里面的所有文件都可以被Git管理起來,每個文件的修改、刪除,Git
都能跟蹤,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以"還原"。
工作區、暫存區、版本庫三者的關系如下:
- 圖中左側為工作區,右側為版本庫。Git的版本庫里存了很多東西,其中最重要的是暫存區。
- 在創建Git版本庫事,Git會為我們自動創建一個唯一的master分支,以及指向master的一個指針叫HEAD。
- 當執行git add操作時,會將工作區修改的內容保存到版本庫的暫存區中,暫存區目錄樹的文件索引會被更新。注意:這里工作區修改的內容不僅僅指的是新增和修改,還有刪除!
- 版本庫中還有一個模塊,叫“對象庫(objects)”,里面存儲一堆git對象,維護git對象相當于維護了文件的所有版本,即進行了版本管理。
- 當執行git commit操作時,會把暫存區的index樹寫到master分支下,master分支會做相應的更新,注意:git對象都存在objects里,因此暫存區存的是一個個git對象的索引,它是輕量級的一個區域。
- master指向的是當前分支,即最新commit,即最近的一個版本。
總結:通過新建或粘貼進目錄的文件,并不能稱之為向倉庫中新增文件,而只是在工作區新增文件。必須通過兩板斧git add和git commit才能將文件添加到倉庫中進行管理。
小細節:當我們剛創建完一個新目錄,還沒有git add時,是查看不了暫存區的,即.git目錄下的index目錄。
添加文件
(1)場景一:
先在gitcode目錄下創建一個文件ReadMe,給ReadMe文件添加內容:
git add : 添加內容進暫存區
git add ReadMe
當然git add我們可以靈活使用:
git add [file1] [file2].. //添加一個或多個文件到暫存區
git add [dir] //添加指定目錄到暫存區,包括子目錄
git add . //添加當前目錄下的所有文件
git commit命令將暫存區內容添加到本地倉庫:
git commit -m "ReadMe" //提交暫存區全部內容
git commit [file1] [file2]... -m "message"//當然也可以提交暫存區的指定文件
- git commit 后面的 -m 選項,要跟上描述本次提交的message,由用戶自己完成,這部分內容絕對不能省略,并要好好描述,它們用來記錄你的提交細節,方便我們開放以及他人協作。
我們一次性add和commit多個文件:
zhuang@VM-8-14-ubuntu:~/gitcode$ touch file1 file2 file3
zhuang@VM-8-14-ubuntu:~/gitcode$ git add file1
zhuang@VM-8-14-ubuntu:~/gitcode$ git add file2
zhuang@VM-8-14-ubuntu:~/gitcode$ git add file3
zhuang@VM-8-14-ubuntu:~/gitcode$ git commit -m "add 3 file"
[master e42d583] add 3 file3 files changed, 0 insertions(+), 0 deletions(-)create mode 100644 file1create mode 100644 file2create mode 100644 file3
完成之后,我們可以使用git log命令顯示從最近到最遠的提交日志,并且可以看到我們commit時的日志消息:
- commit后跟著的一串字符串是我們每次提交的commit id(版本號),Git的commit Id是一個SHA1計算出來的一個非常大的數字,用十六進制表示。
如果嫌git log一次性輸出信息太多,可以加上--pretty=oneline:
經過上面兩次提交,我們查看.git目錄下發生什么變化:
- 我們發現新增了暫存區index,add后的內容就是添加到這里的。
- HEAD指針指向的就是默認master分支
- 我們查看master,里面保存的其實就是當前最新的一個commit ID,即一個git對象。
objects為Git的對象庫,里面包含了創建的各種版本庫對象以及內容,當執行git add命令時,暫存區的目錄樹被更新,同時工作區修改的文件內容被寫入到對象庫中的一個新對象中,就位于".git/objects"目錄下,我們可以觀察下:
- 查找objects時,要將commit id分成兩部分,其中前兩位是文件夾名稱,后38位是文件名稱
- 找到這個文件之后,一般不能直接看到里面是什么,該文件是經過SHA(安全哈希算法)加密過的文件,我們可以使用 git cat-file -p + commit id 來查看
- 其中還有一行tree,我們可以使用同樣方法查看
- 在查看ReadMe對應的commit ID,我們發現我們第二次提交時對其修改的內容被git記錄下來
總結:在本地的git倉庫中,有幾個文件或目錄很特殊
1. index : 暫存區,git add后會更新該內容
2. HEAD:默認指向master分支的一個指針。
3. refs/heads/master:文件保存當前master分支的最新commit id
4. objects: 包含了創建的各種版本庫對象及內容,可以簡單理解為存放了git維護的所有修改。
(2)場景2
這里我們先創建file4,再創建file5,將file4進行add存放到暫存區,這里顯示只有一個文件改變了,不應是新增了兩個文件嗎?
我們應該弄清楚,git add只是將文件添加到暫存區,git commit是將暫存區內容添加到本地倉庫中。我們并沒有git add file5導致其沒有在暫存區中維護,因此我們commit時只將已經在暫存區中的file4提交了,要想提交file5,只需對其再進行兩板斧add commit即可。
修改文件
Git比其他版本控制系統設計得優秀,因為Git跟蹤并管理的是修改,而非文件。
我們之前說過,修改不僅僅是修改內容,新增一行,刪除一行也是修改,甚至在工作區新增文件也是一個修改。
我們在工作區對ReadMe文件內容進行修改:
此時倉庫中的ReadMe和工作區中的ReadMe是不同的,我們可以使用git status 查看在你上次提交之后是否對文件有再次修改:
注:git status只能查看哪個文件變化/修改,但不知道具體修改內容(對于大文件我們cat無法準確得知修改內容)
我們可以使用git diff [file] 命令顯示暫存區和工作區文件的差異,顯示的格式正式Unix通用的diff格式
zhuang@VM-8-14-ubuntu:~/gitcode$ git diff ReadMe
diff --git a/ReadMe b/ReadMe //a是改動前 b是改動后
index 8d0e412..05fe86c 100644
--- a/ReadMe //改動前
+++ b/ReadMe //改動后
@@ -1 +1,2 @@ //-1代表改動前第一行內容 原文件在第1行開始,并且原文件只有1行內容。hello git //+1,2表示改動后從第一行開始,連續兩行的內容 新文件從第1行開始,并且新增了1行,使得現在有2行內容。
+hello world
也可以使用git diff HEAD -- [file]來查看版本庫和工作區文件的區別
此時我們把修改的ReadMe再git add會提示在暫存區修改了:
此時再commit即可:
版本回退
我們知道Git能夠管理文件的歷史版本,這也是版本控制器重要的能力,如果有一天你發現之前工作的內容出現很大問題,需要在某個特定的歷史版本重新開始,此時就需要版本回退。
Git中用于版本回退的命令是git reset,可以指定退回某一次提交的版本。
我們之前的操作使得ReadMe存在兩個版本,第一個版本只有一行內容Hello git,第二個版本新增了一行內容Hello world,git reset本質是將版本庫中的內容進行回退,而工作區和暫存區是否回退取決于它的三個選項:【--soft】【--mixed】【--hard】
- --soft :?參數對于?作區和暫存區的內容都不變,只是將版本庫回退到某個指定版本。
- --mixed選項:為默認選項,使?時可以不?帶該參數。該參數將暫存區的內容退回為指定提交版本內容,工作區文件保持不變
- --hard:參數將暫存區與?作區都退回到指定版本。切記?作區有未提交的代碼時不要?這個命令,因為工作區會回滾,你沒有提交的代碼就再也找不回了,所以
使?該參數前?定要慎重
我們使用--hard選項演示一下:
我們發現我們的三個區域都回退了,如果我們想反悔,可以使用之前打印的commit ID復原出file1 file2 file3。但這樣做的前提是commit ID沒有被清除
如果commit id被清除了呢?此時我們還可以使用命令git reflog查看本地記錄的每一次提交id進行reset
注:這個55604d7其實是commit ID的一部分,也可以用來進行回退
思考一個問題 : Git版本回退的速度是比較快的,為什么呢?
Git在內部有個指向當前分?(此處是master)的HEAD指針, refs/heads/master?件?保存當前 master 分?的最新 commit id 。當我們在回退版本的時候,Git僅僅是給refs/heads/master中存儲?個特定的version 。
撤銷修改
(1)情況一:對于工作區的代碼還沒add
在原來基礎上我們給ReadMe新增上一行內容:
此時我們如果想撤銷工作區的內容,可以使用git checkout -- 撤銷的文件名:它其實就是幫我們將工作區文件回到最近一次add/commit的狀態(注意加上兩杠)
當工作區的代碼沒有add時,我們可以使用兩種方式進行撤銷:
1. 手動使用Vim工具撤銷 --- 對于這種方式我們不推薦,如果代碼寫了幾天但一直沒有add,此時修改容易出錯
2. 我們推薦使用git checkout -- [filename]?
(2)情況二:已經add,但是沒有commit
我們先對ReadMe文件修改,新增一行內容,add之后使用git status查看狀態:
此時我們可以使用的git reset作用更詳細來說是回退到版本庫的當前版本,我們可以使用--mixed選項先將暫存區回退到版本庫的當前版本,再使用git checkout對工作區進行撤銷:
補充:
git reset --mixed HEAD ReadMe //回退到當前版本
git reset --mixed HEAD^ //回退到上個版本 ^^是回退到上上個版本
(3)情況3:已經add,也已經commit
此時版本庫是最新版本,此時可以使用git rest的--hard選項將三個區域都回退,但是前提是commit之后,沒有push,撤銷才有效。(實際公司開放跑的代碼都是圍繞遠程倉庫的,所以撤銷主要目的是不影響遠程倉庫),Push操作是將版本從版本庫->遠程倉庫。
演示:
準備工作
撤銷
刪除文件
rm是刪除工作區的文件,但對于本地倉庫并沒有刪掉,實際應該怎么刪除呢?
此時就完成一個文件在工作區 暫存區 版本庫的修改,我們總結一下刪除文件的步驟:
1.?rm --- 刪除工作區內容
2.?git add --- 提交工作區的變動
3. git commit --- 更新到版本庫
git rm + 要刪除文件 : 該命令幫我們刪除工作區文件同時幫我們add,我們只需要commit即可
總結一下:
1. Git是一個版本控制器,跟蹤的是版本的修改。
2. git init 創建本地倉庫
3. git三板斧 : git add -> 工作目錄放到暫存區 git commit 暫存區->版本庫master git push 本地倉庫->遠程倉庫
4. 版本回退:git reset,存在三個選項--soft --mixed --hard
5. 查看相關命令:git log 查看commit id , git status 查看倉庫狀態