1. 程式人生 > >git撤銷修改各種情況

git撤銷修改各種情況

如何在Git裡撤銷(幾乎)任何操作

一、撤銷一個已經公開的改變

場景:已經執行了gitpush,將修改傳送到了github,需要撤銷某一個commit。

方法:git revert<commit版本號>,則改commit的所有改變都會被反轉。這是git最安全、最基本的撤銷場景。

二、修正最後一個commit訊息

場景:在最後一條commit訊息裡有一個筆誤,已經執行git commit –m’xxx’,但在push之前發現說明資訊有誤

方法:git commit–-amend 或者git commit –amend –m’正確的資訊’

原理:git commit–amend會用一個新的commit更新並替換最近的commit,這個心的commit會把任何修改內容和上一個commit的內容結合起來。如果當前沒有提出任何修改,這個操作會把上次的commit訊息重寫一遍。

三、撤銷本地修改

場景:git add後恢復,撤銷git add。

方法:git checkout– filename

此種撤銷會使任何修改完全消失,所以使用前最好用git diff確認下。

四、重置本地的修改

場景:在本地提交了一些東西(還沒有push),希望撤銷前面的三次提交。

方法:git reset <lastgood SHA>或git reset –hard <last good SHA>

原理:git reset會把程式碼庫歷史返回到指定的SHA狀態。這樣就像這些提交從來沒有發生過。預設情況下,git reset會保留工作目錄。這樣提交是沒有了,但是修改內容還在磁碟上。這是一種安全選擇,但通常希望一步就撤銷提交及修改內容,這就是—hard選項的功能了。

五、在撤銷了本地修改之後再恢復

場景:提交了幾個commit後,用git reset –-hard撤銷了這些修改,希望還原這些修改。

方法:git reflog和git reset或git checkout

原理:git reflog對於恢復專案歷史是一個超棒的資源。可以恢復幾乎任何東西——任何你commit過得東西。

一些注意事項:

l  它涉及的只是HEAD的改變。在切換分支、用git commit進行提交、以及用git reset撤銷commit時,HEAD都會改變,但是當用git checkout -- <bad filrname>時,HEAD並不會改變,因此reflog也無法恢復。

l  git reflog不會永遠保持。Git會定期清理那些用不到的物件,不要指望幾個月前的提交還在那裡。

l  不能用reflog來恢復另一個開發者沒有push過得commit。

l  如果下網準確恢復專案的歷史到某個時間點,用gitreset—hard<SHA>

l  如果希望重建工作目錄裡的一個或多個檔案,讓它們恢復到某個時間點的狀態,用git checkout <SHA> -- <filename>

l  如果希望把這些commit裡的某一個重新提交到程式碼庫,用git cherry-pick <SHA>

六、利用分支的另一種做法

場景:進行了一些提交,然後意識到開始check out的是master分支。希望提交到另一個分支(feature)。

方法:git branchfeature,git reset –-hard origin/master,and git checkoutfeature

原理:gitcheckout –b <name>建立新的分支,這是建立新分支並馬上check out的流行捷徑,但是如果不希望馬上切換分支。這裡。git branch feature建立一個叫做feature的新分支並指向最近的commit,但還是checkout在master分支上。下一步,在提及任何新的commit之前,用git reset –-hard把master分支倒回到origin/master。不過那些commit還在feature中。最後,用git checkout切換到新的feature分支,並且讓你最近所有的工作都完好無損。

七、在master繁殖的基礎上建立了feature分支,但master分支已經滯後origin/master很多。現在master分支已經和origin/master同步,你希望在feature上的提交從現在開始,而不是從滯後很多的地方開始。

方法:git checkoutfeature和git rebase master

原理:要達到這個效果,你本來可以通過git reset (不加,--hard,這樣可以在磁碟上保留修改)和git checkout –b <new branch name>然後再重新提交修改,不過這樣做的話就會失去提交歷史。

git rebase master會做如下事情:

Ø  首先他會找到你當前check out的分支和master分支的共同祖先。

Ø  然後它reset當前check out的分支到那個共同祖先,在一個臨時儲存區存放所有之前的提交。

Ø  然後它把當前check out的分支提交到master的末尾部分,並從臨時儲存區重新把存放的commit提交到master分支的最後一個commit之後。

八、大量的撤銷/恢復

場景:進行了很多次提交,但是發現只需要其中一部分,其他提交需要捨棄。

方法:git rebase–i <earlier SHA>

原理:-i 引數讓rebase進入“互動模式”。它開始類似於前面討論的rebase,但在重新進行提交之前,它會暫停下來並允許詳細修改每個提交。

rebase –I 會開啟你的預設文字編譯器,裡面列出候選的提交。前面兩列是鍵:第一個是選定命令,對應第二列裡的SHA確定的commit。預設情況下,rebase–i假定每個commit都要通過pick命令。

要丟棄一個commit,只要在編輯器裡刪除那一行就可以了。如果你需要commit的內容,而是對commit訊息進行編輯,可以使用reword命令。把第一列裡的pick替換為reword(或者直接用r)。有人會覺得這裡直接重寫commit訊息就行了,但是這樣不管用rebase –i會忽略SHA列前面的任何東西,它後面的文字只是來幫助我們記住這個commit是來幹嘛的。當你完成rebase –i的操作之後,你會被提示輸入需要編寫的任何commit訊息。

如果比需要把兩個commit合併到一起,可以使用squash或者fixup命令。Squash和fixup會向上合併,帶有這兩個命令的commit會被合併它的前一個commit裡。如果選擇squash,git會提示給新合併的commit一個新的commit訊息;fixup則會把合併清單裡第一個commit的訊息直接給新合併的commit。當你儲存並退出編輯器時,git會按從頂部到底部的順序運用你的commit。可以通過在儲存前修改commit順序來改變運用的順序。

九、停止追蹤一個檔案

場景:偶然把application.log加到程式碼庫裡了,現在每次執行應用,git都會報告在application.log裡有未提交的修改。你把*.login放到了.gitignore檔案裡,可檔案還是在程式碼庫裡,怎麼才能告訴git撤銷對這個檔案的追蹤呢?

方法:git rm –cachedapplication.log

原理:雖然.gitignore會阻止git追蹤檔案的修改,甚至不關心檔案是否存在,但這只是針對於那些以前從來沒有追蹤過得檔案。一旦有個檔案被加入提交,git就會持續關注該檔案的改變。如果你希望從git的追蹤物件中刪除那個本應忽略的檔案,git rm –-cached會從追蹤物件中刪除它,但讓檔案在磁碟上保持原封不動。因為現在它已經被忽略了,你再git status裡就不會再看見這個檔案,也不會再偶然提交該檔案的修改了。