部分內容翻譯自:Resetting,Checking Out & Reverting
Introduction
在git中以下三個命令可以幫助代碼回滾。
- git reset
- git checkout
- git revert
checkout和reset通常是進行local或者private的撤銷。當push的時候會很容易發生沖突。
revert是一個對public撤銷安全的操作。因為會創建一個新的commit。
Prerequirements
可以看做three trees。
不同的操作對工作目錄、暫存區和commit history的影響。(index為暫存區)
Checkout
checkout可以把當前的HEAD指向某個具體的commit。
是commit級別或者文件級別的操作。文件級別會把文件內容變成要求的commit的內容。
git checkout
是commit histroy樹的更新。
Example
HEAD和Main當前都指向d

git checkout b
Revert
會用一個新的commit來撤銷指定的commit上的更改。
是commit級別的操作。不能用在文件級別。
Reset
reset會重置three trees到要求的commit。
git reset --hard commit_id
提交:
git push origin
回退到上一個版本:
git reset --hard HEAD^
Sum
總結三個命令的常用場景。
Command | Scope | Common use cases |
---|---|---|
git reset |
Commit-level | Discard commits in a private branch or throw away uncommited changes |
git reset |
File-level | Unstage a file |
git checkout |
Commit-level | Switch between branches or inspect old snapshots |
git checkout |
File-level | Discard changes in the working directory |
git revert |
Commit-level | Undo commits in a public branch |
git revert |
File-level | (N/A) |
Commit-Level Operations
Git reset和git checkout的scope由傳給他們的參數決定。如果沒有指定file path,那么就是commit-level。
Reset A Specific Commit
把hotfix分支移動到兩個commit之前。
git checkout hotfix git reset HEAD~2
reset通常用來撤回沒有和別人共享的commit。
除了撤回到之前的commit,也有可以用通過設置下列參數來更改暫存區或者工作目錄。
- --soft:不會改變暫存區或者工作目錄。(即原本的更新內容還在工作目錄和暫存區,但是commit id回到之前的。可以重新git commit)
- --mixed:暫存區會更新到指定的commit。但是工作目錄不受影響。默認參數。(可以重新編輯、然后add和commit)
- --hard:暫存區和工作目錄都會更新到指定的commit。(即指定commit之后的更新會全部消失)
Checkout old commit
checkout通常可以用來切換分支,即HEAD會從一個分支切換到另一個分支:
git checkout hotfix
因為可能會覆蓋本地的更改,所以git會強制我們commit或者stash所有的更改。
也可以用checkout來切換到之前的commit。例如:
git checkout HEAD~2
以為沒有任何的分支引用,所以這種情況的HEAD處於游離狀態。如果這個時候添加新的commit會非常危險,因為如果你切換到了其他的分支就沒有辦法再切回來了。所以HEAD處於游離狀態的時候,一定要新建一個分支來進行操作。
Undo Public Commits with Revert
revert會通過添加一個新的commit來撤銷一個commit。這是一個非常安全的撤銷操作。因為它不會更改原來的commit歷史。
git checkout hotfix git revert HEAD~2
這個操作會撤銷兩個commit之前的更新,但是是建立一個新的commit來實現的。
總的來說,git reset適合在private branch上使用,git revert適合在public上使用。
File-level Operations
Git Reset A Specific File
git reset會根據指定的commit id更新暫存區的內容。
git reset HEAD~2 foo.py
這個命令會按照兩個commit之前的內容來更新foo.py文件。
--soft、--mixed和--hard在file level上不會有任何影響。
Git Checkout File
git checkout會更改工作目錄。不會更改HEAD的引用。
git checkout HEAD~2 foo.py
請注意,這會刪除對文件的所有后續更改,而 git revert 命令僅撤消由指定提交引入的更改。