文章目錄
- 學習目標
- Ⅰ. 初始 Git
- 💥注意事項
- Ⅱ. Git 安裝
- Linux-centos安裝Git
- Ⅲ. Git基本操作
- 一、創建git本地倉庫 -- git init
- 二、配置 Git -- git config
- 三、認識工作區、暫存區、版本庫
- ① 工作區
- ② 暫存區
- ③ 版本庫
- ④ 三者的關系
- 四、添加、提交更改、查看提交日志命令
- ① 場景一
- 查看 .git 文件變化
- ② 場景二
- 五、修改文件
- ① 查看工作目錄和暫存區的狀態 -- git status
- ② 查看暫存區和工作區等之間的更改內容 -- git diff
- 六、版本回退 -- git reset && git reflog
- ① --mixed選項
- 如何撤銷版本回退???
- ② --hard選項
- 💥各版本回退選項的總結
- 為什么版本回退以及撤銷的時候,速度那么快???
- 七、撤銷修改 -- git checkout -- [filena]
- 情況一:工作區的代碼還未add
- 情況二:代碼已經 add,但還未 commit
- 情況三:代碼已經 add 和 commit
- 8、刪除文件 -- git rm

學習目標
- 掌握
Git
企業級應用,深刻理解Git
操作過程與操作原理,理解工作區,暫存區,版本庫的含義 - 掌握
Git
版本管理,自由進行版本回退、撤銷、修改等Git
操作方式與背后操作原理 - 掌握
Git
分支管理,從分支創建,切換,合并,刪除的整個生命周期,靈活進行各種場景下的分支管理,學習常見分支管理策略 - 掌握
Git
遠程倉庫與本地倉庫,結合版本管理與分支管理,做到基于分支級的個人級開發 - 理解分布式版本控制系統,學習遠程倉庫與本地倉庫的交互操作,掌握多人協作開發模式
- 學習企業級常見分支策略(
master
/release
/develop
/feature
/hotfix
等),理解不同公司,不同環境下適合的分支模型。結合案例,引入工程程師,測試人員,技術經理等角色,展現項目開發過程的全貌,深刻理解開發的整體流程,俯視Git
在其中的作用
? 另外還要明白,我們 平時使用的 gitee
、github
等平臺,其實只是基于 git
的托管平臺,相當于遠程倉庫,要分清楚!
Ⅰ. 初始 Git
? 不知道你工作或學習時,有沒有遇到這樣的情況:我們在編寫各種文檔時,為了防止文檔丟失,更改失誤,失誤后能恢復到原來的版本,不得不復制出一個副本,比如:
“報告-v1”
“報告-v2”
“報告-v3”
“報告-確定版”
“報告-最終版”
“報告-究極進化版”
...
? 每個版本有各自的內容,但最終會只有一份報告需要被我們使用。
? 但在此之前的工作都需要這些不同版本的報告,于是每次都是復制粘貼副本,產出的文件就越來越多,文件多不是問題,問題是:隨著版本數量的不斷增多,你還記得這些版本各自都是修改了什么嗎?
? 文檔如此,我們寫的項目代碼,也是存在相同的問題!!
? 此時就引入了 版本控制器 的概念!
? 為了能夠更方便我們管理這些不同版本的文件,便有了版本控制器。所謂的版本控制器,就是能讓你了解到一個文件的歷史,以及它的發展過程的系統。通俗的講就是一個可以記錄工程的每一次改動和版本迭代的一個管理系統,同時也方便多人協同作業。
? 目前最主流的版本控制器就是 Git
。Git
可以控制電腦上所有格式的文件,例如 doc
、excel
、dwg
、dgn
、rvt
等等。對于我們開發人員來說,Git
最重要的就是可以幫助我們管理軟件開發項目中的源代碼文件!
💥注意事項
? 還需要再明確一點,所有的版本控制系統,Git
也不例外,其實只能跟蹤 文本文件
的改動,比如 TXT
文件,網頁,所有的程序代碼等等。版本控制系統可以告訴你每次的改動,比如在第 5
行加了一個單詞 “Linux”
,在第 8
行刪了一個單詞 “Windows”
。
? 而 圖片、視頻這些二進制文件,雖然也能由版本控制系統管理,但 沒法跟蹤二進制文件的變化,只能把二進制文件每次改動串起來,也就是只知道圖片從 100KB
改成了 120KB
,但到底改了啥,版本控制系統不知道,也沒法知道。
Ⅱ. Git 安裝
? Git
是開放源代碼的代碼托管工具,最早是在 Linux
下開發的。開始也只能應用于 Linux
平臺,后面慢慢的被移植到 windows
下,現在,Git
可以在 Linux
、Unix
、Mac
和 Windows
這幾大平臺上正常允許了。
? 這里就不細講安裝了,比較簡單,可以上網查!
Linux-centos安裝Git
? 安裝比較簡單,首先,你可以試著輸入 git
,看看系統有沒有安裝 git
:
[liren@VM-8-7-centos ~]$ git --version
git version 1.8.3.1
? 如果沒有出現上述內容,說明沒有安裝,使用 yum
指令安裝:
sudo yum -y install git
? 其它操作系統安裝也是類似的,自行查閱資料!
Ⅲ. Git基本操作
? Git
的工作就是創建和保存你項目的快照及與之后的快照進行對比。對于下述出現的常見指令以及其它指令,都會在后面介紹到!
? Git基本操作
圖示說明:
workspace
:工作區staging area
:暫存區/緩存區local repository
:版本庫或本地倉庫remote repository
:遠程倉庫
一、創建git本地倉庫 – git init
? 要提前說的是,倉庫的本質是進行版本控制的一個文件目錄。我們要想對文件進行版本控制,就必須先創建一個倉庫出來,然后在這個倉庫中對我們要追蹤管理的文件進行管理!
? 💥 注意,這里說的 本地倉庫
和我們后面講的 版本庫
是不一樣的!
? 創建一個 Git
本地倉庫對應的命令為 git init
,注意命令要在文件目錄下執行,例如:
[liren@VM-8-7-centos gitcode]$ pwd
/home/liren/gitcode
[liren@VM-8-7-centos gitcode]$ git init
Initialized empty Git repository in /home/liren/gitcode/.git/
[liren@VM-8-7-centos gitcode]$ ls -al
total 12
drwxrwxr-x 3 liren liren 4096 Jul 9 21:38 .
drwx------ 15 liren liren 4096 Jul 9 21:38 ..
drwxrwxr-x 7 liren liren 4096 Jul 9 21:38 .git
[liren@VM-8-7-centos gitcode]$
? 我們發現,當前目錄下多了?個 .git
的隱藏文件, .git
目錄是 Git
來跟蹤管理倉庫的,不要手動修改這個目錄里面的文件,不然改亂了,就把 Git
倉庫給破壞了。
? 其中包含 Git
倉庫的諸多細節,隨著我們學習的深入,后面會挑重點來講!
[liren@VM-8-7-centos gitcode]$ tree .git
.git
|-- branches
|-- config
|-- description
|-- HEAD
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- prepare-commit-msg.sample
| |-- pre-push.sample
| |-- pre-rebase.sample
| `-- update.sample
|-- info
| `-- exclude
|-- objects
| |-- info
| `-- pack
`-- refs|-- heads`-- tags9 directories, 13 files
[liren@VM-8-7-centos gitcode]$
二、配置 Git – git config
? 當安裝 Git
后首先要做的事情是設置你的 用戶名稱 和 郵箱地址,這是非常重要的,它相當于是我們操作 Git
的賬號和密碼那般重要。
? 添加配置命令 為:
git config [--global] user.name "Your Name" # 把 Your Name 改成你的昵稱
git config [--global] user.email "email@example.com" # 把 email@example.com 改成郵箱的格式,只要格式正確即可
? 其中 --global
是一個可選項。如果使用了該選項,表示這臺機器上所有的 Git
倉庫都會使用這個配置。如果你希望在不同倉庫中使用不同的 名稱 或 郵箱,可以不要 --global
選項,但要注意的是,執行命令時必須要在倉庫里。
? 查看配置命令 為:
git config -l
? 下面我們舉個例子,給當前的倉庫添加名稱和郵箱:
[liren@VM-8-7-centos gitcode]$ git config -l # 查看配置
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true[liren@VM-8-7-centos gitcode]$ git config --global user.name "sharp-blade"
[liren@VM-8-7-centos gitcode]$ git config --global user.email "2916776007@qq.com"[liren@VM-8-7-centos gitcode]$ git config -l # 查看配置,多了兩個配置
user.name=sharp-blade
user.email=2916776007@qq.com
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
[liren@VM-8-7-centos gitcode]$
? 那我們要是想 刪除對應的配置 的話,則要用以下配置指令:
git config [--global] --unset user.name
git config [--global] --unset user.email
? 💥注意,如果 對應的配置使用了 --global
選項,然后要刪除的話,也要加上 --global
選項才能刪除!
三、認識工作區、暫存區、版本庫
我們先來理解下 Git
中 工作區、暫存區 和 版本庫 概念:
① 工作區
? 工作區就是當前 Git
倉庫所在的目錄。
? 在工作區中,我們可以進行代碼的修改、添加、刪除等操作,并且可以在工作區中直接進行提交。提交操作 add
會將工作區中的更改內容同步到暫存區中,并將它們標記為已暫存狀態。在提交時,Git
會將暫存區中的內容提交到遠程倉庫中,并創建一個新的提交對象。
? 需要注意的是,工作區和暫存區都是相對于當前分支的,因此 只有在當前分支中進行的操作才會影響它們。當切換到其他分支時,工作區和暫存區也會隨之改變。
? 舉個例子,我們和上面創建倉庫的位置一樣,在 /home/liren/gitcode/
目錄就是我們的倉庫,此時里面的文件如下所示:
② 暫存區
? 暫存區實際上是一個位于工作區與版本庫之間的臨時區域,是一個 二進制文件,包含所有在工作區中修改的文件,叫做 stage
或 index
。其 一般存放在 .git
目錄下的 index
文件(.git/index
)中,所以我們把暫存區有時也叫作索引(index
)。
? 暫存區是位于版本庫之上的一個特殊分支,用于臨時存儲和管理代碼更改。當使用 git add
命令將文件添加到暫存區時,Git
會根據這些修改生成新的提交對象,并將它們與版本庫中的提交對象關聯起來。并且可以使用 git commit
命令提交更改到對應版本分支下面!
? 💥需要注意的是,暫存區是一個獨立、臨時的區域,它只存在于當前分支中。當你切換到其他分支時,暫存區也將隨之改變。此外,當你的分支合并到主分支時,暫存區也會受到影響。
?
? 舉個例子,我們用 tree
指令看一下還沒有使用 git add
之前的版本庫 .git
中對應暫存區 index
文件的位置:
? 另外我們也可以看到,工作區的內容也是不會顯示在版本庫中的,說明它們是相互獨立的!
? 下面我們使用 git add
指令,將工作區的內容提交到暫存區中,再看看效果:
? 后面我們再來講這個 objects
目錄是個什么鬼!
③ 版本庫
? 版本庫(Repository
) 是一個位于工作區之外的目錄,其中包含所有 Git
存儲的數據,如提交對象、分支、標簽等。
? 在工作區中有一個 隱藏目錄 .git
,它不算是工作區,而是 Git
的版本庫。這個版本庫里面的所有文件都可以被 Git
管理起來,每個文件的修改、刪除操作,Git
都能跟蹤到,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以“還原”。
? 還是提醒一下,切記不要在 .git
目錄下手動修改文件,不然很容易導致倉庫不能用了!
? 下面我們使用 git commit -m
指令,將暫存區中的文件,提交到默認的主分支 master
中:
④ 三者的關系
? 下面這個圖展示了工作區、版本庫中的暫存區和版本庫之間的關系:
- 圖中左側為工作區,右側為版本庫。在版本庫中標記為
index
的區域是 暫存區(stage
/index
),標記為master
的是master
分支 所代表的目錄樹。 HEAD
實際是指向master
分支的一個"游標"。所以圖示的命令中出現HEAD
的地方可以用master
來替換。- 圖中的
objects
標識的區域為Git
的對象庫,實際位于.git/objects
目錄下,里面包含了創建的各種對象及內容。
- 在創建
Git
版本庫時,Git
會為我們自動創建一個唯一的master
分支,以及指向master
的一個指針叫HEAD
。(分支和HEAD
的概念后面再說) - 當對工作區修改(或新增)的文件 執行
git add
命令時,暫存區目錄樹的文件索引index
會被更新。 - 當執行提交操作
git commit
時,master
分支會做相應的更新,可以簡單理解為暫存區的目錄樹才會被真正寫到版本庫中。
? 由上述描述我們便能得知:通過新建或粘貼進目錄的文件,并不能稱之為向倉庫中新增文件,而只是在工作區新增了文件,其實質上并沒有進入到倉庫中被管理。所以 必須要通過使用 git add
和 git commit
命令才能將文件添加到倉庫中進行管理!!!
四、添加、提交更改、查看提交日志命令
- 添加
- 添加一個或多個文件到暫存區:
git add [file1] [file2] ...
- 添加指定目錄到暫存區,包括子目錄:
git add [dir]
- 添加當前目錄下的所有文件到暫存區:
git add .
- 添加一個或多個文件到暫存區:
- 提交更改
- 將當前工作目錄中的所有更改提交到暫存區中:
git commit -a
- 將當前工作目錄中的更改提交到暫存區中,并添加一個提交消息:
git commit -m "commit message"
- 將指定文件中的更改提交到暫存區中,并添加一個提交消息:
git commit -m "commit message" filename
- 將當前工作目錄中的更改提交到暫存區中,并添加一個提交消息,同時將提交記錄添加到本地分支中:
git commit -m "commit message" -a -s
- 將當前工作目錄中的所有更改提交到暫存區中:
- 查看提交日志
- 查看最近一次提交到最近的提交之間的所有提交記錄:
git log
- 查看當前分支和遠程倉庫的
master
分支之間的所有提交記錄:git log master..origin/master
- 查看
master
分支上的所有提交記錄的詳細差異:git log -p master
- 查看最近的
n
次提交記錄:git log -n
- 查看所有分支的提交記錄:
git log --all
- 除此之外,還可以通過設置其它不同的選項來查看不同的提交記錄,例如:
git log --author=username
:查看指定作者的提交記錄。git log --grep="pattern"
:查看包含指定模式的提交記錄。git log --pretty=oneline
:用于將提交記錄以一行的形式輸出,這對于在某些情況下快速查看提交記錄非常有用。git log --graph --abbrev-commit
:這兩個選項一般用于查看提交日志時候用時間線的形式顯示不同分支的提交情況,看起來很直觀!- ……
- 查看最近一次提交到最近的提交之間的所有提交記錄:
下面我們分為兩個場景來使用這三個指令!
① 場景一
? 在包含 .git
的目錄下新建一個 readme
文件,使用 git add
命令可以將文件添加到暫存區,再使用 git commit
命令將暫存區內容提交到本地倉庫也就是版本庫。
? 💥注意,git commit
后面的 -m
選項,要跟上描述本次提交的 message
,由用戶自己完成,這部分內容絕對不能省略,并要好好描述,是用來記錄你的提交細節,是給我們人看的。
[liren@VM-8-7-centos gitcode]$ ls -al
total 12
drwxrwxr-x 3 liren liren 4096 Jul 10 11:08 .
drwx------ 15 liren liren 4096 Jul 10 11:13 ..
drwxrwxr-x 7 liren liren 4096 Jul 10 11:08 .git[liren@VM-8-7-centos gitcode]$ touch readme
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git commit -m 'first add file:readme'
[master (root-commit) cdc96e6] first add file:readme1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 readme[liren@VM-8-7-centos gitcode]$
? git commit
命令執行成功后會告訴我們,有一個文件被改動(就是我們新添加的 readme
文件),插入了零行內容(說明 readme
沒有插入新內容)。
? 我們還可以多次 add
不同的文件,而只 commit
一次便可以提交所有文件,是因為需要提交的文件是通通被 add
到暫存區中,然后一次性 commit
暫存區的所有修改。如下所示:
[liren@VM-8-7-centos gitcode]$ touch file1 file2 file3
[liren@VM-8-7-centos gitcode]$ git add file1 # 添加一個文件
[liren@VM-8-7-centos gitcode]$ git add file2 file3 # 添加多個文件
[liren@VM-8-7-centos gitcode]$ git commit -m 'add 3 files'
[master 7eb10f5] add 3 files3 files changed, 0 insertions(+), 0 deletions(-)create mode 100644 file1create mode 100644 file2create mode 100644 file3
[liren@VM-8-7-centos gitcode]$
? 截至目前為止,我們已經更夠將代碼直接提交至本地倉庫了。我們可以使用 git log
命令,來查看下歷史提交記錄:
[liren@VM-8-7-centos gitcode]$ git log
commit 7eb10f50de9781d05a4a4af2134a8673352e89fa
Author: lirendada <2916776007@qq.com>
Date: Mon Jul 10 13:05:02 2023 +0800add 3 filescommit cdc96e6d432ea74b61b4bf36de4dc19f07310eb0
Author: lirendada <2916776007@qq.com>
Date: Mon Jul 10 11:50:00 2023 +0800first add file:readme[liren@VM-8-7-centos gitcode]$
? 該命令顯示從最近到最遠的提交日志,并且可以看到我們 commit
時的日志消息。如果嫌輸出信息太多,看得眼花繚亂的,可以試試加上 --pretty=oneline
參數:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
? 需要說明的是,我們看到的一大串類似 7eb10……2e89fa
的是每次提交的 commit id
(版本號),Git
的 commit id
不是 1,2,3……
遞增的數字,而是一個 SHA1
計算出來的一個非常大的數字,用十六進制表示(當然你看到的 commit id
和我的肯定不一樣,以你自己的為準)
查看 .git 文件變化
? 首先來看一下 .git
的目錄結構,其實我們前面已經看過了
[liren@VM-8-7-centos gitcode]$ tree .git
.git
|-- branches
|-- COMMIT_EDITMSG
|-- config
|-- description
|-- HEAD
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- prepare-commit-msg.sample
| |-- pre-push.sample
| |-- pre-rebase.sample
| `-- update.sample
|-- index
|-- info
| `-- exclude
|-- logs
| |-- HEAD
| `-- refs
| `-- heads
| `-- master
|-- objects
| |-- 27
| | `-- 1d813417b08f049274d2dfda5211ec2ea2ec95
| |-- 7e
| | `-- b10f50de9781d05a4a4af2134a8673352e89fa
| |-- cd
| | `-- c96e6d432ea74b61b4bf36de4dc19f07310eb0
| |-- e6
| | `-- 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
| |-- e8
| | `-- 0ad49ace82167de62e498622d70377d913c79e
| |-- info
| `-- pack
`-- refs|-- heads| `-- master`-- tags17 directories, 23 files
下面我們來介紹其中幾個重要的:
-
index
就是暫存區,我們add
之后的內容都是添加到這里的 -
HEAD
是默認指向當前分支也就是master
分支最后一次提交內容的指針:[liren@VM-8-7-centos gitcode]$ cat .git/HEAD ref: refs/heads/master
? 而此時的
master
分支,其實就是:[liren@VM-8-7-centos gitcode]$ cat .git/refs/heads/master 7eb10f50de9781d05a4a4af2134a8673352e89fa
? 這串內容就是 當前分支最新的
commit id
,這可以在上面的objects
對象文件中找到,其中7e
是目錄名,相當于是房間號;而后面的那串就是更具體的提交內容文件! -
objects
為Git
的對象庫,里面包含了創建的各種版本庫對象及內容。當執行git add
命令時,暫存區的目錄樹被更新,同時工作區修改(或新增)的文件內容被寫入到對象庫中的一個新的對象中,就位于.git/objects
目錄下,讓我們來看看這些對象有何用處:[liren@VM-8-7-centos gitcode]$ ls .git/objects/ 27 7e cd e6 e8 info pack
? 查找
object
時要將commit id
分成兩部分,其 前兩位是文件夾名稱,后38
位是文件名稱。找到這個文件之后,一般不能直接看到里面是什么,因為該類文件是經過sha
(安全哈希算法)加密過的文件!? 好在我們可以使用
git cat-file
命令來查看版本庫對象的內容:[liren@VM-8-7-centos gitcode]$ git cat-file -p 7eb10f50de9781d05a4a4af2134a8673352e89fa #-p選項表示美觀的打印出來 tree 271d813417b08f049274d2dfda5211ec2ea2ec95 parent cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 author lirendada <2916776007@qq.com> 1688965502 +0800 committer lirendada <2916776007@qq.com> 1688965502 +0800add 3 files [liren@VM-8-7-centos gitcode]$
? 我們一探究竟,順便將它的父親節點還有根節點都看看到底存放著什么:
總結一下,在本地的 git
倉庫中,有幾個文件或者目錄很特殊:
- index:就是暫存區,
git add
后會更新該內容 - HEAD:默認指向
master
分?的?個指針 - refs/heads/master:文件里保存當前
master
分支的 最新commit id
- objects:包含了創建的各種版本庫對象及內容,可以簡單理解為放了
git
維護的所有修改內容
? 后面在學習過程中,最好能將常見的 git
操作與 .git
目錄當中的結構內容變化對應起來,這樣有利于我們理解 git
細節流程!
② 場景二
? 學習到這里,我們已經清楚了如何向倉庫中添加文件,并且對于工作區、暫存區、版本庫也有了一定的認識。那么我們再展示一種添加文件的場景,能加深對工作區、暫存區、版本庫的理解,實例如下:
[liren@VM-8-7-centos gitcode]$ touch file4 #新增file4
[liren@VM-8-7-centos gitcode]$ touch file5 #新增file5
[liren@VM-8-7-centos gitcode]$ git add file4 #添加file4到暫存區
[liren@VM-8-7-centos gitcode]$ git commit -m 'add file4' #提交更改
[master ced585b] add file41 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 file4
[liren@VM-8-7-centos gitcode]$
? 提交后發現打印了 1 file changed, 0 insertions(+), 0 deletions(-)
,意思是只有一個文件改變了,這時我們提出了疑問,不是新增了兩個文件嗎?
? 其實學了上面的內容之后,這里就不難理解了,git add
是將工作區文件添加到暫存區, git commit
是將暫存區的內容添加到本地倉庫中。由于我們并沒有使用 git add file5
,此時 file5
就不在暫存區中維護,所以我們 commit
的時候其實只是把已經在暫存區的 file4
提交了,而遺漏了工作區的 file5
。
? 那如何提交 file5
呢?很簡單,再次 add
然后 commit file5
即可,這里就不演示了!
五、修改文件
? 這里要強調一下,git
追蹤的其實是修改的內容,而不是整個文件!也就是說 git
不會每次都為整個文件創建 object
對象,而是只對其中修改的內容進行創建對象管理,這樣子一來就能節省很大部分的空間,這也就是為什么 Git
比其它版本控制器優秀的地方!
? 什么是修改,比如你新增了一行,這就是一個修改,刪除了一行,也是一個修改,更改了某些字符,也是一個修改,刪了一些又加了一些,也是一個修改,甚至創建一個新文件,也算一個修改。
① 查看工作目錄和暫存區的狀態 – git status
? 下面我們做一些操作:向之前的 readme
文件里面增添數據,不進行 add
操作;向之前的 file5
文件中增添數據,并且進行 add
操作,但不進行 commit
操作;創建一個新文件 file6
,也向里面增添數據,不進行 add
操作:
[liren@VM-8-7-centos gitcode]$ echo 'lirendada' > readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada[liren@VM-8-7-centos gitcode]$ echo 'liren' > file5
[liren@VM-8-7-centos gitcode]$ git add file5
[liren@VM-8-7-centos gitcode]$ cat file5
liren[liren@VM-8-7-centos gitcode]$ touch file6
[liren@VM-8-7-centos gitcode]$ echo 'lirendada' > file6
[liren@VM-8-7-centos gitcode]$ cat file6
lirendada
? 此時如何查看當前倉庫的狀態呢?這就得使用 git status
命令!
? git status
命令用于顯示工作目錄和暫存區的狀態。使用此命令能看到哪些修改被暫存到了,哪些沒有,哪些文件沒有被 Git
追蹤到。git status
不顯示已經 commit
到項目歷史中去的信息。看項目歷史的信息要使用 git log
。
? 并且 git status
也不會顯示具體修改的內容,想要查看的話得通過 git diff
指令來查看,這個下面會講!
? 在每次執行 git commit
之前先使用 git status
檢查文件狀態是一個很好的習慣,這樣能防止你不小心提交了不想提交的東西。
② 查看暫存區和工作區等之間的更改內容 – git diff
? git diff
命令用于顯示提交和工作樹等之間的更改,此命令比較的是 已寫入暫存區和已經被修改但尚未寫入暫存區 文件的區別。
? 主要使用方式如下所示:
git diff <file> # 比較當前文件和暫存區文件差異
git diff HEAD -- [file] # 查看版本庫和工作區文件的區別git diff <id1><id2> # 比較兩次提交之間的差異
git diff <branch1> <branch2> # 在兩個分支之間比較git diff --staged # 顯示暫存區和上一次提交(commit)的差異
git diff --cached # 顯示暫存區和上一次提交(commit)的差異git diff --stat # 簡單查看差異,僅僅比較統計信息
? 下面我們以上面的 readme
文件為例,查看一下它的差異:
[liren@VM-8-7-centos gitcode]$ git diff readme
diff --git a/readme b/readme # a/readme表示比較的是當前工作目錄下的,而b/readme表示比較的是倉庫中的readme文件
index e69de29..ff2fbef 100644 # 這一行顯示了文件內容的差異。e69de29和ff2fbef是兩個文件的哈希值,用于比較它們之間的差異
--- a/readme # 顯示了當前工作目錄下的readme文件
+++ b/readme # 顯示了倉庫中的readme文件
@@ -0,0 +1 @@ # 顯示了文件內容的差異。-0,0表示當前工作目錄下的readme文件沒有修改,+1表示倉庫中的readme文件增加了一條新行
+lirendada # 顯示了倉庫中的readme文件的新行,即lirendada
? 知道了對 readme
做了什么修改后,再把它提交到本地倉庫就放心多了!
? 下面我們對 readme
文件進行 add
操作,看看變化:
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file5
# modified: readme
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file6
[liren@VM-8-7-centos gitcode]$
? 可以看到它已經被定義為 Changes to be committed
了,下面我們繼續對其進行 commit
操作:
[liren@VM-8-7-centos gitcode]$ git commit -m 'change readme'
[master c82c67b] change readme2 files changed, 2 insertions(+)
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file6
nothing added to commit but untracked files present (use "git add" to track)
[liren@VM-8-7-centos gitcode]$
? 可以看到,進行 commit
之后包括 file5
也被提交更新到版本庫去了,因為它們都是在暫存區中的!
? 而對于 file6
來說,只要我們不對其進行 add
操作,那么它就只是在工作區操作罷了!
? 此時我們將 file6
刪除之后,會發現 git
就不再管理到它了!
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
六、版本回退 – git reset && git reflog
? 之前我們也提到過,Git
能夠管理文件的歷史版本,這也是版本控制器重要的能力。如果有一天你發現之前的工作出現了很大的問題,需要在某個特定的歷史版本重新開始,這個時候,就需要版本回退的功能了。
? git reset
命令用于回退版本,可以指定退回某一次提交的版本。
? 其語法格式如下:
git reset [--soft | --mixed | --hard] [HEAD]
? 要解釋一下 “回退” 本質是要將 版本庫
中的內容進行回退,而 工作區
或 暫存區
是否回退由命令參數決定!
下面我們來介紹一下這些參數:
--mixed
為 默認選項,使用時可以不用帶該參數。該參數將暫存區的內容退回為指定提交版本內容,工作區內容保持不變。--soft
參數對于工作區和暫存區的內容都不變,只將版本庫回退到某個指定版本。--hard
參數將 暫存區與工作區都退回到指定版本。切記工作區有未提交的代碼時不要用這個命令!因為工作區回滾之后,你沒有提交的代碼就再也找不回了,所以 使用該參數前一定要慎重!!HEAD
- 常見用法:
- 可直接寫成
commit id
,表示指定退回的版本HEAD
:當前版本HEAD^
:上一個版本HEAD^^
:上上一個版本HEAD^^^
:上上上一個版本- 以此類推……
- 也可以使用
~數字
表示
HEAD~0
:表示當前版本HEAD~1
:上一個版本HEAD^2
:上上一個版本HEAD^3
:上上上一個版本- 以此類推……
? 這樣子干巴巴的說,可能比較不好理解,下面我們舉 --mixed
和 --hard
選項來解釋!
① --mixed選項
? 我們先來看看之前我們操作時留下的 git
提交日志:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
? 我們一開始創建 readme
文件的時候,它是沒有數據的,而最后一次修改和提交的時候,readme
里面是有一行文本為 lirendada
,那么此時我們就有一個版本回退的要求啦,就是回到最開始的提交的那個版本,我們就能得到 readme
文本是空的,下面我們就來操作一下回退版本!
? 我們先用默認選項 --mixed
來測試一下:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline # 先打印提交日志
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme[liren@VM-8-7-centos gitcode]$ git reset --mixed cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 # 退到最開始的版本
Unstaged changes after reset:
M readme
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline # 再次打印提交日志,發現只剩最開始的版本
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme[liren@VM-8-7-centos gitcode]$ ls # 但是可以發現此時工作區的內容是不變的!
d file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
如何撤銷版本回退???
? 如果說此時我們后悔了,不想回退了,那么其實也是有辦法進行撤銷版本回退的,請記住,撤銷版本回退的 關鍵點
在于要有原來版本的 commit id
,如果找不到這個 commit id
了,那么天皇老子來了也沒用哈哈!
? 所以說我們撤銷版本回退的重點就是找到 commit id
,然后方法就是 再次使用之前我們進行版本回退的指令,比如說我們使用了 git reset --mixed "舊版本commit id"
的話,那么我們也要使用 git reset --mixed "原來版本的commit id"
。
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #打印提交日志
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme[liren@VM-8-7-centos gitcode]$ git reset --mixed c82c67bb370034ef67d0bde191252742fcc7d6f6 #根據原來版本的commit id撤銷回退[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #再次打印提交日志,發現我們已經回到原來的版本了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls
d file1 file2 file3 file4 file5 readme
? 但是有一個問題啊,如果此時我們版本回退之后,服務器不小心重啟了,找不到原來的 commit id
,那該怎么辦,是不是就找不到那個 commit id
了???
? 其實 git
早已給我們留了后路,只需要使用 git reflog
指令,就能找到我們以前所有的版本提交信息了,如下所示:
[liren@VM-8-7-centos gitcode]$ git reflog
cdc96e6 HEAD@{0}: reset: moving to cdc96e6d432ea74b61b4bf36de4dc19f07310eb0
c82c67b HEAD@{1}: reset: moving to c82c67bb370034ef67d0bde191252742fcc7d6f6
cdc96e6 HEAD@{2}: reset: moving to cdc96e6d432ea74b61b4bf36de4dc19f07310eb0
c82c67b HEAD@{3}: commit: change readme
ac00e61 HEAD@{4}: commit: add file5
ced585b HEAD@{5}: commit: add file4
7eb10f5 HEAD@{6}: commit: add 3 files
cdc96e6 HEAD@{7}: commit (initial): first add file:readme
? 但是可能因為項目的代碼很復雜,我們提交了很多日志,此時我們要去找到原來版本的日志,那是難上加難,所以 建議給自己留條后路,不要回退的太徹底!
? 從上面的信息中,可以明顯看出 c82c67b
就是我們要找的原來版本的 commit id
,雖說變短了,但是依然有效,此時再次撤銷版本回退:
[liren@VM-8-7-centos gitcode]$ git reset --hard c82c67b
HEAD is now at c82c67b change readme[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #查看提交日志,發現都回來了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
? 注意:上面出現了 --hard
選項是因為我又用了 --hard
去進行版本回退,這點不需要關心太多!
② --hard選項
? 這里和上面一樣,還是版本回退到第一個版本,看看這次有什么不同:
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #打印提交日志
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme[liren@VM-8-7-centos gitcode]$ git reset --hard cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 #版本回退,三個區域都是
HEAD is now at cdc96e6 first add file:readme[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #打印提交日志,發現只剩第一個版本
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls #工作區中的文件也只剩第一個版本中存在的文件
d readme
[liren@VM-8-7-centos gitcode]$ cat readme #并且文件中的內容也回退到空之前的空了
[liren@VM-8-7-centos gitcode]$
? 接下來我們進行撤銷版本回退:
[liren@VM-8-7-centos gitcode]$ git reset --hard c82c67bb370034ef67d0bde191252742fcc7d6f6 #進行撤銷版本回退
HEAD is now at c82c67b change readme[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline #可以看到信息變成原來的版本了!
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$ ls
d file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$
💥各版本回退選項的總結
為什么版本回退以及撤銷的時候,速度那么快???
? 值得說的是,Git
的版本回退速度非常快,因為 Git
在內部有個指向當前分支(此處是master
)的 HEAD
指針, refs/heads/master
文件里保存當前 master
分支的最新 commit id
。當我們在回退版本的時候,Git
僅僅是給 refs/heads/master
中存儲一個特定的 version
,可以簡單理解成如下示意圖:
? 版本回退前:
? 版本回退后:
? 當你使用 git reset
版本回退時,回退的版本并不會被永久刪除。相反,回退命令會創建一個新的提交記錄,該記錄指向你回退到的舊版本。這個新提交記錄會成為你現在的 HEAD
,也就是當前工作目錄所在的版本。
? 因此,你可以通過 git reflog
命令查看你最近的操作記錄,包括回退操作,以及你之前所處的版本。如果你想恢復到之前的版本,你可以使用 git checkout
命令指定之前的提交記錄的哈希值或分支名,以切換到相應的版本。
? 需要注意的是,如果你在回退之后對舊版本所在的分支進行了修改并提交了更改,那么這些更改可能會被覆蓋或丟失,因為你的回退操作會將你的分支指向舊版本,而不是新更改所在的版本。因此,在 回退之前,最好先將當前分支中的更改提交或保存到其他分支中,以防止數據丟失。
七、撤銷修改 – git checkout – [filena]
? 如果我們在我們的 工作區 寫了很長時間代碼,越寫越寫不下去,覺得自己寫的實在是看不下去,想恢復到上一個版本,此時就要進行撤銷修改操作了,這和我們上面講的版本回退是有關系的!
? 主要分為以下三種情況,我們一一解釋!
情況一:工作區的代碼還未add
此時有兩種做法:
- 直接對想撤銷的代碼手動進行撤銷修改 – 不推薦這種做法,如果代碼量大的話,可能會越改越亂,背道而馳。
- 使用
git checkout -- [filename]
指令- 它可以將指定文件恢復為最近一次提交或添加到暫存區時的狀態。在這種情況下,雙橫線(
--
)用于區分文件名和分支名或提交哈希值,并且 這個雙橫線不能省略,省略了的話該命令就變成其它意思了! - 需要注意的是,該命令 會覆蓋工作目錄中的文件,因此你應該確保你不再需要該文件中未提交的更改。
- 它可以將指定文件恢復為最近一次提交或添加到暫存區時的狀態。在這種情況下,雙橫線(
? 下面我們向 readme
文件中新增文本 “hello world”,記得這個文件中本來還有一條 “lirendada” 的文本,下面來實踐一下:
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme #往文件中插入數據
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
hello world[liren@VM-8-7-centos gitcode]$ git checkout -- readme #想恢復為最近一次提交或添加到暫存區時的狀態[liren@VM-8-7-centos gitcode]$ cat readme #查看文件內容,變成原來的樣子
lirendada
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
情況二:代碼已經 add,但還未 commit
此時依然是有兩種做法:
- 利用
git reset --mixed [filename]
指令撤銷暫存區的內容,然后變成情況一去解決 – 不推薦,因為用下面的方法更方便! - 利用
git reset --hard HEAD
指令,一步到位,直接版本回退到HEAD
指針所指的最近一次commit
的版本狀態,此時工作區和暫存區都會回退!
? 下面我們向 readme
文件中新增文本 “hello world”,記得這個文件中本來還有一條 “lirendada” 的文本,然后進行 add
操作,但是不進行 commit
操作,這里只演示第二種做法:
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: readme
#[liren@VM-8-7-centos gitcode]$ git reset --hard HEAD # 直接回退到最近一次commit的版本,工作區和暫存區都會回退
HEAD is now at c82c67b change readme[liren@VM-8-7-centos gitcode]$ cat readme # 可以看到內容都已經回退了
lirendada
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
nothing to commit, working directory clean
[liren@VM-8-7-centos gitcode]$
情況三:代碼已經 add 和 commit
? 首先我們要明白,出現這種情況的大前提是要和遠程倉庫這種概念聯系起來才有意義,因為一般來說,我們在公司寫代碼的時候,公司的倉庫對于我們來說就是遠程倉庫,我們都是在本地先形成倉庫,然后用 push
操作推送到遠程倉庫中去的!
? 如果此時說我們不小心用 push
把我們不需要的東西推送到了遠程倉庫中,那就真的慘了……
? 在這種大前提下,我們才有必要說去回退到前一個版本!其實并不難,懂了上面兩種,這種就知道怎么做了:
- 使用
git reset --hard HEAD^
指令,回退到HEAD
所指的最近一次commit
版本的上一個版本,也就是HEAD^
,并且--hard
是對 工作區和暫存區都會有回退影響的,達到了我們的目的!
? 下面我們向 readme
文件中新增文本 “hello world”,記得這個文件中本來還有一條 “lirendada” 的文本,然后進行 add
操作,并且進行 commit
操作,然后進行回退操作:
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$ echo "hello world" >> readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
hello world
[liren@VM-8-7-centos gitcode]$ git add readme
[liren@VM-8-7-centos gitcode]$ git commit -m 'modify readme' readme
[master 8cf3a74] modify readme1 file changed, 1 insertion(+)[liren@VM-8-7-centos gitcode]$ git reset --hard HEAD^ # 進行版本回退,使用--hard撤銷工作區和暫存區的內容
HEAD is now at c82c67b change readme[liren@VM-8-7-centos gitcode]$ cat readme # 可以看到版本已經回退了
lirendada
[liren@VM-8-7-centos gitcode]$ git log --pretty=oneline
c82c67bb370034ef67d0bde191252742fcc7d6f6 change readme
ac00e613b660a4d916a166d64ef518132d04bf34 add file5
ced585b446ebc42530ca850efc02195ae709cbad add file4
7eb10f50de9781d05a4a4af2134a8673352e89fa add 3 files
cdc96e6d432ea74b61b4bf36de4dc19f07310eb0 first add file:readme
[liren@VM-8-7-centos gitcode]$
8、刪除文件 – git rm
? 刪除文件其實也有指令,但是如果我們不用指令,直接刪掉工作區的文件,比如下面文件中的 readme:
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ rm readme #刪除工作區文件
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5[liren@VM-8-7-centos gitcode]$ git checkout -- readme #嘗試恢復,發現是可以的[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5 readme
[liren@VM-8-7-centos gitcode]$ cat readme
lirendada
[liren@VM-8-7-centos gitcode]$
? 其實這是沒刪干凈,因為我們只是刪了工作區的文件,此時可能暫存區或者版本庫中還有對應的文件,那這可不算是什么刪除文件!
? 其實刪除完之后,我們可以用 git status
指令就會告訴我們已經刪除了什么文件,如下所示:
[liren@VM-8-7-centos gitcode]$ rm readme
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: readme
#
no changes added to commit (use "git add" and/or "git commit -a")
? 所以如果想真的刪除的話,我們就得用 git commit
指令,將此時這個刪除信息也推送到版本庫中,此時才算是刪除完成!
?
這里就不使用這種方式了,我們直接使用 git rm
指令,下面是其一些常見選項:
- 將文件從暫存區和工作區中刪除:
git rm <file>
- 如果刪除之前修改過并且已經放到暫存區域的話,則必須要用強制刪除選項
-f
:git rm -f <file>
- 如果想把文件從暫存區域移除,但仍然希望保留在當前工作目錄中:
git rm --cached <file>
? 使用該指令之后,我們 依然得用 git commit
指令推送到版本庫中,版本庫才能知道此時需要刪除該文件啦:
[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5 readme[liren@VM-8-7-centos gitcode]$ git rm readme #刪除工作區和暫存區中該文件
rm 'readme'[liren@VM-8-7-centos gitcode]$ ls
file1 file2 file3 file4 file5
[liren@VM-8-7-centos gitcode]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# deleted: readme
#[liren@VM-8-7-centos gitcode]$ git commit -m 'delete readme' #需要commit后版本庫才會知道需要去刪除
[master 3131533] delete readme1 file changed, 1 deletion(-)delete mode 100644 readme
? 那要是我們不小心刪錯文件了怎么辦???
? 很簡單呀,此時就 轉變為了上面基本操作的第七點:撤銷修改
的問題 了!這里就不多解釋了,具體參考上面!