1 回答

TA貢獻1869條經驗 獲得超4個贊
任何一個版本控制系統中,最有用的特性之一莫過于 逗撤銷(undo)地操作。在Git中,逗撤銷地有很多種含義。
當你完成了一次新的提交(commit),Git會及時存儲當前時刻倉庫(repository)的快照(snapshot);你能夠使用Git將項目回退到任何之前的版本。
下文中,我將列舉幾個常見的、需要逗撤銷地的場景,并且展示如何使用Git來完成這些操作。
一、撤銷一個公共修改 Undo a "public" change
場景:你剛剛用git push將本地修改推送到了GitHub,這時你意識到在提交中有一個錯誤。你想撤銷這次提交。
使用撤銷命令:git revert
發生了什么:git revert將根據給定SHA的相反值,創建一個新的提交。如果舊提交是逗matter地,那么新的提交就是逗anti-matter地——舊提交中所有已移除的東西將會被添加進到新提交中,舊提交中增加的東西將在新提交中移除。
這是Git最安全、也是最簡單的逗撤銷地場景,因為這樣不會修改歷史記錄——你現在可以git push下剛剛revert之后的提交來糾正錯誤了。
二、修改最近一次的提交信息 Fix the last commit message
場景:你只是在最后的提交信息中敲錯了字,比如你敲了git commit -m "Fxies bug #42",而在執行git push之前你已經意識到你應該敲"Fixes bug #42"。
使用撤銷命令:git commit –amend或git commit --amend -m "Fixes bug #42"
發生了什么:git commit –amend將使用一個包含了剛剛錯誤提交所有變更的新提交,來更新并替換這個錯誤提交。由于沒有staged的提交,所以實際上這個提交只是重寫了先前的提交信息。
三、撤銷本地更改 Undo "local" changes
場景:當你的貓爬過鍵盤時,你正在編輯的文件恰好被保存了,你的編輯器也恰在此時崩潰了。此時你并沒有提交過代碼。你期望撤銷這個文件中的所有修改——將這個文件回退到上次提交的狀態。
使用撤銷命令:git checkout --
發生了什么:git checkout將工作目錄(working directory)里的文件修改成先前Git已知的狀態。你可以提供一個期待回退分支的名字或者一個確切的SHA碼,Git也會默認檢出HEAD——即:當前分支的上一次提交。
注意:用這種方法逗撤銷地的修改都將真正的消失。它們永遠不會被提交。因此Git不能恢復它們。此時,一定要明確自己在做什么?。ɑ蛟S可以用git diff來確定)
四、重置本地修改 Reset "local" changes
場景:你已經在本地做了一些提交(還沒push),但所有的東西都糟糕透了,你想撤銷最近的三次提交——就像它們從沒發生過一樣。
使用撤銷命令:git reset或git reset --hard
發生了什么:git reset將你的倉庫紀錄一直回退到指定的最后一個SHA代表的提交,那些提交就像從未發生過一樣。默認情況下,git
reset會保留工作目錄(working
directory)。這些提交雖然消失了,但是內容還在磁盤上。這是最安全的做法,但通常情況是:你想使用一個命令來逗撤銷地所有提交和本地修改——那
么請使用--hard參數吧。
五、撤銷本地后重做 Redo after undo "local"
場景:你已經提交了一些內容,并使用git reset –hard撤銷了這些更改(見上面),突然意識到:你想還原這些修改!
使用撤銷命令:git reflog和git reset, 或者git checkout
發生了什么:git reflog是一個用來恢復項目歷史記錄的好辦法。你可以通過git reflog恢復幾乎任何已提交的內容。
你或許對git log命令比較熟悉,它能顯示提交列表。git reflog與之類似,只不過git reflog顯示的是HEAD變更次數的列表。
一些說明:
1. 只有HEAD會改變。當你切換分支時,用git commit提交變更時,或是用git
reset撤銷提交時,HEAD都會改變。但當你用git checkout --時,
HEAD不會發生改變。(就像上文提到的情形,那些更改根本就沒有提交,因此reflog就不能幫助我們進行恢復了)
2. git reflog不會永遠存在。Git將會定期清理那些逗不可達(unreachable)地的對象。不要期望能夠在reflog里找到數月前的提交記錄。
3. reflog只是你個人的。你不能用你的reflog來恢復其他開發者未push的提交。
因此,怎樣合理使用reflog來找回之前逗未完成地的提交呢看這要看你究竟要做什么:
1. 如果你想恢復項目歷史到某次提交,那請使用git reset --hard
2. 如果你想在工作目錄(working direcotry)中恢復某次提交中的一個或多個文件,并且不改變提交歷史,那請使用git checkout--
3. 如果你想確切的回滾到某次提交,那么請使用git cherry-pick。
六、與分支有關的那些事 Once more, with branching
場景:你提交了一些變更,然后你意識到你正在master分支上,但你期望的是在feature分支上執行這些提交。
使用撤銷命令:git branch feature, git reset --hard origin/master, 和 git checkout feature
發生了什么:你可能用的是git checkout -b來建立新的分支,這是創建和檢出分支的便捷方法——但實際你并不想立刻切換分支。git
branch feature會建立一個叫feature的分支,這個分支指向你最近的提交,但是你還停留在master分支上。
git reset --hard將master回退至origin/master,并忽略所有新提交。別擔心,那些提交都還保留在feature上。
最后,git checkout將分支切換到feature,這個分支原封不動的保留了你最近的所有工作。
七、事半功倍處理分支 Branch in time saves nine
場景:你基于master新建了一個feature分支,但是master分支遠遠落后與origin/master?,F在master分支與
origin/master同步了,你期望此刻能在feature下立刻commit代碼,并且不是在遠遠落后master的情況下。
使用撤銷命令:git checkout feature和git rebase master
發生了什么:你也許已經敲了命令:git reset(但是沒用--hard,有意在磁盤上保存這些提交內容),然后敲了git checkout -b,之后重新提交更改,但是那樣的話,你將失去本地的提交記錄。不過,一個更好的方法:
使用git rebase master可以做到一些事情:
1.首先,它定位你當前檢出分支和master之間的共同祖先節點(common ancestor)。
2.然后,它將當前檢出的分支重置到祖先節點(ancestor),并將后來所有的提交都暫存起來。
3.最后,它將當前檢出分支推進至master末尾,同時在master最后一次提交之后,再次提交那些在暫存區的變更。
- 1 回答
- 0 關注
- 682 瀏覽
添加回答
舉報