git reset 命令原理
文章目錄
本文摘抄自《Pro Git》
git如何管理版本
認識git
git中有HEAD、Index和working Directory下表是他們的用途
名稱 | 用途 |
---|---|
HEAD | 上一次提交的快照,下一次提交的父結點 |
Index | 預期的s下一次提交的快照,可以理解爲暫存區 |
Working Directory | 工作目錄 |
HEAD 是當前分支引用的指針,它總是指向該分支上的最後一次提交.
Indox是預期的下一次提交。 也就是指向 Git 的 “暫存區域”,這就是當你運行 git commit 時 Git 看起來的樣子。
working directory 會將.git文件夾中的內容解包爲實際的文件以便編輯,
git的工作流程
git主要是操縱上述三個地方來實現其版本管理的功能的
下面我們來一步一步實現這個過程:
step1: 創建git
假設我們進入到一個新目錄,其中有一個文件。 我們稱其爲該文件的 v1 版本,將它標記爲藍色。 現在運行 git init,這會創建一個 Git 倉庫,其中的 HEAD 引用指向未創建的分支(master 還不存在)。
此時,只有工作目錄有內容
step2: 向索引中添加內容
現在我們想要提交這個文件,所以用git add
來獲取工作目錄中的內容,並將其複製到索引中
step3: 提交當前版本
運行git commit
,它會取得索引中的內容並將它保存爲一個永久的快照,然後創建一個指向該快照的提交對象,最後更新 master 來指向本次提交 現在我們來運行一下git status
命令發現沒有任何改動,這是因爲現在這三個地方的文件是相同的
step4: 對文件做改動
現在我們想要對文件進行修改然後提交它。 我們將會經歷同樣的過程;首先在工作目錄中修改文件。 我們稱其爲該文件的 v2 版本,並將它標記爲紅色。 如果現在運行 git status,我們會看到文件顯示在 “Changes not staged for commit,” 下面並被標記爲紅色,因爲該條目在索引與工作目錄之間存在不同。
step5: 將新修改加入暫存區
我們運行 git add 來將它暫存到索引中
此時,由於索引和 HEAD 不同,若運行 git status 的話就會看到 “Changes to be committed” 下的該文件變爲綠色 ——也就是說,現在預期的下一次提交與上一次提交不同
step6: 提交新修改
我們運行 git commit
來完成提交 現在我們來運行一下git status
命令發現沒有任何改動,這是因爲現在這三個地方的文件是相同的
以上就是git對版本控制的工作流程以及各個流程階段工作目錄,暫存區和本地倉庫的狀態
git的分支切換和克隆流程
切換分支或克隆的過程也類似。 當檢出一個分支時,它會修改 HEAD 指向新的分支引用,將 索引 填充爲該次提交的快照,然後將 索引 的內容複製到 工作目錄 中
重置
知道了git的工作流程,現在我們可以來看一下git是如何重置的.
假設我們再次修改了 file.txt 文件並第三次提交它。 現在的歷史看起來是這樣的:
step1: 移動HEAD(–soft)
reset
做的第一件事是移動 HEAD 的指向. (這與checkout改變 HEAD 自身是不同)
此時本地的狀態如下圖所示
該命令等同與git reset --soft HEAD~
如圖,它本質上是撤銷了上一次 git commit 命令。 當你在運行 git commit 時,Git 會創建一個新的提交,並移動 HEAD 所指向的分支來使其指向該提交。 當你將它 reset 退回 HEAD~(HEAD 的父結點)時,其實就是把該分支移動回原來的位置,而不會改變索引和工作目錄。
如果此時你運行git status
命令,你會看到如下輸出你現在可以直接使用git commit 將其提交
step2: 更新索引(–mixed)
接下來,reset 會用 HEAD 指向的當前快照的內容來更新索引
git在上一步的基礎上,取消了暫存區的所有東西,於是,我們回滾到了上次commit之後.
此時運行git status會看到如下輸出: reset 命令默認就是執行git reset --mixed HEAD~ 所以如果你運行git reset commitID
,git會爲你清空暫存區並將HEAD指針指向commitID的位置.
step3: 更新工作目錄(–hard)
如果你使用–hard選項,那麼git會爲你更新工作目錄
必須注意,–hard 標記是 reset 命令唯一的危險用法,它也是 Git 會真正地銷燬數據的僅有的幾個操作之一。 其他任何形式的 reset 調用都可以輕鬆撤消,但是 --hard 選項不能,因爲它強制覆蓋了工作目錄中的文件。 在這種特殊情況下,我們的 Git 數據庫中的一個提交內還留有該文件的 v3 版本,我們可以通過 reflog 來找回它。但是若該文件還未提交,Git 仍會覆蓋它從而導致無法恢復.
總結
在使用reset命令時,你可以通過指定參數來選擇你想要回滾的位置
- 移動該分支中HEAD的指向,保留暫存區和工作目錄中的數據 (–soft)
- 移動該分支中HEAD的指向,只保留工作目錄中的數據(–mixed)
- 移動該分支中HEAD的指向,清空暫存區和工作目錄(–hard)