文章目錄
- Git 初識
- Git 安裝
- Linux-centos
- Linux-ubuntu
- Windows
- Git 基本操作
- 配置 Git
- 認識工作區、暫存區、版本庫
- 添加文件 -- 場景一
- 查看 .git 文件
- 添加文件 -- 場景二
- 修改文件
- 版本回退
- 撤銷修改
- 情況一:對于工作區的代碼,還沒有 add
- 情況二:已經 add ,但沒有 commit
- 情況三:已經 add ,并且也 commit 了
- 刪除文件
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
如果你的的平臺是centos,安裝git相當簡單,以我的centos7.6為例:
首先,你可以試著輸入Git,看看系統有沒有安裝Git:
$ git-bash: git: command not found
出現像上面的結果,Linux會友好地告訴你Git沒有安裝。
安裝 Git:
$ sudo yum -y install git
查看 Git 安裝的版本:
$ git --version
Linux-ubuntu
如果你的的平臺是ubuntu,安裝git相當簡單,以我的ubuntu22.04為例:
首先,你可以試著輸入git,看看系統有沒有安裝Git:
$ gitCommand 'git' not found, but can be installed with:sudo apt install git
出現像上面的結果,Linux會友好地告訴你Git沒有安裝,還會告訴你如何安裝Git。
安裝 Git:
$ sudo apt-get install git -y
查看 git 安裝的版本:
$ git --version
Windows
參考鏈接: Windows安裝Git-點擊即可https://www.bilibili.com/video
Git 基本操作
創建 Git 本地倉庫
要提前說的是,倉庫是進行版本控制的一個文件目錄。我們要想對文件進行版本控制,就必須先創建一個倉庫出來。
創建一個 Git 本地倉庫對應的命令為 git init
,注意命令要在文件目錄下執行,例如:
[root@MyComputer:~]# mkdir gitcode
[root@MyComputer:~]# cd gitcode
[root@MyComputer:gitcode]# pwd
/root/gitcode
[root@MyComputer:gitcode]# git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /root/gitcode/.git/
[root@MyComputer:gitcode]# ll -a
total 12
drwxr-xr-x 3 root root 4096 Jul 27 23:30 ./
drwx------ 14 root root 4096 Jul 27 23:30 ../
drwxr-xr-x 7 root root 4096 Jul 27 23:30 .git/
我們發現,當前目錄下多了一個 .git 的隱藏文件, .git 目錄是 Git 來跟蹤管理倉庫的,不要手動修改這個目錄里面的文件,不然改亂了,就把 Git 倉庫給破壞了。
其中包含 Git 倉庫的諸多細節,有興趣的同學可以進入看看。
[root@MyComputer:gitcode]# tree .git/
.git/
├── HEAD
├── branches
├── config
├── description
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ ├── push-to-checkout.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs├── heads└── tags
配置 Git
當安裝 Git 后首先要做的事情是設置你的 用戶名稱 和 e-mail 地址,這是非常重要的。配置命令為:
git config [--global] user.name "Your Name"git config [--global] user.email "email@example.com"# 把 Your Name 改成你的昵稱# 把 email@example.com 改成郵箱的格式,只要格式正確即可。
查看配置命令為:
git config -l
刪除對應的配置命令為:
git config [--global] --unset user.namegit config [--global] --unset user.email
[root@MyComputer:gitcode]# git config user.name "lwz" //配置你的名字
[root@MyComputer:gitcode]# git config user.email "2244514959@qq.com" //配置你的郵箱
[root@MyComputer:gitcode]# git config -l //查看配置
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
user.name=lwz
user.email=2244514959@qq.com
[root@MyComputer:gitcode]# git config --unset user.name //重置你的名字
[root@MyComputer:gitcode]# git config --unset user.email //重置你的郵箱
[root@MyComputer:gitcode]# git config -l //查看配置
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
[root@MyComputer:gitcode]# git config --global user.email "2244514959@qq.com"
[root@MyComputer:gitcode]# git config --global user.name "lwz"
[root@MyComputer:gitcode]# git config -l
user.email=2244514959@qq.com
user.name=lwz
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
[root@MyComputer:gitcode]# git config --global --unset user.email
[root@MyComputer:gitcode]# git config --global --unset user.name
[root@MyComputer:gitcode]# git config -l
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
其中 --global
是?個可選項。如果使用了該選項,表示這臺機器上所有的 Git 倉庫都會使用這個配置。如果你希望在不同倉庫中使用不同的 name 或 e-mail ,可以不要 --global
選項,但要注意的是,執行命令時必須要在倉庫里。
認識工作區、暫存區、版本庫
- 工作區:是在電腦上你要寫代碼或文件的目錄。
- 暫存區:英文叫 stage 或 index。一般存放在 .git 目錄下的 index 文件(.git/index)中,我們把暫存區有時也叫作索引(index)。
- 版本庫:又名倉庫,英文名 repository 。工作區有一個隱藏目錄 .git ,它不算工作區,而是 Git 的版本庫。這個版本庫里面的所有文件都可以被 Git管理起來,每個文件的修改、刪除,Git都能跟蹤,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以“還原”。
注意!!!!!!這句話一定要看!!!!!!!!!根據上面這個版本庫的定義,我們在這一篇文章中就可以看待成 本地倉庫 == 版本庫 == .git 目錄
下面這個圖展示了工作區、暫存區和版本庫之間的關系:
-
圖中左側為工作區,右側為版本庫。Git 的版本庫里存了很多東西,其中最重要的就是暫存區。
-
在創建 Git 版本庫時,Git 會為我們自動創建一個唯一的 master 分支,以及指向 master 的一個指針叫HEAD。
-
當對工作區修改(新增、修改、刪除)的文件執行
git add
命令時,暫存區目錄樹的文件索引會被更新。 -
當執行提交操作
git commit
時,master 分支會做相應的更新,也就是將暫存區的內容提交到版本庫的master分支,可以簡單理解為暫存區的目錄樹才會被真正寫到版本庫中。
由上述描述我們便能得知:通過新建或粘貼進目錄的文件,并不能稱之為向倉庫中新增文件,而只是在工作區新增了文件。必須要通過使用 git add 和 git commit 命令才能將文件添加到版本庫中進行管理!!!
添加文件 – 場景一
在包含 .git 的目錄下新建一個 ReadMe 文件,我們可以使用 git add 命令可以將文件添加到暫存區:
- 添加一個或多個文件到暫存區: git add [file1] [file2] …
- 添加指定目錄到暫存區,包括子目錄: git add [dir]
- 添加當前目錄下的所有文件改動到暫存區: git add .
再使用 git commit 命令將暫存區內容添加到版本庫中:
- 提交暫存區全部內容到版本庫中: git commit -m “message”
- 提交暫存區的指定文件到版本庫中: git commit [file1] [file2] … -m “message”
注意 git commit 后面的 -m 選項,要跟上描述本次提交的 message,由用戶自己完成,這部分內容絕對不能省略,并要好好描述,是用來記錄你的提交細節,是給我們人看的。
例如:
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git commit -m "commit my first file"
[master (root-commit) 77344dc] commit my first file1 file changed, 2 insertions(+)create mode 100644 ReadMe
git commit
命令執行成功后會告訴我們,1個文件被改動(就是我們新添加的ReadMe文件),插入了兩行內容(ReadMe有兩行內容)。
我們還可以多次 add 不同的文件,而只 commit 一次便可以提交所有文件,是因為需要提交的文件是通通被 add 到暫存區中,然后一次性 commit 暫存區的所有修改。如:
[root@MyComputer:gitcode]# touch file1 file2 file3
[root@MyComputer:gitcode]# git add file1 file2 file3
[root@MyComputer:gitcode]# git commit -m "add 3 file"
[master bd3e2aa] add 3 file3 files changed, 0 insertions(+), 0 deletions(-)create mode 100644 file1create mode 100644 file2create mode 100644 file3
截至目前為止,我們已經更夠將代碼直接提交至版本庫了。我們可以使用 git log
命令,來查看下歷史提交記錄:
[root@MyComputer:gitcode]# git log
commit bd3e2aa98e215d39febbe3c3abd282961525d611 (HEAD -> master)
Author: lwz <2244514959@qq.com>
Date: Mon Jul 28 10:26:00 2025 +0800add 3 filecommit 77344dcba2ba6304b9a55dc862a83ef555592982
Author: lwz <2244514959@qq.com>
Date: Mon Jul 28 10:23:31 2025 +0800commit my first file
如果這里不退出,最后一行就一個冒號,在英文輸入狀態下,按 q鍵即可。
該命令顯示從最近到最遠的提交日志,并且可以看到我們 commit 時的日志消息。
如果嫌輸出信息太多,看得眼花繚亂的,可以試試加上 --pretty=oneline
參數:
[root@MyComputer:gitcode]# git log --pretty=oneline
bd3e2aa98e215d39febbe3c3abd282961525d611 (HEAD -> master) add 3 file
77344dcba2ba6304b9a55dc862a83ef555592982 commit my first file
需要說明的是,我們看到的一大串類似 23807c5…56eed6 的是每次提交的 commit id (版本號),Git 的commit id 不是1,2,3……遞增的數字,而是一個 SHA1 計算出來的一個非常大的數字,用十六進制表示(你看到的 commit id 和我的肯定不?樣,以你自己的為準哦)
查看 .git 文件
先來看看我們的 .git 的目錄結構:
- index 就是我們的暫存區,add 后的內容都是添加到這里的。
- HEAD 就是我們的默認指向 master 分支的指針:
[root@MyComputer:gitcode]# cat .git/HEAD
ref: refs/heads/master
而默認的 master 分支,其實就是: 細心的人就知道這是什么了,往上翻一下就看到了,保存的就是當前最新的 commit id 。
[root@MyComputer:gitcode]# cat .git/refs/heads/master
bd3e2aa98e215d39febbe3c3abd282961525d611
- objects 為 Git 的對象庫,里面包含了創建的各種版本庫對象及內容。當執行
git add
命令時,暫存區的目錄樹被更新,同時工作區修改(新增、修改、刪除)的文件內容被寫入到對象庫中的一個新的對象中,就位于 “.git/objects” 目錄下,讓我們來看看這些對象有何用處:
[root@MyComputer:gitcode]# ls .git/objects/
25 4f 77 9d bd e6 info pack
查找 object 時要將 commit id 分成2部分,其前2位是文件夾名稱,后38位是文件名稱。
找到這個文件之后,一般不能直接看到里面是什么,該類文件是經過 sha (安全哈希算法)加密過的文件,好在我們可以使用 git cat-file
命令來查看版本庫對象的內容,后面跟一個-p
選項指的是打印出來的內容更優雅,更好看,其實就是-pretty:
[root@MyComputer:gitcode]# git cat-file -p bd3e2aa98e215d39febbe3c3abd282961525d611
tree 2546009580cb745d1603d79b29c5dcc1e0b7b6c3
parent 77344dcba2ba6304b9a55dc862a83ef555592982
author lwz <2244514959@qq.com> 1753669560 +0800
committer lwz <2244514959@qq.com> 1753669560 +0800add 3 file # 這就是我們最近?次的提交!
其中,還有一行 tree 2546009580cb745d1603d79b29c5dcc1e0b7b6c3 ,我們使用同樣的方法,看看結果:
[root@MyComputer:gitcode]# git cat-file -p 2546009580cb745d1603d79b29c5dcc1e0b7b6c3
100644 blob 9d261842fd570f4514ec7b8393f3f296b71a3459 ReadMe
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3
在看 ReadMe 對應的 9d261842fd570f4514ec7b8393f3f296b71a3459 :
[root@MyComputer:gitcode]# git cat-file -p 9d261842fd570f4514ec7b8393f3f296b71a3459
Hello lwz
Hello lwz
# 這是我們對ReadMe做的修改!!被git記錄了下來!!
總結一下,在本地的 git 倉庫中,有幾個文件或者目錄很特殊:
- index: 暫存區,
git add
后會更新該內容。 - HEAD: 默認指向 master 分支的一個指針。
refs/heads/master
: 文件里保存當前 master 分支的最新 commit id 。- objects: 包含了創建的各種版本庫對象及內容,可以簡單理解為放了 git 維護的所有修改。
后面再學習過程中,最好能將常見的 git 操作與 .git 目錄當中的結構內容變化對應起來,這樣有利于我們理解git 細節流程。我們后面還會學習什么分支,標簽什么的,那我想后面就應該學習對應著研究了!
添加文件 – 場景二
學習到這里,我們已經清楚了如何向版本庫中添加文件,并且對于工作區、暫存區、版本庫也有了一定的認識。那么我們再展示一種添加文件的場景,能加深對工作區、暫存區、版本庫的理解,示例如下:
[root@MyComputer:gitcode]# touch file6
[root@MyComputer:gitcode]# git add file6
[root@MyComputer:gitcode]# touch file7
[root@MyComputer:gitcode]# git commit -m "add new file"
[master b26397e] add new file1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 file6
提交后發現打印了 1 file changed, 0 insertions(+), 0 deletions(-) ,意思是只有一個文件改變了,這時我們提出了疑問,不是新增了兩個文件嗎?
再來回憶下, git add
是將文件添加到暫存區, git commit
是將暫存區的內容添加到版本庫中。由于我們并沒有使用 git add file7
,file7 就不在暫存區中維護,所以我們 commit 的時候其實只是把已經在暫存區的 file6 提交了,而遺漏了工作區的 file7。如何提交 file7 呢?很簡單,再次add , commit 即可。
[root@MyComputer:gitcode]# git add file7
[root@MyComputer:gitcode]# git commit -m "add file7"
[master fa52354] add file71 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 file7
修改文件
Git 比其他版本控制系統設計得優秀,因為 Git 跟蹤并管理的是修改,而非文件。
什么是修改?比如你新增了一行,這就是一個修改,刪除了一行,也是一個修改,更改了某些字符,也是一個修改,刪了一些又加了一些,也是一個修改,甚至創建一個新文件,也算一個修改。
讓我們將 ReadMe 文件進行一次修改:
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
此時,版本庫中的 ReadMe 和我們工作區的 ReadMe 是不同的,如何查看版本庫的狀態呢?
git status
命令用于查看在你上次提交之后是否有對文件進行再次修改。
[root@MyComputer:gitcode]# git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: ReadMeno changes added to commit (use "git add" and/or "git commit -a")
上面的結果告訴我們,ReadMe 被修改過了,但還沒有完成添加與提交。
目前,我們只知道文件被修改了,如果能知道具體哪些地方被修改了,就更好了。有人就會說,我剛改的我知道呀!可是,你還記得你三天前寫了什么代碼嗎?或者沒寫?
[root@MyComputer:gitcode]# git diff ReadMe
diff --git a/ReadMe b/ReadMe
index 9d26184..ee54fe7 100644
--- a/ReadMe # 原始文件
+++ b/ReadMe # 修改后文件
@@ -1,2 +1,3 @@ # 原始文件第1行開始的2行 → 修改后第1行開始的3行Hello lwz # 未修改行Hello lwz # 未修改行
+Hello world!!!! # 新增行
git diff [file]
命令用來顯示暫存區和工作區文件的差異,顯示的格式正是Unix通用的diff格式。也可以使用 git diff HEAD -- [file]
命令來查看版本庫和工作區文件的區別。
知道了對 ReadMe 做了什么修改后,再把它提交到本地倉庫就放心多了。
git add
之后,就沒有看到上面 no changes added to commit (use “git add” and/or “git commit -a”) 的消息了。接下來讓我們繼續 git commit 即可:
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git status
On branch master
Changes to be committed:(use "git restore --staged <file>..." to unstage)modified: ReadMe[root@MyComputer:gitcode]# git commit -m "Modify ReadMe"
[master 59ac2b9] Modify ReadMe1 file changed, 1 insertion(+)
[root@MyComputer:gitcode]# git status
On branch master
nothing to commit, working tree clean
版本回退
之前我們也提到過,Git 能夠管理文件的歷史版本,這也是版本控制器重要的能力。如果有一天你發現之前的工作做的出現了很大的問題,需要在某個特定的歷史版本重新開始,這個時候,就需要版本回退的功能了。
執行 git reset
命令用于回退版本,可以指定退回某一次提交的版本。要解釋一下“回退”本質是要將版本庫中的內容進行回退,工作區或暫存區是否回退由命令參數決定:
git reset
命令語法格式為: git reset [--soft | --mixed | --hard] [HEAD]
-
–mixed 為默認選項,使用時可以不用帶該參數。該參數將暫存區的內容退回為指定提交版本內容,工作區文件保持不變。
-
–soft 參數對于工作區和暫存區的內容都不變,只是將版本庫回退到某個指定版本。
-
–hard 參數將暫存區與工作區都退回到指定版本。切記工作區有未提交的代碼時不要用這個命令,因為工作區會回滾,你沒有提交的代碼就再也找不回了,所以使用該參數前一定要慎重。
-
HEAD 說明:
? 可直接寫成 commit id,表示指定退回的版本
? HEAD 表示當前版本
? HEAD^ 上一個版本
? HEAD^^ 上上一個版本
? 以此類推… -
可以使用 ?數字表示:
? HEAD~0 表示當前版本
? HEAD~1 上一個版本
? HEAD^2 上上一個版本
? 以此類推…
為了便于表述,方便測試回退功能,我們先做一些準備工作:更新3個版本的 ReadMe,并分別進行3次提交,如下所示:
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git commit -m "add version1"
[master b1daad2] add version11 file changed, 1 insertion(+)
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git commit -m "add version2"
[master 8d1af5b] add version21 file changed, 1 insertion(+)
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git commit -m "add version3"
[master d68ea84] add version31 file changed, 1 insertion(+)
[root@MyComputer:gitcode]# git log --pretty=oneline
d68ea84a1142d3d517478ff5715b428a5d32657d (HEAD -> master) add version3
8d1af5b1c416062bbf068fa904b83e7dd71edbc7 add version2
b1daad2ede33dd5fdb39fffe4b29383103eacdf4 add version1
現在,如果我們在提交完 version3 后, 發現 version3 編寫錯誤,想回退到 version2,重新基于 version2 開始編寫。由于我們在這里希望的是將工作區的內容也回退到 version2 版本,所以需要用到 --hard
參數,示例如下:
[root@MyComputer:gitcode]# git reset --hard 8d1af5b1c416062bbf068fa904b83e7dd71edbc7
HEAD is now at 8d1af5b add version2
我們驚奇的發現,此時 ReadMe 文件的內容,已經回退到 version2 了!,當前,我們再次用 git log
查看一下提交日志,發現 HEAD 指向了version2,如下所示:
[root@MyComputer:gitcode]# git log --pretty=oneline
8d1af5b1c416062bbf068fa904b83e7dd71edbc7 (HEAD -> master) add version2
b1daad2ede33dd5fdb39fffe4b29383103eacdf4 add version1
到這里一般回退功能就演示完了,但現在如果我后悔了,想再回到 version 3 怎么辦?
我們可以繼續使用 git reset
命令,回退到 version3 版本,但我們必須要拿到 version 3 的 commit id 去指定回退的版本。
但我們看到了 git log
并不能打印出 version3 的 commit id ,運氣好的話我們可以從終端上去找找之前的記錄,運氣不好的話 commit id 已經被我們搞丟了。
Git 還提供了一個 git reflog
命令能補救一下,該命令用來記錄本地的每一次命令。
8d1af5b (HEAD -> master) HEAD@{0}: reset: moving to 8d1af5b1c416062bbf068fa904b83e7dd71edbc7
d68ea84 HEAD@{1}: commit: add version3
8d1af5b (HEAD -> master) HEAD@{2}: commit: add version2
b1daad2 HEAD@{3}: commit: add version1
這樣,你就可以很方便的找到你的所有操作記錄了,但 d68ea84
這個是啥東西?
這個是 version3 的 commit id 的部分。沒錯,Git 版本回退的時候,也可以使用部分 commit id 來代表目標版本。示例如下:
# 退回到version3
[root@MyComputer:gitcode]# git reset --hard d68ea84
HEAD is now at d68ea84 add version3
# 查看log
[root@MyComputer:gitcode]# git log --pretty=oneline
d68ea84a1142d3d517478ff5715b428a5d32657d (HEAD -> master) add version3
8d1af5b1c416062bbf068fa904b83e7dd71edbc7 add version2
b1daad2ede33dd5fdb39fffe4b29383103eacdf4 add version1
可往往是理想很豐滿,現實很骨感。在實際開發中,由于長時間的開發了,導致 commit id 早就找不到了,可突然某一天,我又想回退到 version3,那該如何操作呢?貌似現在不可能了。。。
值得說的是,Git 的版本回退速度非常快,因為 Git 在內部有個指向當前分支(此處是master)的 HEAD 指針, refs/heads/master
文件里保存當前 master 分支的最新 commit id 。當我們在回退版本的時候,Git 僅僅是給 refs/heads/master
中存儲一個特定的version,可以簡單理解成如下示意圖:
撤銷修改
如果我們在我們的工作區寫了很長時間代碼,越寫越寫不下上一個版本。
情況一:對于工作區的代碼,還沒有 add
你當然可以直接刪掉你目前在工作區新增的代碼,像這樣:
[root@MyComputer:gitcode]# git status
On branch master
nothing to commit, working tree clean
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
This piece of code is like shit #新增代碼
[root@MyComputer:gitcode]# git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: ReadMeno changes added to commit (use "git add" and/or "git commit -a")# 直接刪除代碼
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
[root@MyComputer:gitcode]# git status
On branch master
nothing to commit, working tree clean
幸虧我們工作效率不高,才寫了一行代碼就發現不行了,要是你寫了3天,一直都沒有提交,該怎么刪掉呢?你自己都忘了自己新增過哪些,有人會說,我可以 git diff xxx
一下,看看差別在刪啊,那你肯定又要花3天時間刪代碼了,并且很大的概率還會改出bug。一周過去了,你怎么向你的老板交代呢?
Git 其實還為我們提供了更好的方式,我們可以使用 git checkout -- [file]
命令讓工作區的文件回到最近一次 add 或 commit 時的狀態。 要注意 git checkout -- [file]
命令中的 --
很重要,切記不要省略,一旦省略,該命令就變為其他意思了,后面我們再說。示例如下:
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
This piece of code is like shit #新增代碼# 恢復到上?次 add 或 commit
[root@MyComputer:gitcode]# git checkout -- ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
情況二:已經 add ,但沒有 commit
add 后還是保存到了暫存區呢?怎么撤銷呢?
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
This piece of code is like shit #新增代碼# add 存?暫存區
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git status
On branch master
Changes to be committed:(use "git restore --staged <file>..." to unstage)modified: ReadMe
讓我們來回憶一下學過的 git reset
回退命令,該命令如果使用 --mixed
參數,可以將暫存區的內容退回為指定的版本內容,但工作區文件保持不變。那我們就可以回退下暫存區的內容了!!!示例如下:
這個git reset HEAD ReadMe
命令作用:
- 取消暫存:如果之前使用 git add ReadMe 將 ReadMe 文件添加到了暫存區(stage/index),執行 git reset HEAD ReadMe 后,該文件會從暫存區中移除。
- 工作目錄不受影響:此命令僅修改暫存區,不會改變工作目錄中的文件內容。因此,對 ReadMe 文件的修改仍然存在,只是不再處于待提交狀態。
注意哦,HEAD:表示當前分支master的最新提交。
# --mixed 是默認參數,使?時可以省略
[root@MyComputer:gitcode]# git reset HEAD ReadMe
Unstaged changes after reset:
M ReadMe
用 git status
查看一下,發現現在暫存區是干凈的,工作區有修改。
[root@MyComputer:gitcode]# git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: ReadMeno changes added to commit (use "git add" and/or "git commit -a")
還記得如何丟棄工作區的修改嗎?
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
This piece of code is like shit #新增代碼[root@MyComputer:gitcode]# git checkout -- ReadMe[root@MyComputer:gitcode]# git status
On branch master
nothing to commit, working tree clean[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
恢復了!
情況三:已經 add ,并且也 commit 了
不要擔心,我們可以 git reset --hard HEAD^
回退到上一個版本!不過,這是有條件的,就是你還沒有把自己的本地倉庫推送到遠程倉庫。還記得Git是分布式版本控制系統嗎?我們后面會講到遠程倉庫,一旦你推送到遠程倉庫,你就真的慘了……
[root@MyComputer:gitcode]# vim ReadMe
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
This piece of code is like shit #新增代碼
[root@MyComputer:gitcode]# git add ReadMe
[root@MyComputer:gitcode]# git commit -m "test quash"
[master 084197a] test quash1 file changed, 1 insertion(+)
[root@MyComputer:gitcode]# git reset --hard HEAD^
HEAD is now at d68ea84 add version3
[root@MyComputer:gitcode]# cat ReadMe
Hello lwz
Hello lwz
Hello world!!!!
Hello Git
Hello version1
Hello version2
Hello version3
刪除文件
在 Git 中,刪除也是一個修改操作,我們實戰一下, 如果要刪除 file5 文件,怎么搞呢?如果你這樣做了:
[root@MyComputer:gitcode]# la
.git ReadMe file1 file2 file3 file4 file5 file6 file7
[root@MyComputer:gitcode]# rm file5
[root@MyComputer:gitcode]# la
.git ReadMe file1 file2 file3 file4 file6 file7
但這樣直接刪除是沒有用的,反而徒增煩惱, git status
命令會立刻告訴你哪些文件被刪除了:
[root@MyComputer:gitcode]# git status
On branch master
Changes not staged for commit:(use "git add/rm <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)deleted: file5no changes added to commit (use "git add" and/or "git commit -a")
此時,工作區和版本庫就不一致了,要刪文件,目前除了要刪工作區的文件,還要清除版本庫的文件。
一般走到這里,有兩種可能:
- 確實要從版本庫中刪除該文件
- 不小心刪錯了
對第二種情況,很明顯誤刪,需要使用 git 來進行恢復,很簡單,我們剛學過(刪除也是修改):
[root@MyComputer:gitcode]# git checkout -- file5
[root@MyComputer:gitcode]# la
.git ReadMe file1 file2 file3 file4 file5 file6 file7
對于第一種情況,很明顯是沒有刪完,我們只刪除了工作區的文件。這時就需要使用 git rm
將文件從暫存區和工作區中刪除,并且 commit :
[root@MyComputer:gitcode]# git rm file5
rm 'file5'
[root@MyComputer:gitcode]# git status
On branch master
Changes to be committed:(use "git restore --staged <file>..." to unstage)deleted: file5[root@MyComputer:gitcode]# git commit -m "deleted file5"
[master fef2e2e] deleted file51 file changed, 0 insertions(+), 0 deletions(-)delete mode 100644 file5
[root@MyComputer:gitcode]# git status
On branch master
nothing to commit, working tree clean
現在,文件就從版本庫中被刪除了。
我們刪除的本質就是將工作區、暫存區、版本庫全部同步的內容全部刪除,我們刪除第一個方法就是要三步,第二種方法就是兩步。所以更推薦第二種方法。