GIT reset命令锁保,似乎讓人很迷惑除抛,以至于誤解狮杨,誤用。但是事實上不應(yīng)該如此難以理解到忽,只要你理解到這個命令究竟在干什么橄教。
一、首先我們來看幾個術(shù)語:
(一) HEAD
這是當前分支版本頂端的別名喘漏,也就是在當前分支你最近的一個提交
(二) Index
index也被稱為staging area护蝶,是指一整套即將被下一個提交的文件集合。他也是將成為HEAD的父親的那個commit
(三) Working Copy
working copy代表你正在工作的那個文件集
(四) Flow
當你第一次checkout一個分支翩迈,HEAD就指向當前分支的最近一個commit持灰。在HEAD中的文件集(實際上他們從技術(shù)上不是文件,他們是blobs(一團)负饲,但是為了討論的方便我們就簡化認為他們就是一些文件)和在index中的文件集是相同的堤魁,在working copy的文件集和HEAD,INDEX中的文件集是完全相同的。所有三者(HEAD,INDEX(STAGING),WORKING COPY)都是相同的狀態(tài)返十,GIT很happy妥泉。
當你對一個文件執(zhí)行一次修改,Git感知到了這個修改洞坑,并且說:“嘿盲链,文件已經(jīng)變更了!你的working copy不再和index,head相同迟杂!”刽沾,隨后GIT標記這個文件是修改過的。
然后逢慌,當你執(zhí)行一個git add,它就stages the file in the index悠轩,并且GIT說:“嘿,OK攻泼,現(xiàn)在你的working copy和index區(qū)是相同的火架,但是他們和HEAD區(qū)是不同的鉴象!”
當你執(zhí)行一個git commit,GIT就創(chuàng)建一個新的commit,隨后HEAD就指向這個新的commit何鸡,而index,working copy的狀態(tài)和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,那么你執(zhí)行
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是不一樣的吮炕。如果你運行g(shù)it checkout B,那么你講得到:
- A - B (HEAD) - C (master)
這時HEAD和master branch就不在一個點上了腊脱,你進入detached HEAD STATE. HEAD,work tree,index都指向了B,但是master branch卻依然指向C龙亲。如果在這個點上陕凹,你執(zhí)行一個新的commit D,那么你講得到下面(當然這可能并不是你想要的鳄炉,你可能想要的是創(chuàng)一個branch做bug fix):
- A - B - C (master) \ D (HEAD)
記住git reset不會產(chǎn)生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 狀態(tài)
(五) Reset
如果你仔細研究reset命令本身就知道磕仅,它本身做的事情就是重置HEAD(當前分支的版本頂端)到另外一個commit珊豹。假設(shè)我們有一個分支(名稱本身無所謂,所以我們就簡單稱為"super-duper-feature”分支吧)榕订,圖形化表示如下:
如果我們執(zhí)行:
git reset HEAD
任何事情都不會發(fā)生店茶,這是因為我們告訴GIT重置這個分支到HEAD,而這個正是它現(xiàn)在所在的位置劫恒。
git reset HEAD~1
當我們再執(zhí)行上面的命令時(HEAD~1是“the commit right before HEAD”的別名贩幻,或者說:put differently "HEAD's parent"),我們的分支將會如下所示:
如果我們執(zhí)行g(shù)it reset HEAD~2,則意味著將HEAD從頂端的commit往下移動兩個更早的commit两嘴。
(六) Parameters
-
soft
--soft參數(shù)告訴Git重置HEAD到另外一個commit丛楚,但也到此為止。如果你指定--soft參數(shù)憔辫,Git將停止在那里而什么也不會根本變化趣些。這意味著index,working copy都不會做任何變化,所有的在original HEAD和你重置到的那個commit之間的所有變更集都放在stage(index)區(qū)域中贰您。
182225251979460.png
如果我們執(zhí)行g(shù)it reset HEAD~2,則意味著將HEAD從頂端的commit往下移動兩個更早的commit坏平。
-
hard
--hard參數(shù)將會blow out everything.它將重置HEAD返回到另外一個commit(取決于~12的參數(shù))拢操,重置index以便反映HEAD的變化,并且重置working copy也使得其完全匹配起來舶替。這是一個比較危險的動作令境,具有破壞性,數(shù)據(jù)因此可能會丟失顾瞪!如果真是發(fā)生了數(shù)據(jù)丟失又希望找回來舔庶,那么只有使用:git reflog命令了。makes everything match the commit you have reset to.你的所有本地修改將丟失陈醒。如果我們希望徹底丟掉本地修改但是又不希望更改branch所指向的commit惕橙,則執(zhí)行g(shù)it reset --hard = git reset --hard HEAD. i.e. don't change the branch but get rid of all local changes.另外一個場景是簡單地移動branch從一個到另一個commit而保持index/work區(qū)域同步。這將確實令你丟失你的工作孵延,因為它將修改你的work tree吕漂!
182225251979460.png -
mixed(default)
--mixed是reset的默認參數(shù),也就是當你不指定任何參數(shù)時的參數(shù)尘应。它將重置HEAD到另外一個commit,并且重置index以便和HEAD相匹配,但是也到此為止吼虎。working copy不會被更改犬钢。所有該branch上從original HEAD(commit)到你重置到的那個commit之間的所有變更將作為local modifications保存在working area中,(被標示為local modification or untracked via git status)思灰,但是并未staged的狀態(tài)玷犹,你可以重新檢視然后再做修改和commit
182225251979460.png