使用git時,如果對剛剛提交的后悔了怎么辦,如何撤銷?
方法一:手動修改
你把新增的文件刪了 或者 更改過的文件再改回來,然后再commit一次。這種方式不推薦,當修改量大的時候根本法沒法搞,雖然git diff可以幫助我們在最近兩次提交上做對比,但依然很難操作
方法二:使用reset命令
實際上,可以將reset其視為rollback(回滾”)- 將你的local environment指向以前的commit。 “本地環境”包括:local repository(本地存儲庫), staging area(暫存區域), and working directory(工作目錄)。
下圖是Git中的一系列提交記錄。 Git中的分支可以想象成一個指向特定提交命名的可移動指針。 在這種情況下,我們的主分支指向commit鏈中最新的提交。

查看提交歷史記錄
$ git log --oneline
b764644 File with three lines
7c709f0 File with two lines
9ef9173 File with one line
試想如果我們回滾到先前的提交會發生什么? 簡單 - 我們只需移動branch pointer(分支指針),Git提中reset命令就是為我們執行此操作的。 例如,如果我們想要將master重置為指向當前提交的兩個提交,我們可以使用以下任一方法:
$ git reset 9ef9173
或者
$ git reset current~2
下圖顯示此操作的結果。 在此之后,如果我們在當前分支(master)上執行git log命令,我們將只看到一個提交。
$ git log --oneline
9ef9173 File with one line

git reset命令還包括一些列參數,這些參數允許你使用最終提交的內容更新本地環境的其他部分。 這些選項包括:
hard:重置repository中branch pointer的指向,使用commit的內容填充working directory ,以及重置staging area(暫存區域)。
soft:僅重置repository中branch pointer的指向。
mixed:(默認值)重置repository中branch pointer的指向。重置staging area(暫存區域)。
使用這些選項在目標環境中非常有用,例如git reset --hard <commit sha1 | reference>。 這會覆蓋您尚未提交的任何本地更改。 實際上,它會重置(清除)staging area,並使用使用commit的內容填充working directory 。 在使用hard選項之前,請確保這是您真正想要做的事情,因為該命令會覆蓋任何未提交的更改。
方法三:使用revert命令
git revert命令的凈效果類似於reset,但其方法不同。 通常,reset的做法是移動分支指針到commit鏈其他位置,進而實現撤銷更改。revert命令會在鏈的末尾添加新的提交以“取消”更改。 見下圖,返回到只有兩行的版本的一種方法是reset當前提交,即git reset HEAD~1。另一種轉到兩行版本的方法是添加一個刪除三行版本的新提交 - 效果上等價於取消三行那個版本。 這可以使用git revert命令完成,例如:
$ git revert HEAD
由於這會添加一個新的提交,Git會提示commit消息:
Revert "File with three lines" This reverts commit b764644bad524b804577684bf74e7bca3117f554. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # modified: file1.txt #
下圖為revert操作后的commit鏈情況

如果我們執行git log,會看到之前的提交記錄
$ git log --oneline 11b7712 Revert "File with three lines" b764644 File with three lines 7c709f0 File with two lines 9ef9173 File with one line
當前工作目錄內容是
$ cat <filename> Line 1 Line 2
選擇revert還是reset?
如果您已經將commit鏈推送到遠端倉庫(其他人可能已經提取代碼並開始使用它),則revert是一種讓他人獲取更改的非常友好的方式。這是因為Git工作流很適合在分支結束時獲取額外的提交,這是因為 Git 工作流可以非常好地在分支的末端添加提交,但是當有人 reset 分支指針之后,會導致一些分支再也看不見(如果你記得住那些分支的sha1,是可以在reset回來的。但是怎么可能有人記得住那么多sha1)。
使用Git時的一個基本規則:在本地存儲庫中進行這些類型的更改,reset、revert都沒關系。但是,如果提交已經被推送到遠程倉庫而其他人可能正在使用它們的話,則不要做影響commit歷史紀錄的更改。
簡而言之,如果你rollback,undo或rewrite其他人正在使用的commit鏈的歷史記錄,那么當他們嘗試根據他們提取的原始鏈合並更改時,他們將會很頭疼。 如果您必須對已經被推送並且正由其他人使用的代碼進行更改,請在進行更改之前考慮進行通知,讓他人有機會合並自己的更改。 然后他們可以在侵權操作后提取新的副本而無需合並。
你可能已經注意到,在我們完成reset后,原始提交鏈仍然存在。 我們移動分支指針並將代碼重置為先前的commit,但它沒有刪除任何提交。 這意味着,只要我們知道分支指針的sha1,我們還能指回來。
git reset <sha1 of commit>
在替換commit時,我們在Git中執行的大多數其他操作中都會發生類似的事情。 創建新提交,並將分支指針移動到新的commit。 但舊的commit仍然存在。
