我看到有趣的帖子解釋了關於git reset
微妙之處。 git
不幸的是,我讀的越多,我就越不能徹底理解它。 我來自SVN背景,Git是一個全新的範例。 我很容易變得善變,但Git更具技術性。 安全
我認爲git reset
接近hg revert
,但彷佛存在差別。 服務器
那麼git reset
究竟作了什麼? 請包括如下詳細說明: svn
--hard
, - --soft
和--merge
; HEAD
使用的奇怪符號,如HEAD^
和HEAD~1
; HEAD
和您的全球壓力水平的影響。 當您提交git的東西時,首先必須暫存(添加到索引)您的更改。 這意味着在git認爲它們是提交的一部分以前,你必須git添加你想要包含在這個提交中的全部文件。 讓咱們先來看看git repo的圖像: 工具
因此,如今很簡單。 咱們必須在工做目錄中工做,建立文件,目錄和全部。 這些更改是未跟蹤的更改。 要跟蹤它們,咱們須要使用git add命令將它們添加到git索引。 一旦將它們添加到git索引中。 若是咱們想將它推送到git存儲庫,咱們如今能夠提交這些更改。 學習
但忽然間咱們知道咱們提交了一個額外的文件,咱們在索引中添加了不須要推入git存儲庫。 這意味着咱們不但願索引中的該文件。 如今的問題是如何從git索引中刪除該文件,由於咱們使用git add將它們放在索引中,因此使用git rm是合乎邏輯的? 錯誤! git rm將簡單地刪除該文件並將刪除添加到索引中。 那麼如今該怎麼辦: ui
使用:- spa
git重置 線程
它清除您的索引,保持您的工做目錄不變。 (只是取消暫停一切)。 指針
它能夠與許多選項一塊兒使用。 使用git reset有三個主要選項: - hard, - soft和--mixed 。 重置時,這些會影響除HEAD指針以外的重置。
首先, - 硬重置一切。 您當前的目錄將徹底像您一直關注該分支同樣。 工做目錄和索引將更改成該提交。 這是我常用的版本。 git reset --hard就像svn revert 。
接下來,徹底相反的-soft ,不會重置工做樹和索引。 它只移動HEAD指針。 這使您的當前狀態的任何更改都與您在目錄中切換到的提交不一樣,而且「暫存」以進行提交。 若是您在本地進行提交但還沒有將提交推送到git服務器,則能夠重置爲先前的提交,並從新發送一個良好的提交消息。
最後, - mix複製索引,但不重置工做樹。 所以,全部更改仍然存在,可是「未分級」而且須要git add'ed或git commit -a 。 咱們有時會使用這個,若是咱們使用git commit -a承諾了更多,咱們可使用git reset -mixed返回提交,添加咱們想要提交的東西並提交它們。
git revert和git reset之間的區別 : -
在簡單的話,git的復位是「修復未提交的錯誤」和Git將其還原爲命令,以「修復COMMITED錯誤」的命令。
這意味着若是咱們在某些更改中犯了一些錯誤並提交併將其推送到git repo,那麼git revert就是解決方案。 若是咱們在推送/提交以前已經識別出相同的錯誤,咱們可使用git reset來解決問題。
我但願它能夠幫助你擺脫困惑。
通常來講, git reset
的功能是獲取當前分支並將其重置爲指向其餘位置,並可能帶來索引和工做樹。 更具體地說,若是您的主分支(當前已檢出)是這樣的:
- A - B - C (HEAD, master)
而且你意識到你但願master指向B而不是C,你將使用git reset B
將其移動到那裏:
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
題外話:這與結帳不一樣。 若是你運行git checkout B
,你會獲得這個:
- A - B (HEAD) - C (master)
你最終處於一個獨立的HEAD狀態。 HEAD
,工做樹,索引所有匹配B
,但主分支在C
處留下。 若是你在這一點上作了一個新的提交D
,你會獲得這個,這可能不是你想要的:
- A - B - C (master) \ D (HEAD)
請記住,reset不會進行提交,它只是更新一個分支(指向提交的指針)以指向不一樣的提交。 其他的只是索引和工做樹會發生什麼的詳細信息。
我git reset
在下一節中對各類選項的描述中介紹git reset
許多主要用例。 它能夠真正用於各類各樣的事情; 常見的線程是全部這些都涉及重置分支,索引和/或工做樹以指向/匹配給定的提交。
--hard
可能會讓你真的失去工做。 它會修改您的工做樹。
git reset [options] commit
會致使你(丟棄)提交。 在上面的玩具示例中,咱們丟失了提交C
它仍然在回購中,您能夠經過查看git reflog show HEAD
或git reflog show master
找到它,但它實際上不能從任何分支訪問。
Git會在30天后永久刪除此類提交,但在此以前,您能夠經過再次指向分支來恢復C( git checkout C; git branch <new branch name>
)。
解釋手冊頁,最多見的用法是git reset [<commit>] [paths...]
,它會將給定路徑重置爲給定提交的狀態。 若是未提供路徑,則重置整個樹,若是未提供提交,則將其視爲HEAD(當前提交)。 這是git命令的常見模式(例如checkout,diff,log,雖然確切的語義各不相同),因此它不該該太使人驚訝。
例如, git reset other-branch path/to/foo
全部內容重置爲其餘分支中的狀態, git reset -- .
將當前目錄重置爲HEAD中的狀態,而且簡單的git reset
會將全部內容重置爲HEAD中的狀態。
有四個主要選項能夠控制在重置期間工做樹和索引起生的狀況。
請記住,索引是git的「臨時區域」 - 當你說準備提交git add
時,事情就會發生。
--hard
使一切都與你重置的提交相匹配。 這多是最容易理解的。 您全部的本地更改都會被破壞。 一個主要用途是吹走你的工做而不是切換提交: git reset --hard
意味着git reset --hard HEAD
,即不要更改分支可是去除全部本地更改。 另外一種是簡單地將分支從一個地方移動到另外一個地方,並使索引/工做樹保持同步。 這能夠真正讓你失去工做,由於它會修改你的工做樹。 很是肯定你想在運行任何reset --hard
以前扔掉當地的工做 - reset --hard
。
--mixed
是默認值,即git reset
意味着git reset --mixed
。 它重置索引,但不重置工做樹。 這意味着您的全部文件都是完整的,但原始提交與您重置的文件之間的任何差別都將顯示爲具備git status的本地修改(或未跟蹤文件)。 當你意識到你作了一些很差的提交時,使用它,但你想保留你已經完成的全部工做,這樣你就能夠修復它並從新發送。 爲了提交,你必須再次將文件添加到索引( git add ...
)。
--soft
不會觸及索引或工做樹。 全部文件都與--mixed
同樣完整,但全部更改都顯示爲changes to be committed
使用git status changes to be committed
(即在準備提交時簽入)。 當你意識到你作了一些很差的提交時使用它,可是工做都很好 - 你須要作的就是以不一樣的方式從新發送它。 索引是不變的,所以您能夠根據須要當即提交 - 結果提交將具備與重置以前相同的內容。
--merge
最近被添加,旨在幫助您停止失敗的合併。 這是必要的,由於git merge
實際上容許您嘗試與髒工做樹(具備本地修改的工做樹)合併,只要這些修改在不受合併影響的文件中。 git reset --merge
重置索引(如--mixed
- 全部更改都顯示爲本地修改),並重置受合併影響的文件,但--mixed
其餘文件。 這將有望恢復在糟糕合併以前的一切。 你一般會將它用做git reset --merge
(意思是git reset --merge HEAD
),由於你只想重置合併,而不是實際移動分支。 ( HEAD
還沒有更新,由於合併失敗)
更具體地說,假設您已經修改了文件A和B,而且嘗試在修改了文件C和D的分支中進行合併。因爲某種緣由合併失敗,而且您決定停止它。 你使用git reset --merge
。 它將C和D帶回到它們在HEAD
,但僅對A和B進行修改,由於它們不是嘗試合併的一部分。
我確實認爲man git reset
對此很是有用 - 也許你須要對git的工做方式有一點了解才能真正沉入其中。 特別是,若是您花時間仔細閱讀它們,那些詳細說明索引和工做樹中全部各類選項和案例的文件狀態的表很是有用。 (可是,它們很是密集 - 它們以很是簡潔的形式傳達了大量上述信息。)
你提到的「奇怪的符號」( HEAD^
和HEAD~1
)只是指定提交的簡寫,而沒必要使用像3ebe3f6
這樣的哈希名稱。 它徹底記錄在git-rev-parse手冊頁的「指定修訂版」部分 ,包含大量示例和相關語法。 插入符號和波形符號實際上意味着不一樣的東西 :
HEAD~
是HEAD~1
縮寫,表示提交的第一個父級。 HEAD~2
表示提交的第一個父親的第一個父親。 將HEAD~n
想象爲「在HEAD以前提交n」或「HEAD的第n代祖先」。 HEAD^
(或HEAD^1
)也表示提交的第一個父級。 HEAD^2
表示提交的第二個父級。 請記住,正常的合併提交有兩個父級 - 第一個父級是合併的提交,第二個父級是合併的提交。 通常來講,合併實際上能夠有任意多的父母(章魚合併)。 ^
和~
運算符能夠串成,如在HEAD~3^2
,第三代祖先的第二個親本HEAD
, HEAD^^2
,的第一個親本的第二個親本HEAD
,甚至HEAD^^^
,至關於HEAD~3
。 請記住,在git
你有:
HEAD
指針 ,它告訴您正在進行的提交 請包括如下詳細說明:
--hard
, ---soft
和--merge
;
隨着危險程度的增長:
--soft
移動HEAD
但不觸及暫存區域或工做樹。 --mixed
移動HEAD
並更新暫存區域,但不更新工做樹。 --merge
移動HEAD
,重置暫存區域,並嘗試將工做樹中的全部更改移動到新的工做樹中。 --hard
移動HEAD
並將你的臨時區域和工做樹調整到新HEAD
,扔掉全部東西。 具體用例和工做流程;
--soft
。 你須要這個不多見。 -
# git reset --soft example touch foo // Add a file, make some changes. git add foo // git commit -m "bad commit message" // Commit... D'oh, that was a mistake! git reset --soft HEAD^ // Go back one commit and fix things. git commit -m "good commit" // There, now it's right.
-
當您想要查看另外一次提交時的內容時,請使用--mixed
(這是默認設置),但您不但願丟失已有的任何更改。
若是要移動到新位置,請使用--merge
,但將已有的更改合併到工做樹中。
使用--hard
擦除全部內容並在新提交中開始新的事件。
請注意,這是一個簡化的解釋,旨在做爲了解這一複雜功能的第一步。
對於想要在每一個命令以後可視化項目狀態的視覺學習者可能會有所幫助:
對於那些使用打開顏色的終端的人(git config --global color.ui auto):
git reset --soft A
你會看到B和C的東西是綠色的(上演並準備提交)
git reset --mixed A
(或git reset A
),你會看到B和C的東西是紅色的(未分階段,準備上演(綠色),而後提交)
git reset --hard A
你將不會再看到B和C的變化(就好像它們從未存在過)
或者對於那些使用像'Tower'或'SourceTree'這樣的GUI程序的人
git reset --soft A
,你會在'staged files'區域看到B和C的東西準備提交
git reset --mixed A
(或git reset A
),你會在'unstaged files'區域看到B和C的東西,準備移動到staged而後提交
git reset --hard A
你將不會再看到B和C的變化(就好像它們從未存在過)
TL; DR
git reset
Staging重置爲上次提交。 使用--hard
還能夠將工做目錄中的文件重置爲上次提交。
更長的版本
但這顯然是簡單化的,所以許多至關冗長的答案。 在撤消更改的上下文中,我更有意義地閱讀git reset
。 例如看到這個:
若是git revert是一種撤消更改的「安全」方式,您能夠將git reset視爲危險方法。 使用git reset撤消(而且任何ref或reflog再也不引用提交)時,沒法檢索原始副本 - 它是永久撤消。 使用此工具時必須當心,由於它是惟一可能丟失工做的Git命令之一。
來自https://www.atlassian.com/git/tutorials/undoing-changes/git-reset
還有這個
在提交級別,重置是一種將分支的提示移動到另外一個提交的方法。 這可用於從當前分支中刪除提交。
來自https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations