git的幾個常用基本操作
阿新 • • 發佈:2020-07-20
![](https://img2020.cnblogs.com/blog/1566782/202007/1566782-20200720082144826-1137829947.jpg)
## 需求一:如何把stage中的修改還原到work dir中
這個需求很常見,也很重要,比如我先將當前`work dir`中的修改新增到`stage`中,然後又對`work dir`中的檔案進行了修改,但是又後悔了,如何把`work dir`中的全部或部分檔案還原成`stage`中的樣子呢?
來個實際場景,我先新建兩個檔案,然後把他們都加到`stage`:
```sh
$ 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`檔案:
```sh
$ 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** 命令:
```sh
$ 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 dir`中`a.txt`檔案還原成了`stage`中的狀態(一個空檔案)。
當然,如果`work dir`中被修改的檔案很多,可以使用萬用字元全部恢復成`stage`:
```
$ git checkout .
```
有一點需要指出的是,`checkout`命令只會把**被「修改」**的檔案恢復成`stage`的狀態,如果`work dir`中新增了新檔案,你使用`git checkout .`是不會刪除新檔案的。
## 需求二:比如說`commit`完之後,突然發現一些錯別字需要修改,又不想為改幾個錯別字而新開一個`commit`到`history`區
那麼就可以使用下面這個命令:
```
$ git commit --amend
```
這樣就是把錯別字的修改和之前的那個`commit`中的修改合併,作為一個`commit`提交到`history`區。
## 需求三:將history區的檔案還原到stage區
這個需求很常見,比如說我用了一個`git add .`一股腦把所有修改加入`stage`,但是突然想起來檔案`a.txt`中的程式碼我還沒寫完,不應該把它`commit`到`history`區,所以我得把它從`stage`中撤銷,等後面我寫完了再提交。
```sh
$ 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.txt`從`stage`區還原出來呢?可以使用 **git reset** 命令:
```sh
$ 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`命令的完整寫法如下:
```sh
$ 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`命令,但是和之前的使用方式有一些不同:
```sh
$ git checkout HEAD .
Updated 12 paths from d480c4f
```
這樣,`work dir`和`stage`中所有的「修改」都會被撤銷,恢復成`HEAD`指向的那個`history commit`。
注意,類似之前通過`stage`恢復`work dir`的`checkout`命令,這裡撤銷的也只是修改,新增的檔案不會被撤銷。
當然,只要找到任意一個`commit`的 HASH 值,`checkout`命令可就以將檔案恢復成任一個`history commit`中的樣子:
```sh
$ 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
```
比如`reset`,`checkout`等等關鍵操作都會在這裡留下記錄,所有`commit`的 Hash 值都能在這裡找到,所以如果你發現有哪個`commit`突然找不到了,一定都可以在這裡