1. 程式人生 > >git的幾個常用基本操作

git的幾個常用基本操作

![](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`突然找不到了,一定都可以在這裡