上篇文章講過了Git合并分支,這里不多做講述,在開發(fā)中,有可能遇到的情況是可能有個bug在上個節(jié)點已經(jīng)提交過了,這個版本有復(fù)現(xiàn),現(xiàn)在需要再次測試上個節(jié)點的代碼,怎么辦?
那么我們今天研究一下git reset 和git revert的區(qū)別和聯(lián)系。
先看下git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
git reset [<mode>][<commit>]
目的是重置當前分支的head指向到commit,并根據(jù)model更新索引(將其重置為<commit>),如果省略model,則默認model是--mixed。model必須是下邊的列表:
--soft
不用修改索引文件和工作樹(和所有模式一樣,將head指向commit),這和git status一樣,將保存所有要提交的更改。
--mixed
重置索引,但不重置工作樹(即保留更改的文件,但不標記為提交),并報告未更新的內(nèi)容。這是默認操作。(需要重新添加git add)
如果指定了-n,則刪除的路徑將標記為有意添加
--hard
重置索引樹和工作樹。自<commit>之后,對工作樹中跟蹤文件的任何更改都將被丟棄。
--merge
重置索引并更新工作樹中<commit>和head之間不同的文件,但保留索引和工作樹之間不同的文件(即具有未添加的更改)。如果在<commit>和索引之間不同的文件有未分頁的更改,重置將中止。
換句話說,--merge執(zhí)行類似于git read tree-u-m<commit>的操作,但會轉(zhuǎn)發(fā)未合并的索引項。
--keep
重置索引項并更新工作樹中<commit>和head之間不同的文件。如果<commit>和head之間不同的文件發(fā)生了本地更改,重置將中止。
If you want to undo a commit other than the latest on a branch,is your friend.
如果你不想取消當前分支的最近的commit,請看一下git revert 。這下邊會講。
我們造一個demo如下:

現(xiàn)在我們的HEAD指向節(jié)點d248cd,但是我們想看節(jié)點的file_2的代碼,
我們執(zhí)行命令
git reset --soft head^1
Yong:test_git_revert Yong$ git log --graph
* commit b53ccde9dce1691b555dd5e42c8eb346f736ef81 (HEAD -> master)
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 14:29:07 2019 +0800
|
| add file_2
|
* commit f5f2498c24c2771f906c2a1ac02b540f092fdcbb
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 14:28:55 2019 +0800
|
| add file_1
|
* commit e002e347a24ad3079b283156887a7e7d67f881cc
Author: fanguangyong <fanguangyong@xqafu.com>
Date: Fri May 10 14:28:05 2019 +0800
Initial Commit
然后add file_3不見了,
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: test_git_revert/ViewController.m
可以看出來 代碼回退過來了,剛才提交的記錄也沒了,只是將head指針前移動了一個,但是修改的test_git_revert/ViewController.m文件是更改了,想要執(zhí)行代碼,還是所有的代碼,緊緊是記錄回退了,代碼卻是所有的代碼(代碼未動),只是工作區(qū)的 跟蹤狀態(tài)不一樣。

如何測試完了在次更新到最新的節(jié)點呢?
Yong:test_git_revert Yong$ git commit -am 'add file_3_repeat'
[master 200cb3f] add file_3_repeat
1 file changed, 1 deletion(-)
Yong:test_git_revert Yong$ git log --graph
* commit 200cb3fddf04c03cb1661bf7dc9e7f84525c28b3 (HEAD -> master)
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 17:01:15 2019 +0800
|
| add file_3_repeat
|
* commit b53ccde9dce1691b555dd5e42c8eb346f736ef81
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 14:29:07 2019 +0800
|
| add file_2
|
* commit f5f2498c24c2771f906c2a1ac02b540f092fdcbb
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 14:28:55 2019 +0800
|
| add file_1
|
* commit e002e347a24ad3079b283156887a7e7d67f881cc
Author: fanguangyong <fanguangyong@xqafu.com>
Date: Fri May 10 14:28:05 2019 +0800
Initial Commit
剛才add file_3已經(jīng)消失了,因為又提交了一次,message變成了add file_3_repeat,新增了一條提交記錄。
那么我們修改一下文件,當前status是:

然后執(zhí)行回滾
git reset --soft head^1
結(jié)果是:

