最近在開發項目的一個小需求的時候,發生了一件尷尬的事情。那就是當我把新功能開發完成的時候,突然發現本身開發使用的分支是錯誤的分支。php
不過我記得以前學習git
的時候有一個git stash
的命令能夠把當前沒有提交的內容存檔起來,而後能夠在切換分支以後把當前的存檔應用到目標分支。不過由於平時不怎麼使用這個命令,因此有點生疏了,須要再次去看看文檔。html
花了十幾分鍾,把git stash
相關的命令又再次溫習了一下,接着就順利地把這個問題給解決掉。由於平時的開發也都是遵循相關的git
流程,通常不會出現什麼錯誤,並且平時使用的git
命令也都是一些經常使用的。git
此次出現這個問題有一部分緣由是由於這個項目不是一個長期維護的項目,當開發新功能的時候,一打開項目,就覺得還在本身的開發分支。也沒及時檢查一下開發的分支是否正確。更深層次的緣由仍是由於git
掌握得不夠好。也正好借這個機會,把相關的命令再次好好複習一下,也挺好的。app
其實當你在錯誤的分支開發了新功能以後,這裏會有三種狀況:編輯器
新功能尚未在本地進行commit
(提交),也就是我此次遇到的狀況ide
新功能已經在本地提交了,可是尚未push
到遠程倉庫學習
新功能已經在本地提交了,且push
到了遠程倉庫測試
雖然我遇到的是第一種狀況,那麼當我解決這個問題以後,我很天然的就會想:若是遇到了另外兩種狀況我該怎麼處理呢?這篇文章就跟你們一塊兒探討一下針對上述三種狀況下,若是你在錯誤的分支開發了新功能,咱們應該怎麼作。spa
commit
(提交) 在這種狀況下咱們能夠在當前分支下使用:命令行
git stash
這個命令表示把咱們當前修改的內容暫存起來,而後咱們的工做區就恢復到在沒有開發新功能以前的樣子。
這個時候咱們須要切換到正確的工做分支,而後運行命令:
git stash apply
這個命令表示把咱們以前暫存的內容,應用到當前分支。這樣咱們就至關於把修改的內容從一個分支移動到了另外一個分支,是否是很簡單呢。
上面那兩個命令也是我解決這個問題中使用的命令。我以爲不能知足於只解決這個問題,我須要詳細的瞭解一下有關git stash
的命令,接下來的內容是關於git stash
的一些深刻的內容,咱們不只要知其然,還要知其因此然。
首先咱們須要知道使用git stash
命令會把咱們工做區和暫存區的修改保存下來,而後將這些修改的內容從當前的文件中移出並保存在存檔庫裏面。因此咱們就回到了以前沒有修改過內容的乾淨的工做區。
git stash
在沒有添加任何參數的時候至關於git stash push
命令,咱們使用git stash
建立一個當前修改的快照的時候,命令運行完會給出以下的信息:
Saved working directory and index state WIP on <branchname>: <hash> <commit message>
其中branchname
是你當前所在分支的名字,hash
是當前分支最近一次提交的hash值,commit message
就是你最近的一次提交的時候添加的提交信息。
對於當前只想存儲一個快照的狀況下使用git stash
是比較方便直觀的,若是你在當前分支想存儲多個快照,那麼最好給每個快照添加一些解釋信息,以便使用的時候可以知道每個快照都是幹嗎的。
咱們可使用git stash push -m message
來給每個快照添加詳細的說明信息,好比:
git stash push -m 「add feature 1」
在這個命令行運行完成以後,在終端上會顯示以下的信息:
Saved working directory and index state On <branchname>: add feature 1
根據終端顯示的信息,咱們能夠知道當前這個快照是在那個分支產生的,而且有了add feature 1
這個詳細的描述,等到之後使用的時候會更加的清楚一點。
當咱們有了不少快照的時候,咱們可能想看一下當前的快照列表。這個時候咱們能夠使用git stash list
來看一下當前的快照列表。在終端運行git stash list
後,若是你在以前添加了一些快照的話,會顯示以下的一些信息:
stash@{0}: On <branchname>: add feature 1 stash@{1}: On <branchname>: add feature 0 stash@{2}: On <branchname>: <message> stash@{3}: WIP on <branchname>: 47e52ae <commit message> stash@{4}: On <branchname>: <message>
從上面的信息中咱們能夠知道最新的快照是排在最上面的,存儲快照的是一個棧,因此最新添加的快照是放在最上面的。
若是咱們想查看最近一次快照跟生成快照當時已提交的文件之間的變化狀況的話,可使用命令git stash show
。這個命令默認展現的是文件的差異統計。若是想展現具體改動的內容的話,可使用git stash show -p
。
由於咱們有不止一個快照,因此咱們還想要看以前的快照跟產生這個快照當時已提交的版本之間的差別的話,咱們能夠在上面的命令後面添加快照的索引,好比若是你想看上面add feature 0
這個快照的文件變更的話,可使用下面的命令:
git stash show stash@{1} # 簡略的信息 git stash show -p stash@{1} # 詳細的內容更改
接下來就到了應用(恢復)快照的時候了,若是這時候你想把某個快照的內容應用於當前的分支的話,只須要運行命令:
git stash apply # 將最新的快照內容應用於當前分支 git stash apply stash@{n} # n表示具體的快照索引
這樣就能夠把以前保留的快照內容應用到當前的版本中了,在應用快照的過程當中可能會產生衝突,這時候須要手動把衝突的內容處理一下,而後再次提交就能夠了。
git stash apply
能夠添加--index
參數,這個參數的做用是在應用快照的時候,會把以前已經添加到暫存區(索引區)的更改依舊保存在暫存區,若是不添加這個參數的話,全部的變動都會變成在工做區的變動(也就是沒有保存在索引區的狀態)。
咱們能夠測試一下,對一個文件進行更改,而後把更改添加(使用git add
)到暫存區,而後再次添加一個更改,此次不添加到暫存區。咱們運行git status
命令會看到以下的內容:
On branch dev Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: 20200830/index.html Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: 20200830/README.md
當咱們運行git stash
命令,而後運行git stash apply
命令以後,會看到以下信息:
On branch dev Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: 20200830/README.md modified: 20200830/index.html no changes added to commit (use "git add" and/or "git commit -a")
因此當不使用--index
參數的時候,不會保存以前在暫存區的狀態。
關於git stash
還有一些其它的命令,好比:
git stash drop
:丟棄一個快照git stash pop
:應用最新的快照到當前分支,若是應用成功的話就把這個快照從存儲快照的棧中移除git stash clear
:清除全部的快照關於git stash
一些經常使用的命令和操做上面已經講解的差很少啦,若是你們想繼續瞭解更多的話,能夠參考git-stash。
上面的內容主要是在咱們新開發的功能尚未提交的狀況下所作的一些處理,當咱們開發的新功能已經在本地提交了的狀況下,咱們該如何處理呢?接下來咱們就來探討一下這個問題。
push
到遠程倉庫 若是新開發的功能已經在本地提交了,可是咱們開發的這個分支是一個錯誤的分支。這個時候根據狀況的不一樣,能夠有兩種處理的方式。
首先咱們須要知道在咱們添加新功能以前,當前分支處於哪個提交。能夠運行命令:
git log --oneline
查看當前分支的提交,能夠看到有如下內容的輸出:
085095f (HEAD -> master) update 5 47e52ae update 3 14fefac update 2 fd01444 add README.md 3c76ad1 init
找到咱們添加新功能時,當前分支所處的提交。假如是fd01444
,那麼咱們接下來要作的操做就是將HEAD
指針指向fd01444
,也就是把咱們當前分支已提交的內容重置到咱們開發新功能以前的樣子。咱們須要運行下面的命令:
git reset fd01444 # fd01444是某次提交的hash值
若是沒有指明重置的模式的話,默認會使用--mixed
模式,這樣的話咱們在fd01444
此次提交以後的全部提交都會被重置爲沒有提交的狀態。接下來咱們須要把這些新開發的功能遷移到一個新的分支。這時候咱們可使用下面的命令進行操做:
git checkout -b <newbranch>
這樣咱們就建立了一個新的分支,而且把新添加的功能也都遷移了過去,接下來就是常規的添加和提交操做了。
若是咱們須要把當前添加的新功能遷移到另外一個已經存在的分支,那麼咱們須要作的前幾個步驟跟上面的操做是同樣的:
git log --oneline # 查找新功能開發以前的提交 git reset <commit hash> # 將當前分支重置到新功能開發以前的提交
接下來咱們如今的狀態就回到了新功能尚未提交的狀態,那麼就能夠繼續使用git stash
相關的命令去操做了。
咱們還有另一個方法也可以將已提交到當前分支的功能添加到另外一個分支上,那就是使用git cherry-pick
命令。首先咱們仍是先用git log --oneline
查找當前已提交的功能的hash值,而後切換到目標分支,運行命令:
git cherry-pick <commit hash>
這樣就把咱們在另外一個分支開發的功能,添加到咱們想要的分支了。若是有衝突的話,須要手動處理一下衝突。而後咱們回到最初的分支,再次運行git reset <commit hash>
命令,把已提交的內容進行重置,而後運行命令:
git checkout -- .
把當前分支沒有添加到暫存區的內容都清除掉,這樣也能夠達到咱們上面所說的,把新功能添加到另外一個分支的目的。
push
到了遠程倉庫 第三種狀況就是,咱們已經把新開發的功能push
到遠程的倉庫了,可是咱們突然發現新功能不該該在這個分支開發,咱們這個時候應該怎麼辦呢?
首先咱們應該保持當前的工做區是沒有修改的,是一個乾淨的狀態。否則使用撤銷命令的時候會提示你須要把當前的文件內容變動先提交或者生成快照。當咱們的工做區的狀態是乾淨的時候,咱們就能夠進行撤銷操做了。
首先須要知道咱們應該撤銷那一次提交的狀態。使用git log --oneline
查看要撤銷的提交的索引,而後運行下面的命令:
git revert <commit>
這個時候命令運行的終端會進入編輯器模式,讓你填寫提交的信息。固然你也可使用參數--no-edit
這樣就不會在進行撤銷操做的時候打開編輯模式了。
若是須要撤銷的提交比較多的話,咱們可使用..
表示一個提交記錄的範圍。好比c1..c2
就表示c2
的可達提交,且排除c1
的可達提交。所謂可達的提交指的是:提交自己及其祖先鏈中提交的集合。
咱們能夠舉個例子:
... a - b - c - d - HEAD
若是上面表示的是某個分支的提交記錄,那麼對於b..d
表示的就是c d
這兩個提交,對於a..d
表示的就是b c d
這三個提交。若是你們想了解更多相關的內容,能夠在git-rev-list這裏深刻的學習一下。
因此咱們若是想快速的撤銷一段範圍的提交的話,能夠運行相似下面這樣的命令:
git revert 54dc134..a72d612 --no-edit
上述命令的54dc134
就表示c1
,a72d612
就表示c2
,--no-edit
代表咱們在運行撤銷操做的時候不打開編輯模式。
咱們若是須要對遠程的分支進行撤銷的話,首先考慮的就是使用git revert
命令,由於git revert
命令不會修改歷史的提交記錄,只是在原來的提交基礎上添加新的提交,因此不會形成代碼的丟失。在多人合做的狀況下使用git revert
命令撤銷push
到遠程的操做仍是頗有必要的。
若是你們對於上面的這些問題有更好的解決方案的話,歡迎你們在文章下面留言,咱們能夠一塊兒探討一下,一塊兒進步。若是你對文章有什麼意見和建議的話也歡迎在文章下面留言,或者在這裏提出來,我會持續努力改進的。也歡迎你們關注個人公衆號關山不難越,及時獲取最新的文章更新。
參考連接: