git的幾個常用基本操作

murphy_gb發表於2020-07-20

需求一:如何把stage中的修改還原到work dir中

這個需求很常見,也很重要,比如我先將當前work dir中的修改新增到stage中,然後又對work dir中的檔案進行了修改,但是又後悔了,如何把work dir中的全部或部分檔案還原成stage中的樣子呢?

來個實際場景,我先新建兩個檔案,然後把他們都加到stage

$ touch a.txt b.txt
$ git add .
$ git status
On branch master
Changes to be committed:
    new file:   a.txt
    new file:   b.txt

然後我又修改了a.txt檔案:

$ echo hello world >> a.txt
$ git status
On branch master
Changes to be committed:
    new file:   a.txt
    new file:   b.txt

Changes not staged for commit:
    modified:   a.txt

現在,我後悔了,我認為不應該修改a.txt,我想把它還原成stage中的空檔案,怎麼辦?

答案是,使用 checkout 命令:

$ git checkout a.txt
Updated 1 path from the index

$ git status
On branch master
Changes to be committed:
    new file:   a.txt
    new file:   b.txt

看到了麼,輸出顯示從index區(也就是stage區)更新了一個檔案,也就是把work dira.txt檔案還原成了stage中的狀態(一個空檔案)。

當然,如果work dir中被修改的檔案很多,可以使用萬用字元全部恢復成stage

$ git checkout .

有一點需要指出的是,checkout命令只會把被「修改」的檔案恢復成stage的狀態,如果work dir中新增了新檔案,你使用git checkout .是不會刪除新檔案的。

需求二:比如說commit完之後,突然發現一些錯別字需要修改,又不想為改幾個錯別字而新開一個commithistory

那麼就可以使用下面這個命令:

$ git commit --amend

這樣就是把錯別字的修改和之前的那個commit中的修改合併,作為一個commit提交到history區。

需求三:將history區的檔案還原到stage區

這個需求很常見,比如說我用了一個git add .一股腦把所有修改加入stage,但是突然想起來檔案a.txt中的程式碼我還沒寫完,不應該把它commithistory區,所以我得把它從stage中撤銷,等後面我寫完了再提交。

$ echo aaa >> a.txt; echo bbb >> b.txt;
$ git add .
$ git status
On branch master
Changes to be committed:
    modified:   a.txt
    modified:   b.txt

如何把a.txtstage區還原出來呢?可以使用 git reset 命令:

$ git reset a.txt

$ git status
On branch master
Changes to be committed:
    modified:   b.txt

Changes not staged for commit:
    modified:   a.txt

你看,這樣就可以把a.txt檔案從stage區移出,這時候進行git commit相關的操作就不會把這個檔案一起提交到history區了。

上面的這個命令是一個簡寫,實際上reset命令的完整寫法如下:

$ git reset --mixed HEAD a.txt

其中,mixed是一個模式(mode)引數,如果reset省略這個選項的話預設是mixed模式;HEAD指定了一個歷史提交的 hash 值;a.txt指定了一個或者多個檔案。

該命令的自然語言描述是:不改變work dir中的任何資料,將stage區域中的a.txt檔案還原成HEAD指向的commit history中的樣子。就相當於把對a.txt的修改從stage區撤銷,但依然儲存在work dir中,變為unstage的狀態。

需求四:將work dir中的修改提交到history區

這個需求很簡單,先git add然後git commit就行了,或者一個快捷方法是使用命令git commit -a

需求五:將history區的歷史提交還原到work dir中

這個場景,我說一個極端一點的例子:比如我從 GitHub 上clone了一個專案,然後亂改了一通程式碼,結果發現我寫的程式碼根本跑不通,於是後悔了,乾脆不改了,我想恢復成最初的模樣,怎麼辦?

依然是使用checkout命令,但是和之前的使用方式有一些不同:

$ git checkout HEAD .
Updated 12 paths from d480c4f

這樣,work dirstage中所有的「修改」都會被撤銷,恢復成HEAD指向的那個history commit

注意,類似之前通過stage恢復work dircheckout命令,這裡撤銷的也只是修改,新增的檔案不會被撤銷。

當然,只要找到任意一個commit的 HASH 值,checkout命令可就以將檔案恢復成任一個history commit中的樣子:

$ git checkout 2bdf04a some_test.go
Updated 1 path from 2bdf04a
# 前文的用法顯示 update from index

比如,我改了某個測試檔案,結果發現測試跑不過了,所以就把該檔案恢復到了它能跑過的那個歷史版本……

需求六:由於HEAD指標的回退,導致有的commit在git log命令中無法看到,怎麼得到它們的 Hash 值呢?

只要你不亂動本地的.git資料夾,任何修改只要提交到commit history中,都永遠不會丟失,看不到某些commit只是因為它們不是我們當前HEAD位置的「歷史」提交,我們可以使用如下命令檢視操作記錄:

$ git reflog

比如resetcheckout等等關鍵操作都會在這裡留下記錄,所有commit的 Hash 值都能在這裡找到,所以如果你發現有哪個commit突然找不到了,一定都可以在這裡找到。

相關文章