則沒有提交緩存去的文件沒有丟失,回滾的代碼的狀態(tài)是追蹤,但是沒添加到緩存區(qū)。
測試完成當前版本的時候,則再次
git add
--mixed
Yong:test_git_revert Yong$ git reset --mixed head^1
Unstaged changes after reset:
M test_git_revert/ViewController.m
Yong:test_git_revert Yong$ git log --graph
* commit b53ccde9dce1691b555dd5e42c8eb346f736ef81 (HEAD -> master)
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 14:29:07 2019 +0800
|
| add file_2
|
* commit f5f2498c24c2771f906c2a1ac02b540f092fdcbb
| Author: fanguangyong <fanguangyong@xqafu.com>
| Date: Fri May 10 14:28:55 2019 +0800
|
| add file_1
|
代碼混滾了,直接輸出了最后的一次更改。提交的記錄也丟失。
修改好代碼 執(zhí)行 git add。

--hard

執(zhí)行之后查看本地git緩存區(qū)的數(shù)據(jù)有變化嗎?

--hard丟失節(jié)點3的數(shù)據(jù)。

再測試一下本地有未追蹤的文件的時候:

然后回滾代碼:

文件丟失了怎么找回呢?那么我們測試一下
git reflog看看能不能找回?
現(xiàn)在我們的head指向
2b8edf8,那么我們讓head指向到e55c3e4
$ git reset --hard head@{1}
HEAD is now at e55c3e4 add file3

我們執(zhí)行查找lost的命令:
git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling commit e55c3e450d0a743b6a64db248065b3fdece153d1
dangling blob 6c3bfcdf65a27027ca3168bf2981487fa4ad5dfa
e55c3e450d0a743b6a64db248065b3fdece153d1是我們最后提交的代碼節(jié)點,
6c3bfcdf65a27027ca3168bf2981487fa4ad5dfa是我們最后add之后形成的commit
然后執(zhí)行git show 6c3bfcdf65a27027ca3168bf2981487fa4ad5dfa

如果該條記錄數(shù) 是
dangling commit id類型直接使用git merge commit_id即可實現(xiàn)數(shù)據(jù)恢復(fù),如果是dangling blob id類型則需要使用git show 6c3bfcd> somefileName將其轉(zhuǎn)儲到文件或者使用使用腳本下載本數(shù)據(jù)寫入到相關(guān)的文件最后修改的文件成功找回。
那么不會回退節(jié)點怎么處理呢?
git給我們提供了git revert,會形成一個新的節(jié)點。
名稱
git-revert- 恢復(fù)一些現(xiàn)有的提交
描述
給定一個或多個現(xiàn)有提交,還原相關(guān)修補程序引入的更改,并記錄一些記錄它們的新提交。這需要您的工作樹是干凈的(沒有HEAD提交的修改)。
注意:git revert用于記錄一些新的提交以反轉(zhuǎn)某些早期提交的效果(通常只有一個錯誤的提交)。如果你想丟棄工作目錄中所有未提交的更改,你應(yīng)該看到git-reset [1],特別是--hard選項。如果你想在另一個提交中提取特定文件,你應(yīng)該看到git-checkout [1],特別是git checkout <commit> -- <filename>語法。請注意這些替代方案,因為它們都會丟棄工作目錄中未提交的更改。
--continue
使用.git / sequencer中的信息繼續(xù)正在進行的操作 。可以在解決失敗的挑選或恢復(fù)中的沖突后繼續(xù)使用。
-- quit
忘記當前正在進行的操作。在櫻桃挑選或恢復(fù)失敗后,可用于清除順序器狀態(tài)。
--abort
取消操作并返回到預(yù)序列狀態(tài)。
例子
git revert HEAD~3
還原HEAD中第四個最后一次提交所指定的更改,并使用還原的更改創(chuàng)建一個新提交。
git revert -n master~5..master~2
將提交所做的更改從master(包含)中的第五次提交恢復(fù)為master(包含)中的第三次提交,但不要使用還原的更改創(chuàng)建任何提交?;謴?fù)僅修改工作樹和索引。
恢復(fù)一個提交記錄并生成一個新的記錄:


生成了這個,又不想要了這個節(jié)點怎么辦?
執(zhí)行git reset --hard head^1即可

Q & A:
1.想恢復(fù)到某個版本并且測試代碼怎么辦?
使用git reset --hard [commit_id]回滾,測試完之后,使用git reflog查看記錄,并再次使用git reset --hard [commit_id]回滾到指定代碼版本。
2.想恢復(fù)到某個版本并且測試代碼,又測試出來一些bug該怎么辦?
使用git reset --hard [commit_id]回滾之后修改代碼,修改完成之后可以進行 git push -f進行強制推送到遠程,前提是同學沒有進行push,否則會覆蓋掉其他同學的代碼導致其他業(yè)務(wù)線出問題。