在講git的reset和checkout的區別之前,不得不說說head、index、working directory三個區域。
head、index、working directory
git裡有三個區域很重要
head 指向最近一次commit裡的所有snapshot
index 快取區域,只有index區域裡的東西才可以被commit
working directory 使用者操作區域
下**釋了這三個區域的狀態的變化過程:
初始狀態
當你checkout分支的時候,git做了這麼三件事情
將head指向那個分支的最後一次commit
將head指向的commit裡所有檔案的snapshot替換掉index區域裡原來的內容
將index區域裡的內容填充到working directory裡
所以你可以發現,head、index、working directory這個時候裡的內容都是一模一樣的。
注意:一般會誤解為,index中的內容是空的,只有git add後才會有東西。實際上不是,index裡一直是有東西的。
所以,git的所有操作就是對這三個區域的狀態(或內容)的操作。
changed
如果你在working directory裡修改了檔案,git會發現working directory裡的內容和index區域裡的內容不一致了。
這個時候git status的結果是:
staged
乙個檔案僅僅changed是不能被commit的,git要求只能提交index裡的東西。
所以需要git add。這個命令的意思是,把changed的檔案的內容同步到index區域裡。這樣working directory和index區域的內容就一致了。這個過程被稱之為stage
這個時候git status的結果是:
committed
最後,你就可以提交了
git commit
這樣,就把head的狀態和index以及working directory形成一致了。
reset
reset是用來修改提交歷史的,想象這種情況,如果你在2天前提交了乙個東西,突然發現這次提交是有問題的。
這個時候你有兩個選擇,要麼使用git revert(推薦),要麼使用git reset。
上圖可以看到git reset是會修改版本歷史的,他會丟棄掉一些版本歷史。
而git revert是根據那個commit逆向生成乙個新的commit,版本歷史是不會被破壞的。
已經push到遠端倉庫的commit不允許reset
上面已經講了,git reset是會丟棄掉commit的。
如果commit已經被push到遠端倉庫上了,也就意味著其他開發人員就可能基於這個commit形成了新的commit,這時你去reset,就會造成其他開發人員的提交歷史莫名其妙的丟失,或者其他災難性的後果。
因此,一旦commit已經被push到遠端倉庫,那麼是堅決不允許去reset它的。
不帶檔案引數的reset
前面章節已經說道git有三個區域,git的所有操作實際上是在操作這三個區域的狀態(或內容)。
git reset配合不同的引數,對這三個區域會產生不同的影響。
reset實際上有3個步驟,根據不同的引數可以決定執行到哪個步驟(–soft, –mixed, –hard)。
改變head所指向的commit(–soft)
執行第1步,將index區域更新為head所指向的commit裡包含的內容(–mixed)
執行第1、2步,將working directory區域更新為head所指向的commit裡包含的內容(–hard)
注意–mixed是預設引數,也就是說執行reset的時候不給就認為是–mixed。
下表說明了三種形式的git reset所產生的不同效果。
target代表想要將git指向到哪個commit
帶檔案引數的reset
上面講到的git reset實際上不帶引數的,如果帶上檔案引數,那麼效果會是怎樣的?
head不會動
將那個commit的snapshot裡的那個檔案放到index區域中
需要注意的是帶檔案引數的git reset沒有–hard, –soft這兩個引數。只有–mixed引數。
unstage
下面這兩個命令是一樣的,都是reset到head上。
git reset file.txt
git reset –mixed head file.txt
這個例子的意義在於,unstage file,仔細想一想是不是這樣?當你把乙個檔案stage到index區域裡後後悔了,那麼只需要把index區域裡的這個檔案恢復到最近一次commit的狀態(也就是head),那就相當於unstage了。
恢復到歷史版本
下面這個命令就是將某個檔案恢復到歷史版本上。
reset eb43bf file.txt
這個例子的意思在於,把某個檔案恢復到index區域裡,然後直接commit,這樣就等於把這個檔案恢復到歷史版本了,這樣依賴你都不需要去改動working directory了。
checkout
前面講到checkout是會修改head的指向,變更index區域裡的內容,修改working directory裡的內容。
這看上去很像reset –hard,但和reset –hard相比有兩個重要的差別
reset會把working directory裡的所有內容都更新掉
checkout不會去修改你在working directory裡修改過的檔案
reset把branch移動到head指向的地方
checkout則把head移動到另乙個分支
第二個區別可能有點難以理解,舉例來說:假設你有兩個分支master和develop,這兩個分支指向不一樣的commit,我們現在在develop分支上(head指向的地方)
如果我們git reset master,那麼develop就會指向master所指向的那個commit。
如果我們git checkout master,那麼develop不會動,只有head會移動。head會指向master。看圖:
帶檔案引數
當執行git checkout [branch] file時,checkout幹了這件事情:
更新了index區域裡file檔案的內容
更新了working directory裡file檔案的內容
總結reset和checkout
原文參見:
git的reset和revert的區別
針對問題1 使用git reset命令 1.git reset mixed 版本號 暫存區 add index區 和提交區 commit區 會回退到某個版本,但 不改變。2.git reset soft 版本號 提交區 commit區 會回退到某個版本,暫存區 add index區 不會回退,不改變...
Git命令 reset 和 revert 的區別
reset git reset soft mixed hard git revert no edit n mparent number s s git revert continue git revert quit git revert abortgit revert 用法是撤銷某次操作,此次操作之...
Git版本管理 reset
一 修改已 commit 的版本 檢視資料夾的資訊 git log oneline 輸出b17fed6 change 2 9be868c change 1 e44c7f7 creat demo.txt 有時候我們總會忘了什麼,比如已經提交了 commit 卻發現在這個 commit 中忘了附上另乙個...