Git Reset 三種模式

有時候,我們用Git的時候有可能commit提交代碼后,發現這一次commit的內容是有錯誤的,那么有兩種處理方法:
1、修改錯誤內容,再次commit一次 2、使用git reset 命令撤銷這一次錯誤的commit
第一種方法比較直接,但會多次一次commit記錄。
而我個人更傾向第二種方法,錯誤的commit沒必要保留下來。
那么今天來說一下git reset。它的一句話概括

git-reset - Reset current HEAD to the specified state

意思就是可以讓HEAD這個指針指向其他的地方。例如我們有一次commit不是不是很滿意,需要回到上一次的Commit里面。那么這個時候就需要通過reset,把HEAD指針指向上一次的commit的點。
它有三種模式,soft,mixed,hard,具體的使用方法下面這張圖,展示的很全面了。

git各個區域和命令關系

這三個模式理解了,對于使用這個命令很有幫助。在理解這三個模式之前,需要略微知道一點Git的基本流程。正如上圖,Git會有三個區域:

  • Working Tree 當前的工作區域
  • Index/Stage 暫存區域,和git stash命令暫存的地方不一樣。使用git add xx,就可以將xx添加近Stage里面
  • Repository 提交的歷史,即使用git commit提交后的結果
文件存入Repository流程

以下簡單敘述一下把文件存入Repository流程:

  1. 剛開始 working tree 、 index 與 repository(HEAD)里面的內容都是一致的


    階段1
  2. 當git管理的文件夾里面的內容出現改變后,此時 working tree 的內容就會跟 index 及 repository(HEAD)的不一致,而Git知道是哪些文件(Tracked File)被改動過,直接將文件狀態設置為 modified (Unstaged files)。


    階段2
  3. 當我們執行 git add 后,會將這些改變的文件內容加入 index 中 (Staged files),所以此時working tree跟index的內容是一致的,但他們與repository(HEAD)內容不一致。


    階段3
  4. 接著執行 git commit 後,將Git索引中所有改變的文件內容提交至 Repository 中,建立出新的 commit 節點(HEAD)后, working tree 、 index 與與repository(HEAD)區域的內容 又會保持一致。


    階段4

實戰演示

reset --hard:重置stage區和工作目錄:

reset --hard 會在重置 HEADbranch的同時,重置stage區和工作目錄里的內容。當你在 reset 后面加了 --hard 參數時,你的stage區和工作目錄里的內容會被完全重置為和HEAD的新位置相同的內容。換句話說,就是你的沒有commit的修改會被全部擦掉。

例如你在上次 commit 之后又對文件做了一些改動:把修改后的ganmes.txt文件addstage區,修改后的shopping list.txt保留在工作目錄

git status

最初狀態

然后,你執行了reset并附上了--hard參數:

git reset --hard HEAD^

你的 HEAD 和當前 branch 切到上一條commit 的同時,你工作目錄里的新改動和已經add到stage區的新改動也一起全都消失了:

git status

reset --hard head^之后

可以看到,在 reset --hard 后,所有的改動都被擦掉了。

reset --soft:保留工作目錄,并把重置 HEAD 所帶來的新的差異放進暫存區

reset --soft 會在重置 HEADbranch 時,保留工作目錄和暫存區中的內容,并把重置 HEAD 所帶來的新的差異放進暫存區。

什么是「重置 HEAD 所帶來的新的差異」?就是這里:

由于 HEAD 從 4 移動到了 3,而且在 reset 的過程中工作目錄和暫存區的內容沒有被清理掉,所以 4 中的改動在 reset 后就也成了工作目錄新增的「工作目錄和 HEAD 的差異」。這就是上面一段中所說的「重置 HEAD 所帶來的差異」。

此模式下會保留 working tree工作目錄的內容,不會改變到目前所有的git管理的文件夾的內容;也會
保留 index暫存區的內容,讓 index 暫存區working tree 工作目錄的內容是一致的。就只有 repository 中的內容的更變需要與 reset 目標節點一致,因此原始節點與reset節點之間的差異變更集合會存在與index暫存區中(Staged files),所以我們可以直接執行 git commitindex暫存區中的內容提交至 repository 中。當我們想合并「當前節點」與「reset目標節點」之間不具太大意義的 commit 記錄(可能是階段性地頻繁提交)時,可以考慮使用 Soft Reset 來讓 commit 演進線圖較為清晰點。

所以在同樣的情況下,還是老樣子:把修改后的ganmes.txt文件addstage區,修改后的shopping list.txt保留在工作目錄

git status

最初狀態

假設此時當前 commit 的改動內容是新增了 laughters.txt 文件:

git show --stat
git show --stat

如果這時你執行:

git reset --soft HEAD^

那么除了 HEAD 和它所指向的 branch1 被移動到 HEAD^ 之外,原先 HEADcommit 的改動(也就是那個 laughters.txt 文件)也會被放進暫存區:

git status

使用git reset --soft HEAD^后

這就是--soft--hard 的區別:--hard 會清空工作目錄和暫存區的改動,*而 --soft則會保留工作目錄的內容,并把因為保留工作目錄內容所帶來的新的文件差異放進暫存區

reset 不加參數(mixed):保留工作目錄,并清空暫存區

reset 如果不加參數,那么默認使用 --mixed 參數。它的行為是:保留工作目錄,并且清空暫存區。也就是說,工作目錄的修改、暫存區的內容以及由 reset 所導致的新的文件差異,都會被放進工作目錄。簡而言之,就是「把所有差異都混合(mixed)放在工作目錄中」。

還以同樣的情況為例:

git status
最初狀態

修改了 的games.txt 和 shopping list.txt,并把 games.txt 放進了暫存區。

