目錄
添加文件
查看objects中的文件
小結(jié)
修改文件
版本回退
回退的回退
小結(jié)
撤銷修改
情況一:對于工作區(qū)的代碼,還沒有 add
情況二:已經(jīng) add ,但沒有 commit
情況三:已經(jīng) add ,并且也 commit 了
小結(jié)?
刪除文件
#:首先引入一個未進行任何操作的 ./git 內(nèi)部情況
[qcr@ecs-205826 project]$ 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
└── tags
9 directories, 13 files
? ? ? ? 我們可以找到對應的:objects、HEAD,但是沒有對應的index,master。
添加文件
-
添加一 個或多個文件 到暫存區(qū): git add [file1] [file2] ...
-
添加 指定目錄 到暫存區(qū),包括子目錄: git add [dir ]
-
添加當前目錄下的 所有文件 改動到暫存區(qū): git add .
- 提交暫存區(qū)全部內(nèi)容到本地倉庫中:git commit -m "message"
- 提交暫存區(qū)的指定文件到倉庫區(qū):git commit [file1] [file2] ... -m "message"
Note: git commit 后面的 -m 選項,描述本次提交的 message(由用戶自己完成),這部分內(nèi)容絕對不能省略,并且要好好描述,是用來記錄我們的提交細節(jié)。
????????可以看見 Git 的提示:一個文件改變,是新增了一行的內(nèi)容。
補充:
?$ git log
? ? ? ? 打印出來所有時間從近到遠的提交記錄。
[qcr@ecs-205826 project]$ git log commit e797df72c0669a2b81339ff4854328126d2e6c8e Author: qcr <2390139574@qq.com> Date: Wed Jun 14 19:29:48 2023 +0800 一行你好,用于學習git
? ? ? ? "e797df72c0669a2b81339ff4854328126d2e6c8e":commit ID,每一次提交都會有一個 commit ID,其是經(jīng)過哈希計算出來的非常大的一個數(shù)字(用十六進制表示)。
? ? ? ? 如果覺得這個內(nèi)容眼花繚亂的,可以給這個命令加一個選項參數(shù)。
[qcr@ecs-205826 project]$ git log --pretty=oneline e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git
? ? ? ? 現(xiàn)在再讓我們看一看 ./git?
[qcr@ecs-205826 project]$ 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
│?? ├── 38
│?? │?? └── 1feea9040943c8fa00ac3312d93ed7d97c42ff
│?? ├── e6
│?? │?? └── 076a05b53658ebd812398523da7f38fc552aa1
│?? ├── e7
│?? │?? └── 97df72c0669a2b81339ff4854328126d2e6c8e
│?? ├── info
│?? └── pack
└── refs
├── heads
│?? └── master
└── tags
15 directories, 21 files
????????可以發(fā)現(xiàn)其與之前沒進行任何操作的 ./git 多了很多很多的東西。而之前未出現(xiàn)的 index 出現(xiàn)了,就是由于 git add 而出現(xiàn)的暫存區(qū),而 add 的內(nèi)容就是添加到這個里面的。這個時候再來看?HEAD ,其就是一個指針,指向了 master 。
[qcr@ecs-205826 project]$ cat .git/HEAD
ref: refs/heads/master
????????通過查看我們可以發(fā)現(xiàn),其確實就是指向 master 的,并且該段路徑就是在 ./git 可以找到的。
? ? ? ? 然后我們打印 HEAD 內(nèi)指向的 master 內(nèi)容可以發(fā)現(xiàn)。
[qcr@ecs-205826 project]$ cat .git/refs/heads/master
e797df72c0669a2b81339ff4854328126d2e6c8e
? ? ? ? 這個 master 里面存放的其實就是最新的一次提交的?commit ID 。而之前又有所提到,master 里面放的都是一些索引,這些索引執(zhí)指向的又其實是對象庫中的對象。接下來再將我們的視角放在 objects 中多的東西上。
????????可以看到里面更新了一堆的對象,其實它們就是一些文件。
查看objects中的文件
? ? ? ? 首先我們要將 commit ID 分為兩個部分。
? ? ? ? 下述其實還有一項 parent??,后面跟的是commit ID 意為上一次的提交。
[qcr@ecs-205826 project]$ git cat-file -p e797df72c0669a2b81339ff4854328126d2e6c8e
tree 381feea9040943c8fa00ac3312d93ed7d97c42ff
author qcr <2390139574@qq.com> 1686742188 +0800
committer qcr <2390139574@qq.com> 1686742188 +0800
一行你好,用于學習git
????????-p:pertty更漂亮的打印出來。
? ? ? ? 其中的 tree 我們可以打印其后面的?commit ID 。
[qcr@ecs-205826 project]$ git cat-file -p 381feea9040943c8fa00ac3312d93ed7d97c42ff
100644 blob e6076a05b53658ebd812398523da7f38fc552aa1 test.txt
? ? ? ? 可以發(fā)現(xiàn)此處出現(xiàn)了我們前面的 test.txt 文件,并且其對應著一個 commit ID ,也就是對應一個索引,我們可以使用 cat-file 進行查看。
[qcr@ecs-205826 project]$ git cat-file -p e6076a05b53658ebd812398523da7f38fc552aa1
你好
????????可以發(fā)現(xiàn)正是我們在?test.txt 文件中新增的一行內(nèi)容,這就是我們對于test.txt文件的一次修改,被 Git 記錄下來了,所以我們每一次提交的修改都會被 Git 記錄下來,就是通過對象記錄下來的修改。對于objects一句話:修改的工作區(qū)內(nèi)容會被寫入到對象庫的一個新的git對象中。
小結(jié)
? ? ? ? git倉庫 中有一個?index(暫存區(qū)),用于放add后的一些新增內(nèi)容的。HEAD是一個指針,指向的是 .git/refs/heads/master ,master 里面存放的是我們最新的一次提交的 commit ID,其又是一個索引,對應著的是一個 git 對象,該對象被維護在對象庫中。對應的對象也有其 commit ID 進行查看,可以發(fā)現(xiàn)里面就有存放我們所修改的所有內(nèi)容。
Note:
????????明確一個觀念:Git 追蹤管理的其實是修改,而不是文件
? ? ? ? 并且這是可以在對象庫中體現(xiàn)出來,對象庫中的一個對象,里面存儲的是修改的工作區(qū)中的內(nèi)容。
修改文件
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
? ? ? ? 此時,在工作區(qū)中已經(jīng)對 test.txt 進行了更改,而 Git 中為我們提供了一個命令用于查看當前倉庫的一個狀態(tài)。
[qcr@ecs-205826 project]$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
? ? ? ? 用于查看我們上一次提交之后到現(xiàn)在是否對文件進行過修改,可以根據(jù)上述發(fā)現(xiàn):Changes not staged for commit(沒有將要被提交的暫存區(qū)內(nèi)容),也就是說暫存區(qū)中目前是干凈的沒有內(nèi)容。
? ? ? ? 修改的是在工作區(qū)中修改的,修改的文件就是 test.txt 。git status只能查哪個文件修改了,具體修改的是哪一些內(nèi)容是不知道的。Git 還提供了一個命令,用于顯示目前暫存區(qū)和工作區(qū)之間的差異的。
[qcr@ecs-205826 project]$ git diff test.txt
diff --git a/test.txt b/test.txt
index e6076a0..0891bd4 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
你好
+hello
[qcr@ecs-205826 project]$ git diff HEAD test.txt
diff --git a/test.txt b/test.txt
index e6076a0..0891bd4 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
你好
+hello
? ? ? ? 此時如果我們將 test.txt 文件進行上傳,再進行 diff 命令操作可以發(fā)現(xiàn)。暫存區(qū)和工作區(qū)文件的沒有了差異,于是什么都不會說明,而版本庫和工作區(qū)文件的之間還是有差異的。
[qcr@ecs-205826 project]$ git add test.txt
[qcr@ecs-205826 project]$ git diff test.txt
[qcr@ecs-205826 project]$ git diff HEAD test.txt
diff --git a/test.txt b/test.txt
index e6076a0..0891bd4 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
你好
+hello
? ? ? ? 使用 status 命令操作,其提示我們需要將修改提交至本地倉庫。
[qcr@ecs-205826 project]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: test.txt
#
? ? ? ? 提示了一個在暫存區(qū)中修改的文件:test.txt。
[qcr@ecs-205826 project]$ git commit -m "新增一行"
[master a8760f6] 新增一行
1 file changed, 1 insertion(+)
[qcr@ecs-205826 project]$ git diff test.txt
[qcr@ecs-205826 project]$ git diff HEAD test.txt
? ? ? ? 工作區(qū)、暫存區(qū)、版本庫全部一致,所以沒任何提示。
[qcr@ecs-205826 project]$ git status
# On branch master
nothing to commit, working directory clean
? ? ? ? 這一次我們已經(jīng)提交成功,所以給我們打印的一個狀態(tài)就是沒有什么可以提交了,工作區(qū)是干凈的。
版本回退
????????之前我們也提到過,Git 能夠管理文件的歷史版本,這也是版本控制器重要的能力。如果有?天你發(fā)現(xiàn)之前前的工作做的出現(xiàn)了很大的問題,需要在某個特定的歷史版本重新開始,這個時候,就需要版本回退的功能了。
????????執(zhí)行 git reset 命令用于回退版本,可以指定退回某?次提交的版本。要解釋?下 "回退" 本質(zhì)是要將版本庫中的內(nèi)容進行回退,工作區(qū)或暫存區(qū)是否回退由命令參數(shù)決定:
$ git reset [--soft | --mixed | --hard] [HEAD]
選項 | 具體功能 |
--soft | 參數(shù)對于工作區(qū)和暫存區(qū)的內(nèi)容都不變,只是將版本庫回退到某個指定版本 |
--mixed | 為默認選項,使用時可以不用帶該參數(shù)。該參數(shù)將暫存區(qū)的內(nèi)容退回為指定提交版本內(nèi)容,工作區(qū)文件保持不變。 |
--hard | 將暫存區(qū)與工作區(qū)都退回到指定版本。切記工作區(qū)有未提交的代碼時不要用這個命令,因為?作區(qū)會回滾,你沒有提交的代碼就再也找不回了,所以使用該參數(shù)前?定要慎重。 |
Note:關(guān)于 --hard 選項一定需要注意(慎用!?。。?/span>,如果當前正在工作區(qū)中進行開發(fā),一旦回退是會把正在開發(fā)的數(shù)據(jù)全部干掉,并且是不管如何操作都是找不回對應的開發(fā)數(shù)據(jù)的。
-
HEAD 說明:
- 可直接寫成 commit ID,表示指定退回的版本
- HEAD:表示當前版本
- HEAD^:上?個版本
- HEAD^^:上上?個版本
- 以此類推...
-
可以使用 ~ 數(shù)字表示:
- HEAD~0:表示當前版本
- HEAD~1:上?個版本
- HEAD^2:上上?個版本
- 以此類推...
????????現(xiàn)在之前的基礎(chǔ)上再提交幾個文件(用于實現(xiàn)效果的體現(xiàn)),下述?test1、test2、test3?是用一句 add 和一句 commit 提交的。
[qcr@ecs-205826 project]$ ls
test1 test2 test3 test.txt
[qcr@ecs-205826 project]$ git log --pretty=oneline
1bba34a04f231d8ad49f3ce5079879144cf6f4db 臨時空文件
8f2b55aca176fb578cf39952f776c3da9aa50009 新增一行
e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git
????????現(xiàn)在我們嘗試利用--hard 選項,回退到對應的提交。
[qcr@ecs-205826 project]$ git reset --hard e797df72c0669a2b81339ff4854328126d2e6c8e
HEAD is now at e797df7 一行你好,用于學習git
? ? ? ? 通過上述可以知曉回退成功了,接下來看看當前目錄的文件。
[qcr@ecs-205826 project]$ ls
test.txt
? ? ? ? 然而發(fā)現(xiàn),該目錄下只剩了一個 test.txt 文件,而?test1、test2、test3?不存在了。原因就是,我們使用的--hard 選項,將工作區(qū)也回退了,而?test1、test2、test3?的提交是在回退的提交之后的,所以一旦回退到某一次提交,那么這次提交之后的所有提交都會被回退。
? ? ? ? 此時再打印 test.txt 中的內(nèi)容可以發(fā)現(xiàn)。
[qcr@ecs-205826 project]$ cat test.txt
你好
? ? ? ? 回退成功,再打印 log 。
[qcr@ecs-205826 project]$ git log --pretty=oneline
e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git
? ? ? ? 發(fā)現(xiàn)我們回退的位子成為第一個了。
回退的回退
????????對應我們上一次查的log中,就會有被回退的提交(第一次回退的時候查找的log)。
[qcr@ecs-205826 project]$ git reset --hard 1bba34a04f231d8ad49f3ce5079879144cf6f4db
HEAD is now at 1bba34a 臨時空文件
[qcr@ecs-205826 project]$ ls
test1 test2 test3 test.txt
[qcr@ecs-205826 project]$ git log --pretty=oneline
1bba34a04f231d8ad49f3ce5079879144cf6f4db 臨時空文件
8f2b55aca176fb578cf39952f776c3da9aa50009 新增一行
e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git
? ? ? ? 可以發(fā)現(xiàn)全部回來了。而在這里有后悔藥可以吃,是因為當前終端下并沒有將之前的提交清除掉。
#:如果手殘的在想回退的回退時已將上一次log的信息,因為 clear 而消失,是也可以查到之前的 log 信息的,使用 reflog 命令。
[qcr@ecs-205826 project]$ git log --pretty=oneline e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git [qcr@ecs-205826 project]$ git reflog e797df7 HEAD@{0}: reset: moving to e797df72c0669a2b81339ff4854328126d2e6c8e 1bba34a HEAD@{1}: reset: moving to 1bba34a04f231d8ad49f3ce5079879144cf6f4db e797df7 HEAD@{2}: reset: moving to e797df72c0669a2b81339ff4854328126d2e6c8e 1bba34a HEAD@{3}: commit: 臨時空文件 8f2b55a HEAD@{4}: commit: 新增一行 e797df7 HEAD@{5}: reset: moving to e797df72c0669a2b81339ff4854328126d2e6c8e a8760f6 HEAD@{6}: commit: 新增一行 e797df7 HEAD@{7}: commit (initial): 一行你好,用于學習git
????????reflog 命令是用于記錄本地的每一次的提交命令。
? ? ? ? ?其就是對應提交的 commit ID,這么短是因為其就是?commit ID 的一部分,也是可以使用的。
[qcr@ecs-205826 project]$ git log --pretty=oneline e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git [qcr@ecs-205826 project]$ git reset --hard 1bba34a HEAD is now at 1bba34a 臨時空文件 [qcr@ecs-205826 project]$ git log --pretty=oneline 1bba34a04f231d8ad49f3ce5079879144cf6f4db 臨時空文件 8f2b55aca176fb578cf39952f776c3da9aa50009 新增一行 e797df72c0669a2b81339ff4854328126d2e6c8e 一行你好,用于學習git
????????這樣的前提下,是因為我們能夠找到 commit ID 才能吃后悔藥,而在開發(fā)的過程中是會有很多的 Git 操作,是遲早會將我們的 commit ID 沖掉的。而一旦找不到 commit ID 就沒有后悔藥可以吃了。
小結(jié)
? ? ? ? 值得說的是,Git 的版本回退速度非???,因為 Git 在內(nèi)部有個指向當前分支(此處是master)的 HEAD 指針, refs/heads/master 文件里保存當前 master 分?的最新 commit ID?。當我們在回退版本的時候,Git 僅僅是給 refs/heads/master 中存儲?個特定的 version,可以簡單理解成如下示意圖:
? ? ? ? 所以版本回退其實就是將 master 中的 commit ID 進行改變,也就是將指向進行改變,于是版本的回退是十分的簡單的、快速的。
撤銷修改
????????如果我們在我們的工作區(qū)寫了很長時間代碼,越寫越寫不下去,覺得自己寫的實在是垃圾,想恢復到上?個版本。
情況一:對于工作區(qū)的代碼,還沒有 add
? ? ? ? 這個時候由于我們并沒有進行 add 的操作,所以文件只存在于工作區(qū)中,在暫存區(qū)和版本庫中是沒有的,這個時候撤銷的內(nèi)容是工作區(qū)。
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
不喜歡這行想撤銷
? ? ? ? 這個時候選擇使用編輯文件,然后直接刪除這一行,這個方法肯定是沒有任何的問題的。但是如果寫了很多了,這個時候一行一行的去刪除很不現(xiàn)實,并且很容易就忘記了,并且不能保證手動刪除的準確性!
? ? ? ? ?Git 其實還為我們提供了更好的方式,我們可以使用 git checkout -- [file] 命令讓工作區(qū)的文件回到最近?次 add 或 commit 時的狀態(tài)。 要注意 git checkout -- [file] 命令中的 -- 很重要,切記不要省略,?旦省略,該命令就變?yōu)槠渌馑剂耍?/span>
[qcr@ecs-205826 project]$ git checkout -- test.txt
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
情況二:已經(jīng) add ,但沒有 commit
? ? ? ? 這個時候由于我們進行了 add 的操作,但是沒有進行 commit 操作,所以文件只存在于工作區(qū)與暫存區(qū)中,在版本庫中是沒有的,這個時候撤銷的內(nèi)容是工作區(qū)、暫存區(qū)。
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
不喜歡這行想撤銷
[qcr@ecs-205826 project]$ git add test.txt
[qcr@ecs-205826 project]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: test.txt
#
[qcr@ecs-205826 project]$ git reset HEAD test.txt
Unstaged changes after reset:
M test.txt
[qcr@ecs-205826 project]$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
? ? ? ? 這個時候我們就將暫存區(qū)中回退了,然后就是與情況一,一樣的情況。?
[qcr@ecs-205826 project]$ git checkout -- test.txt
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
情況三:已經(jīng) add ,并且也 commit 了
? ? ? ? 這個時候由于我們進行了 add 和commit 的操作,所以文件存在于工作區(qū)、暫存區(qū)、版本庫中,這個時候撤銷的內(nèi)容是工作區(qū)、暫存區(qū)、版本庫。
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
不喜歡這行想撤銷
[qcr@ecs-205826 project]$ git add test.txt
[qcr@ecs-205826 project]$ git commit -m "用于測試修改"
[master a2fd08f] 用于測試修改
1 file changed, 1 insertion(+)
????????不要擔心,我們可以 git reset --hard HEAD^ 回退到上?個版本!不過,這是有條件的:就是你還沒有把自己的本地版本庫推送到遠程倉庫(commit之后對應push操作,后續(xù)再講解)。撤銷的目的就是:不影響遠程倉庫的代碼。因為我們不知道遠程倉庫中對應的代碼是怎么樣的,所以我們想要撤退的操作的前提是遠程倉庫中確定沒有這一份代碼,才能真正意義上稱作為撤銷。
[qcr@ecs-205826 project]$ git reset --hard HEAD^
HEAD is now at 1bba34a 臨時空文件
[qcr@ecs-205826 project]$ git status
# On branch master
nothing to commit, working directory clean
[qcr@ecs-205826 project]$ cat test.txt
你好
hello
小結(jié)?
工作區(qū) | 暫存區(qū) | 版本庫 | 解決方式 |
---|---|---|---|
新文件 | 舊文件 | 舊文件 | 1、手動撤銷 - 不推薦,易出錯 2、git checkout -- [filename] |
新文件 | 新文件 | 舊文件 | git reset?--mixed(變?yōu)樯鲜銮闆r) git reset --hard HEAD |
新文件 | 新文件 | 新文件 | 前提條件:commit之后沒有進行push git reset --hard HEAD^ |
刪除文件
????????在 Git 中,刪除也是?個修改操作,我們實戰(zhàn)?下,如果要刪除 test.txt?文件,怎么搞?
[qcr@ecs-205826 project]$ ls
test1 test2 test3 test.txt
[qcr@ecs-205826 project]$ rm test3
[qcr@ecs-205826 project]$ ls
test1 test2 test.txt
????????但這樣直接刪除是沒有用的,反而徒增煩惱,其只是將我們對應的工作區(qū)中的內(nèi)容進行刪除,但是對于本地倉庫是并沒有刪除的,?git status 命令會立刻告訴你哪些文件被刪除了:
[qcr@ecs-205826 project]$ 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: test3
#
no changes added to commit (use "git add" and/or "git commit -a")
- 確實要從版本庫中刪除該文件
- 不小心刪錯了
????????對第?種情況,很明顯誤刪,需要使用?git 來進行恢復,很簡單,我們剛學過:文章來源:http://www.zghlxwxcb.cn/news/detail-501639.html
[qcr@ecs-205826 project]$ git checkout -- test3
[qcr@ecs-205826 project]$ ls
test1 test2 test3 test.txt
[qcr@ecs-205826 project]$ git rm test3
rm 'test3'
[qcr@ecs-205826 project]$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# deleted: test3
#
? ? ? ? 可以看出對比前面,其即刪除了工作區(qū)里的文件,也刪除了暫存區(qū)中的文件,然后就只需要我們進行 commit 就可以了。文章來源地址http://www.zghlxwxcb.cn/news/detail-501639.html
[qcr@ecs-205826 project]$ git commit -m "刪除test3"
[master dccd2a4] 刪除test3
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 test3
到了這里,關(guān)于【Git原理與使用】-- 基本操作的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!