您好,登錄后才能下訂單哦!
這篇文章主要講解了“git reset的用法是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“git reset的用法是什么”吧!
一、可以將git簡單的分為三個區域
1、工作區(working directory)
2、暫緩區(stage index)
3、歷史記錄區(history)
其中git add files 把當前工作目錄中的文件放入暫存區域 ,這其實做了兩件事:
1、將本地文件的時間戳、長度,當前文檔對象的id等信息保存到一個樹形目錄中去(index,即平時說的暫存區)
2、將本地文件的內容做快照并保存到Git 的對象庫 。
綜上2點來說,暫存區實際上就是一個包含文件索引的目錄樹,像是一個虛擬的工作區。在這個虛擬工作區的目錄樹中,記錄了文件名、文件的狀態信息(時間戳、文件長度等),文件的內容并不存儲其中,而是保存在 Git 對象庫(.git/objects)中,文件索引建立了文件和對象庫中對象實體之間的對應。
我們可以看到部分 Git 命令是如何影響工作區和暫存區(stage, index)的:
左側為工作區,右側為版本庫。在版本庫中標記為 "index" 的區域是暫存區(stage, index),標記為 "master" 的是 master 分支所代表的目錄樹。
我們可以看出此時 "HEAD" 實際是指向 master 分支的一個“游標”。所以圖示的命令中出現 HEAD 的地方可以用 master 來替換。
objects 標識的區域為 Git 的對象庫,實際位于 ".git/objects" 目錄下
當對工作區修改(或新增)的文件執行 "git add" 命令時,暫存區的目錄樹被更新,同時工作區修改(或新增)的文件內容被寫入到對象庫中的一個新的對象中,而該對象的ID 被記錄在暫存區的文件索引中
當執行提交操作(git commit)時,暫存區的目錄樹寫到版本庫(對象庫)中,master 分支會做相應的更新。即 master 指向的目錄樹就是提交時暫存區的目錄樹 。
當執行 "git status" 命令掃描工作區改動的時候,先依據 .git/index 文件中記錄的(工作區跟蹤文件的)時間戳、長度等信息判斷工作區文件是否改變。如果工作區的文件時間戳改變,說明文件的內容可能被改變了,需要打開文件,讀取文件內容,和更改前的原始文件相比較(本地文件和與之對應的object庫中的文件的內容進行對比),判斷文件內容是否被更改。如果文件內容沒有改變,則將該文件新的時間戳記錄到 .git/index 文件中。因為判斷文件是否更改,使用時間戳、文件長度等信息進行比較要比通過文件內容比較要快的多,所以 Git 這樣的實現方式可以讓工作區狀態掃描更快速的執行,這也是 Git 高效的因素之一。
git diff files用來進行具體文件的變動對比,通常用來進行工作區與暫存區之間的對比,實質上是用 git objects 庫中的快照與工作區文件的內容的對比。
另外,Git中提供了幾個相關的撤銷操作的命令,如git reset、git revert、git checkout,這幾者之間的用法各有不同。
二、git reset的用法
從上圖可知:git reset -- files 用來撤銷最后一次的git add files(因為每git add file一次,暫存區的文件都會被更改一次),你也可以用git reset 撤銷所有暫存區域文件。
另外:
一、git reset的用法:git reset + commit號
1、git reset命令后面需要加2種參數:"--hard"和"--soft",如果不加,默認情況下是"--soft"。
2、--soft表示該條commit號之后(時間作為參考點)的所有commit的修改都會退回到git緩沖區中。所以使用git status命令可以在緩沖區中看到這些修改。
3、"--hard"則表示緩沖區中不會存儲這些修改,git會直接丟棄這部分內容,但需要注意的一個問題是:這樣的重置是直接在本地的修改,無法提交到遠程服務器,如果直接丟棄的內容已經被推到遠程服務器上了,則會造成本地和服務器無法同步的問題,即git reset --hard只能針對本地操作,不能針對遠程服務器進行同樣操作。如果從本地刪掉的內容沒有推到服務器上,則不會有副作用,如果被推到服務器,則下次本地和服務器進行同步時,這
部分刪掉的內容仍然會回來。
(其實這個問題則可以很好的被git revert 命令解決,使用git revert + commit號,該命令撤銷對某個commit的提交,這一撤銷動作會作為一個新的修改存儲起來,這樣,當你和服務器同步時,就不會產生什么副作用。)
其實在merge的時候,也有可能會用到git reset.
如果我們當前使用git pull的時候,可能會出現merge沖突,在沖突狀態下,需要解決沖突的文件會從index暫存區打回到工作區。
如果有沖突的時候,一般用如下步驟解決沖突:
1、用工具或者手工解決沖突
2、git add 命令來表明沖突已經解決。
3、再次commit已解決沖突的文件。
這當中,可以使用git reset --hard ORIG_HEAD用來撤銷已經commit的merge.
使用git reset --hard HEAD 用來撤銷還沒commit 的merge,其實原理就是放棄index和工作區的改動。
也可以使用git reset --merge ORIG_HEAD,注意其中的--hard 換成了 --merge,這樣就可以避免在回滾時清除working tree。
三、git checkout的用法
從上圖可知,git checkout -- files 把文件從暫存區域復制到工作目錄,用來丟棄本地修改。 需要另外注意的是:
1、當執行 "git rm --cached <file>" 命令時,會直接從暫存區刪除文件,工作區則不做出改變。
2、當執行 "git checkout ." 或者 "git checkout -- <file>" 命令時,會用暫存區全部或指定的文件替換工作區的文件。這個操作很危險,會清除工作區中未添加到暫存區的改動
3、當執行 "git checkout HEAD ." 或者 "git checkout HEAD <file>" 命令時,會用 HEAD 指向的 master 分支中的全部或者部分文件替換暫存區以及工作區中的文件。這個命令也是極具危險性的,因為不但會清除工作區中未提交的改動,也會清除暫存區中未提交的改動 。
四、git revert的用法
git revert 也是撤銷命令,區別在于reset是指向原地或者向前移動指針,git revert是創建一個commit來覆蓋當前的commit,指針向后移動。
那么兩者的具體區別有:
1)git revert 是撤銷某次操作,此次操作之前的commit都會被保留,而git reset 是撤銷某次提交,但是此次之后的修改都會被退回到暫存區中。
具體一個例子,假設有三個commit(commit1,commit2,commit3),使用 git status:
commit3: add test3.c
commit2: add test2.c
commit1: add test1.c
當執行git revert HEAD~1時(撤銷倒數第二個操作),第二個操作即commit2這個操作被撤銷了,使用git log可以看到:
commit1:add test1.c
commit3:add test3.c
由于git revert不會回退到暫存區中,所以使用git status 沒有任何變化
如果換做執行git reset --soft(默認) HEAD~1后,運行git log可以看到
commit2: add test2.c
commit1: add test1.c
運行git status,可以看到test3.c處于暫存區了,準備提交。
但如果換做執行git revert后,
顯示:HEAD is now at commit2,運行git log可以看到
commit2: add test2.c
commit1: add test1.c
運行git status, 則沒有任何變化
所以,git revert與git reset最大的不同是,git revert 僅僅是撤銷某次提交,而git reset會將撤銷點之后的操作
都回退到暫存區中。
1、git revert是用一次新的commit來回滾之前的commit,git reset是直接刪除指定的commit。
2、在回滾這一操作上看,效果差不多。但是在日后繼續merge以前的老版本時有區別。
因為git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch時,導致這部分改變不會再次出現,但是git reset是之間把某些commit在某個branch上刪除,因而和老的branch再次merge時,這些被回滾的commit應該還會被引入。
3、git reset 是把HEAD向后移動了一下,而git revert是HEAD繼續前進,只是新的commit的內容和要revert的內容正好相反,能夠抵消要被revert的內容。
六、不得不提的git的其它刪除命令(類似于Linux的命令):
git rm --cached readme.txt 只從緩存區中刪除readme.txt,保留物理文件
git rm readme.txt 不但從緩存區中刪除,同時刪除物理文件
git mv a.txt b.txt 把a.txt改名為b.txt
綜上所以我們有時如果是想撤銷對單個文件的更改:
<->、如果已經用add命令把文件加入stage暫存區了:
1、就先需要從stage暫存區中撤銷:
"git reset HEAD <file>..."
2、然后再從工作區撤銷,即將暫存區的文件替換工作區當前的文件
"git checkout -- <file>..." to discard changes in working directory
如:git checkout a.txt 撤銷a.txt的變動(工作區上的文件)
如果是多個文件:git chenkout .
<二>、如果已經commit了,則需要
1、使用git commit --amend來進行修改,這個只能修改最近一次的,也就是用一個新的提交來覆蓋上一次的提交。因此如果push以后再做這個動作就會有危險。
2、git reset --hard HEAD 放棄工作區和index的改動,HEAD指針仍然指向當前的commit.(參照第一幅圖)
這條命令同時還可以用來撤銷還沒commit的merge,其實原理就是放棄index暫存區和工作區的改動,因為沒commit的改動只存在于index暫存區和工作區中。
而git reset --hard HEAD^ 用來撤銷已經commit的內容(等價于 git reset --hard HEAD~1) 。原理就是放棄工作區和index的改動,同時HEAD指針指向前一個commit對象。
感謝各位的閱讀,以上就是“git reset的用法是什么”的內容了,經過本文的學習后,相信大家對git reset的用法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。