git show --stat
git show --stat

最新的 commit 中新增了 laughters.txt 文件。

這時如果你執行無參數reset或者帶--mixed參數:

git reset HEAD^
git reset --mixed HEAD^

工作目錄的內容和 --soft 一樣會被保留,但和 --soft 的區別在于,它會把暫存區清空,并把原節點和reset節點的差異的文件放在工作目錄,總而言之就是,工作目錄的修改、暫存區的內容以及由 reset 所導致的新的文件差異,都會被放進工作目錄

git status
git reset HEAD^之后

總結

reset 的本質:移動 HEAD 以及它所指向的 branch

實質上,reset 這個指令雖然可以用來撤銷 commit ,但它的實質行為并不是撤銷,而是移動 HEAD ,并且「捎帶」上 HEAD 所指向的 branch(如果有的話)。也就是說,reset 這個指令的行為其實和它的字面意思 "reset"(重置)十分相符:它是用來重置 HEAD 以及它所指向的 branch 的位置的。

reset --hard HEAD^ 之所以起到了撤銷 commit 的效果,是因為它把 HEAD 和它所指向的 branch 一起移動到了當前 commit 的父 commit 上,從而起到了「撤銷」的效果:

git reset

Git 的歷史只能往回看,不能向未來看,所以把 HEADbranch 往回移動,就能起到撤回 commit 的效果。

所以同理,reset --hard 不僅可以撤銷提交,還可以用來把 HEADbranch 移動到其他的任何地方。

git reset --hard branch2
git reset --hard branch2

reset三種模式區別和使用場景

區別:

  1. --hard:重置位置的同時,直接將 working Tree工作目錄index 暫存區repository 都重置成目標Reset節點的內容,所以效果看起來等同于清空暫存區和工作區。

  2. --soft:重置位置的同時,保留working Tree工作目錄index暫存區的內容,只讓repository中的內容和 reset 目標節點保持一致,因此原節點和reset節點之間的【差異變更集】會放入index暫存區中(Staged files)。所以效果看起來就是工作目錄的內容不變,暫存區原有的內容也不變,只是原節點和Reset節點之間的所有差異都會放到暫存區中。

  3. --mixed(默認):重置位置的同時,只保留Working Tree工作目錄的內容,但會將 Index暫存區Repository 中的內容更改和reset目標節點一致,因此原節點和Reset節點之間的【差異變更集】會放入Working Tree工作目錄中。所以效果看起來就是原節點和Reset節點之間的所有差異都會放到工作目錄中。

使用場景:

  1. --hard:(1) 要放棄目前本地的所有改變時,即去掉所有add到暫存區的文件和工作區的文件,可以執行 git reset -hard HEAD 來強制恢復git管理的文件夾的內容及狀態;(2) 真的想拋棄目標節點后的所有commit(可能覺得目標節點到原節點之間的commit提交都是錯了,之前所有的commit有問題)。

  2. --soft:原節點和reset節點之間的【差異變更集】會放入index暫存區中(Staged files),所以假如我們之前工作目錄沒有改過任何文件,也沒add到暫存區,那么使用reset --soft后,我們可以直接執行 git commit 將 index暫存區中的內容提交至 repository 中。為什么要這樣呢?這樣做的使用場景是:假如我們想合并「當前節點」與「reset目標節點」之間不具太大意義的 commit 記錄(可能是階段性地頻繁提交,就是開發一個功能的時候,改或者增加一個文件的時候就commit,這樣做導致一個完整的功能可能會好多個commit點,這時假如你需要把這些commit整合成一個commit的時候)時,可以考慮使用reset --soft來讓 commit 演進線圖較為清晰。總而言之,可以使用--soft合并commit節點

  3. --mixed(默認):(1)使用完reset --mixed后,我們可以直接執行 git add 將這些改變果的文件內容加入 index 暫存區中,再執行 git commitIndex暫存區 中的內容提交至Repository中,這樣一樣可以達到合并commit節點的效果(與上面--soft合并commit節點差不多,只是多了git add添加到暫存區的操作);(2)移除所有Index暫存區中準備要提交的文件(Staged files),我們可以執行 git reset HEADUnstage 所有已列入 Index暫存區 的待提交的文件。(有時候發現add錯文件到暫存區,就可以使用命令)。(3)commit提交某些錯誤代碼,或者沒有必要的文件也被commit上去,不想再修改錯誤再commit(因為會留下一個錯誤commit點),可以回退到正確的commit點上,然后所有原節點和reset節點之間差異會返回工作目錄,假如有個沒必要的文件的話就可以直接刪除了,再commit上去就OK了。

假如手賤,又想回退撤銷的版本呢?

請看另外一篇文章:TODO

參考文章:

https://dotblogs.com.tw/wasichris/2016/04/29/225157
https://www.domon.cn/2018/09/06/Git-reset-used-in-coding/
https://juejin.im/book/5a124b29f265da431d3c472e/section/5a14529bf265da43310d7351(掘金小冊)

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 天氣漸冷了,特別是雨天,風更大了些。我不喜歡溫度低風又大的天氣。早晨出門前看了手機天氣預報,也就沒忘記帶傘。可外面...
    栗子姬閱讀 193評論 0 0
  • 我說你是人間的四月天; 笑響點亮了四面風; 輕靈在春的光艷中交舞著變。 你是四月早天里的云煙, 黃昏吹著風的軟, ...
    郭發光閱讀 438評論 0 0
  • ??為人要學曾國藩,處世要學胡雪巖 胡雪巖(1823-1885),本名胡光墉, 字雪巖,出生于安徽徽州績溪,13歲...
    卡戳閱讀 498評論 0 0