git reset soft,hard,mixed之區別深解

GIT reset命令,似乎讓人很迷惑,以至於誤解,誤用。但是事實上不應該如此難以理解,只要你理解到這個命令究竟在幹什麼。

首先我們來看幾個術語

  • HEAD

這是當前分支版本頂端的別名,也就是在當前分支你最近的一個提交

  • Index

index也被稱爲staging area,是指一整套即將被下一個提交的文件集合。他也是將成爲HEAD的父親的那個commit

  • Working Copy

working copy代表你正在工作的那個文件集

  • Flow

當你第一次checkout一個分支,HEAD就指向當前分支的最近一個commit。在HEAD中的文件集(實際上他們從技術上不是文件,他們是blobs(一團),但是爲了討論的方便我們就簡化認爲他們就是一些文件)和在index中的文件集是相同的,在working copy的文件集和HEAD,INDEX中的文件集是完全相同的。所有三者(HEAD,INDEX(STAGING),WORKING COPY)都是相同的狀態,GIT很happy。

當你對一個文件執行一次修改,Git感知到了這個修改,並且說:“嘿,文件已經變更了!你的working copy不再和index,head相同!”,隨後GIT標記這個文件是修改過的。

然後,當你執行一個git add,它就stages the file in the index,並且GIT說:“嘿,OK,現在你的working copy和index區是相同的,但是他們和HEAD區是不同的!”

當你執行一個git commit,GIT就創建一個新的commit,隨後HEAD就指向這個新的commit,而index,working copy的狀態和HEAD就又完全匹配相同了,GIT又一次HAPPY了。

下面這一段是另外一個牛人的解釋:

總的來說,git reset命令是用來將當前branch重置到另外一個commit的,而這個動作可能會將index以及work tree同樣影響。比如如果你的master branch(當前checked out)是下面這個樣子:

- A - B - C (HEAD, master)

HEAD和master branch tip是在一起的,而你希望將master指向到B,而不是C,那麼你執行

git reset B以便移動master branch到B那個commit:

- A - B (HEAD, master)      # - C is still here, but there's no branch pointing to it anymore

注意:git reset和checkout是不一樣的。如果你運行git checkout B,那麼你講得到:

- A - B (HEAD) - C (master)

這時HEAD和master branch就不在一個點上了,你進入detached HEAD STATE. HEAD,work tree,index都指向了B,但是master branch卻依然指向C。如果在這個點上,你執行一個新的commit D,那麼你講得到下面(當然這可能並不是你想要的,你可能想要的是創一個branch做bug fix):

- A - B - C (master)
       \
        D (HEAD)

記住git reset不會產生commits,它僅僅更新一個branch(branch本身就是一個指向一個commit的指針)指向另外一個commit(Head和branch Tip同時移動保持一致).其他的僅剩對於index和work tree(working directory)有什麼影響。git checkout xxxCommit則隻影響HEAD,如果xxxCommit和一個branch tip是一致的話,則HEAD和branch相匹配,如果xxxCommit並不和任何branch tip相一致,則git進入detached HEAD 狀態

 

 

  • Reset

如果你仔細研究reset命令本身就知道,它本身做的事情就是重置HEAD(當前分支的版本頂端)到另外一個commit。假設我們有一個分支(名稱本身無所謂,所以我們就簡單稱爲"super-duper-feature”分支吧),圖形化表示如下:

如果我們執行:

git reset HEAD

任何事情都不會發生,這是因爲我們告訴GIT重置這個分支到HEAD,而這個正是它現在所在的位置。

git reset HEAD~1

當我們再執行上面的命令時(HEAD~1是“the commit right before HEAD”的別名,或者說:put differently "HEAD's parent"),我們的分支將會如下所示

如果我們執行git reset HEAD~2,則意味着將HEAD從頂端的commit往下移動兩個更早的commit。

  • Parameters
  1. soft

--soft參數告訴Git重置HEAD到另外一個commit,但也到此爲止。如果你指定--soft參數,Git將停止在那裏而什麼也不會根本變化。這意味着index,working copy都不會做任何變化,所有的在original HEAD和你重置到的那個commit之間的所有變更集都放在stage(index)區域中。

 

  2.hard

--hard參數將會blow out everything.它將重置HEAD返回到另外一個commit(取決於~12的參數),重置index以便反映HEAD的變化,並且重置working copy也使得其完全匹配起來。這是一個比較危險的動作,具有破壞性,數據因此可能會丟失!如果真是發生了數據丟失又希望找回來,那麼只有使用:git reflog命令了。makes everything match the commit you have reset to.你的所有本地修改將丟失。如果我們希望徹底丟掉本地修改但是又不希望更改branch所指向的commit,則執行git reset --hard = git reset --hard HEAD. i.e. don't change the branch but get rid of all local changes.另外一個場景是簡單地移動branch從一個到另一個commit而保持index/work區域同步。這將確實令你丟失你的工作,因爲它將修改你的work tree!

  3.mixed(default)

--mixed是reset的默認參數,也就是當你不指定任何參數時的參數。它將重置HEAD到另外一個commit,並且重置index以便和HEAD相匹配,但是也到此爲止。working copy不會被更改。所有該branch上從original HEAD(commit)到你重置到的那個commit之間的所有變更將作爲local modifications保存在working area中,(被標示爲local modification or untracked via git status),但是並未staged的狀態,你可以重新檢視然後再做修改和commit

發佈了251 篇原創文章 · 獲贊 274 · 訪問量 73萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章