@[git|commit|reflog]
在使用Git的過程中亦歉,有時候會因?yàn)橐恍┱`操作,比如reset俏让、rebase楞遏、merge等。特別是在Commit之后又執(zhí)行了git reset --hard HEAD
強(qiáng)制回滾本地記錄以及文件到服務(wù)器版本首昔,導(dǎo)致本地做的修改全部恢復(fù)到Git當(dāng)前分支的服務(wù)器版本寡喝,同時自己的Commmit記錄也消失了。碰到這種情況勒奇,不要慌预鬓,我們在Git上做的任何操作都只是在原來之前的操作上做修改,并且會被記錄下來保存赊颠,也就是說無論你做了什么格二,對于Git來說都可以進(jìn)行回滾操作。
找回Commit###
通過以下例子來了解下具體怎么回滾:
$ git init
$ touch foo.txt
$ echo 'test data' >> foo.txt
$ git add foo.txt
$ git commit -m "initial commit"
$ echo 'new data' >> foo.txt
$ git commit -a -m "more stuff added to foo"
你現(xiàn)在看git的歷史記錄竣蹦,你可以看到兩次提交:
$ git log
* 98abc5a (HEAD, master) more stuff added to foo
* b7057a9 initial commit
現(xiàn)在讓我們來重置回第一次提交的狀態(tài):
$ git reset --hard b7057a9
$ git log
* b7057a9 (HEAD, master) initial commit
這看起來我們是丟掉了我們第二次的提交顶猜,本地的修改也消失了,沒有辦法找回來了痘括。但是 reflog 就是用來解決這個問題的长窄。簡單的說,它會記錄所有HEAD的歷史纲菌,也就是說當(dāng)你做 reset挠日,checkout等操作的時候,這些操作會被記錄在reflog中翰舌。
$ git reflog
b7057a9 HEAD@{0}: reset: moving to b7057a9
98abc5a HEAD@{1}: commit: more stuff added to foo
b7057a9 HEAD@{2}: commit (initial): initial commit
所以嚣潜,我們要找回我們第二commit,只需要做如下操作:
$ git reset --hard 98abc5a
再來看一下 git 記錄:
$ git log
* 98abc5a (HEAD, master) more stuff added to foo
* b7057a9 initial commit
同時本地對foo.txt做的修改也回復(fù)回來了椅贱。
PS:這里在提一下另一個找回Commit的操作
git cherry-pick 98abc5a
,這個操作與上面的reset操作區(qū)別在于后者只是單純的提取98abc5a這個Commit進(jìn)行回滾懂算,如果在b7057a9和98abc5a之間還有其他的Commit操作,則會忽略中間的這些Commit做的修改庇麦,所以應(yīng)用這個命令有可能會文件的沖突
git reset的具體用法###
git reset [--hard|soft|mixed|merge|keep] [<commit>或HEAD]
作用:將當(dāng)前分支reset到指定的<commit>或者HEAD(默認(rèn)為最新的一次提交计技,即重設(shè)到最新一次提交之前的版本)
備注:
- index,執(zhí)行g(shù)it add的操作女器,會對文件創(chuàng)建索引酸役,所有被跟蹤的文件索引會放入index,表示文件被修改待提交
- working tree,當(dāng)前工作區(qū)涣澡,被修改但未被add的文件贱呐,存儲在工作區(qū)
- ORIG_HEAD,用于指向前一個操作狀態(tài),每次的commit或者pull或者reset,git 都會把老的HEAD拷貝到.git/ORIG_HEAD入桂,通過對ORIG_HEAD的引用可以指向前一次的操作狀態(tài)
1奄薇、hard(慎用)
重設(shè)index和working tree,所有改變都會被丟棄,包括文件的修改抗愁、新增馁蒂、刪除等操作,并把HEAD指向<commit>蜘腌,
因此通過git log查看版本提交記錄沫屡,被reset的版本記錄會被丟棄,但可以通過git reflog查看
2撮珠、soft
不重設(shè)index和working tree,僅僅將HEAD指向<commit>,表示已經(jīng)commit的文件會取消commit,
通過git status查看沮脖,文件會處于待commit狀態(tài)“Changes to be committed”
3、mixed(默認(rèn))
重設(shè)index,但不重設(shè)working tree,表示已經(jīng)被add的文件芯急,被取消add勺届,
通過git status查看,文件會處于待添加索引狀態(tài) “Changes not staged for commit”
4娶耍、merge
重設(shè)index免姿,重設(shè)working tree中發(fā)生變化的文件,但是保留index和working tree不一致的文件
5榕酒、keep
重設(shè)index胚膊,重設(shè)working tree中發(fā)生變化的文件
記錄的保存問題###
我們前面說到在Git上做的所有操作都被保存到記錄里,一般是從你本地Git庫執(zhí)行clone開始的所有操作都保存了下來奈应,所以不用擔(dān)心很久之前的一些Commit log找不到澜掩,你或許期望去為已刪除的提交設(shè)置一個更長的保存周期购披。例如:
$ git config gc.pruneexpire "30 days"
意思是一個被刪除的提交會在刪除30天后杖挣,且運(yùn)行 git gc 以后,被永久丟棄刚陡。
你或許還想關(guān)掉 git gc 的自動運(yùn)行:
$ git config gc.auto 0
在這種情況下提交將只在你手工運(yùn)行 git gc 的情況下才永久刪除惩妇。