一份值得收藏的 Git 異常處理清單
前言
Git 作為一種分布式版本控制系統(tǒng)已經(jīng)成為現(xiàn)在開發(fā)的寵兒,不僅應(yīng)用在前端、后端、客戶端等開發(fā)場景中,也成為各行業(yè)互聯(lián)網(wǎng)企業(yè)分工協(xié)作的必備技能之一。
大家在使用過程中總會碰到這樣那樣的問題,本文主要針對以下經(jīng)常發(fā)生的幾種異常情況提供一些解決方案:
-
本地工作區(qū)文件修復
-
遠程分支刪除后,刪除本地分支與其關(guān)聯(lián)
-
修改提交時的備注內(nèi)容
-
修改分支名,實現(xiàn)無縫銜接
-
撤回文件提交
-
撤銷本地分支合并
-
恢復誤刪的本地分支
-
不確定哪個分支有自己提交的 commit
(一)本地工作區(qū)文件修復
大家都知道,一個文件夾中的文件如果被刪掉了,那只有在垃圾箱里面找了。如果垃圾箱里面的也被刪掉了,以筆者的常識在不借助工具的情況下怕是就找不到了,emmmm。。。
不過,關(guān)聯(lián)了 Git 的文件和文件夾就不一樣了,有了本地倉庫和遠程倉庫的雙重保護,找到一個被刪除的文件也不過就分分鐘,一個命令行的事情吧。
語法: git checkout <filename/dirname>
命令: git checkout 1.js
這一命令主要用于本地工作區(qū)文件的撤回,下圖是一個工作區(qū)文件被刪除后的完美恢復過程。
(二)遠程分支刪除后,刪除本地分支及關(guān)聯(lián)
為方便分支提交,一般情況下會用本地命令 git branch --set-upstream-to=origin/master master
建立本地分支與遠程分支的關(guān)聯(lián),從 master 拉出的分支可以自動建立與遠程已有分支的關(guān)聯(lián),這樣可以很方便的使用 git pull
和 git push
拉取遠程分支的代碼和將本地分支提交到遠程。
Git 遠程分支刪除之后,本地分支就無法成功推送到遠程,想要重新建立與遠程倉庫的關(guān)聯(lián),就需要先刪除其原本的與已刪除的遠程分支的關(guān)聯(lián)。
如下圖所示,需要刪除的遠程分支為 feature/test,使用 git push origin --delete feature/test
刪除掉對應(yīng)的遠程分支之后,刪除本地分支關(guān)聯(lián)。
語法: git branch --unset-upstream <branchname>
命令: git branch --unset-upstream feature/test
刪除掉關(guān)聯(lián)關(guān)系之后,用 git branch -vv
命令可查看到本地分支與遠程分支的關(guān)聯(lián)關(guān)系如下圖所示,可觀察到 feature/test 分支已經(jīng)沒有關(guān)聯(lián)的遠程分支了。
(三)修改提交時的備注內(nèi)容
平時提交代碼很多時候因為軍情緊急,會在剛提交的時候填寫了自己不太滿意的備注,但筆者本人有點強迫癥,一定要把它改成想要的樣子咋辦。。。。,不要慌,還是有解決辦法滴!
想要修改最近一次提交的“修改xxx功能”的備注:
語法: git commit --amend
命令: git commit --amend
使用 git log --pretty=oneline
查看內(nèi)容,發(fā)現(xiàn)已經(jīng)成功修改啦。 需要注意的是此項命令會修改提交時的commit-id,即會覆蓋原本的提交,需要謹慎操作 。
(四)修改分支名,實現(xiàn)無縫銜接
開發(fā)中的大佬都是擁有極快手速的人,建了個分支一不小心打錯了某個字母或者兩個字母打反了,可能就與本意存在較大誤差了,Git 提供一種已經(jīng)拉取了分支,在上面開發(fā)了不少的內(nèi)容,但后來發(fā)現(xiàn)原本拉的分支名字就有問題的修復方法。
需要修改的分支名字為 stor-13711, 如下圖所示:
語法: git branch -m <oldbranch> <newbranch>
命令: git branch -m feature/stor-13711 feature/story-13711
執(zhí)行完之后發(fā)現(xiàn)文件的工作區(qū)已修改內(nèi)容一點都沒有變化,真正的實現(xiàn)了無痛過渡,皆大歡喜!
(五)撤回文件提交
日常工作中,可能由于需求變更、對于文件的處理不同、提交了錯誤的本不應(yīng)提交的內(nèi)容等原因?qū)е绿峤涣瞬贿m合提交的內(nèi)容,需要進行撤銷操作。
需要撤回的提交中包含的內(nèi)容如下圖所示:
如下分析了各種原因撤銷的處理方式,主要包括:
-
需求變更等原因?qū)е碌某蜂N
-
代碼重構(gòu)等原因?qū)е碌某蜂N
-
個人疏失等原因?qū)е碌某蜂N
需求變更等原因?qū)е碌某蜂N
該需求仍然需要做,但進行了某些改動,按照之前的提交已經(jīng)不合適,需要重新改動之后一次性提交,以增加每一次提交的連續(xù)性和單個提交的完整性。
語法: git reset --soft [<commit-id>/HEAD~n>]
命令: git reset --soft HEAD~1
命令執(zhí)行完成后,查看文件變更記錄,可發(fā)現(xiàn)如下圖所示:
文件變更記錄與未提交之前的文件變更記錄是一致的,可判斷只是撤銷了 commit 的操作。
文件撤回到工作區(qū)后,可能發(fā)生部分之前上傳的文件不再需要,但是本地又不想刪除或是不能刪除(譬如 node_modules 文件)。
Git 提供了一個完整的解決方案,在本地項目根目錄下新建 .gitignore
文件,使用文件的特定語法(如下圖所示)即可以保證文件不被上傳到本地或遠程倉庫。其實現(xiàn)原理主要是在本地保存的文件快照中刪除 .gitignore
文件中定義的文件,以實現(xiàn)不被上傳的效果。
- # 忽略 .a 文件
- *.a
- # 但否定忽略 lib.a, 盡管已經(jīng)在前面忽略了 .a 文件
- !lib.a
- # 僅在當前目錄下忽略 TODO 文件, 但不包括子目錄下的 subdir/TODO
- /TODO
- # 忽略 build/ 文件夾下的所有文件
- build/
- # 忽略 doc/notes.txt, 不包括 doc/server/arch.txt
- doc/*.txt
- # 忽略所有的 .pdf 文件 在 doc/ directory 下的
- doc/**/*.pdf
代碼重構(gòu)等原因?qū)е碌某蜂N
本地需要進行某些優(yōu)化,對于單次提交上傳的不同文件有不同的處理需求,為使提交記錄更易于閱讀和便于區(qū)分所進行的撤銷。
語法: git reset --mixed [<commit-id>/HEAD~n>]
命令: git reset --mixed HEAD~1
命令執(zhí)行完成后,查看文件變更記錄,可發(fā)現(xiàn)如下圖所示:
已變更的文件都未添加到暫存區(qū),撤銷了 commit 和 add 的操作。
個人疏失等原因?qū)е碌某蜂N
本地需要將完全錯誤的本不應(yīng)提交的內(nèi)容提交到了倉庫,需要進行撤銷。
語法: git reset --hard [<commit-id>/HEAD~n>]
命令: git reset --hard HEAD~1
命令執(zhí)行完成后,查看文件變更記錄,可發(fā)現(xiàn)如下圖所示:
已追蹤文件的變更內(nèi)容都消失了,撤銷了 commit 和 add 的操作,同時撤銷了本地已追蹤內(nèi)容的修改;未追蹤的內(nèi)容不會被改變。從上面的效果可以看到,文件的修改都會被撤銷掉, --hard
的模式下需要謹慎操作 。
(六)撤銷本地分支合并
實際操作中,總會有很多的干擾,導致我們合并了并不該合并的分支到目標分支上。解決這種問題的方式有兩種, git reset
和 git revert
。 reset 的語法和命令之前已經(jīng)介紹過,不做贅述, revert 的語法和命令和 reset 一致。但是產(chǎn)生的實際效果會有不同。
可以先來看下 revert 操作的實際效果,合并分支之后的效果如下圖所示:
撤銷合并:
語法: git revert <commit-id>
命令: git revert 700920
下圖為執(zhí)行命令后的效果:
經(jīng)過前后對比可知,revert 執(zhí)行之后會在原本的記錄中新增一條提交記錄。
reset 如上 “本地文件撤銷” 例子所述,會刪除掉原本已有的提交記錄,在合并分支中,會刪除原本合并分支的記錄。revert 則有不同,會保留原本合并分支的記錄,并在其上新增一條提交記錄,便于之后有需要仍然能夠回溯到 revert 之前的狀態(tài)。
從需要提交到遠程分支的角度來講,reset 能夠毀尸滅跡,不讓別人發(fā)現(xiàn)我們曾經(jīng)錯誤的合并過分支;revert 則會將合并分支和撤回記錄一并顯示在遠程提交記錄上。
從代碼撤銷之后仍然需要合并的角度來講,revert 能夠?qū)崿F(xiàn)多分支合并之后,仍然能夠只撤銷本合并分支的內(nèi)容;reset 則需要使用 git reflog
命令 reset 到第一個沒有出錯的內(nèi)容的 commit-id
,然后再逐個進行合并(前提是這些分支的合并是有順序要求的)。
換言之,需要合并多個分支,如果合并的某個分支在操作過程中修改了內(nèi)容,revert 能夠?qū)崿F(xiàn)仍然合并修改之前的所有分支,reset 則只能合并某一個修改之前的分支。
(七)恢復誤刪的本地分支
本地分支被拉出之后,由于某種疏忽被錯誤的刪除了,而且本地的分支并沒有被同步到遠程分支上,此時想要恢復本地分支。
誤刪的分支為 feature/delete,使用 git reflog
命令可查看到該倉庫下的所有歷史操作,如下圖所示:
語法: git checkout -b <branch-name> <commit-id>
命令: git checkout -b feature/delete HEAD@{2}
命令執(zhí)行完成后,分支恢復到 HEAD@{2} 的快照,即從 master 分支拉取 feature/delete 分支的內(nèi)容,仍然缺少“新增xxx文件”的提交,直接將文件內(nèi)容恢復到最新的提交內(nèi)容,使用命令 git reset --hard HEAD@{1}
即可實現(xiàn)硬性覆蓋本地工作區(qū)內(nèi)容的目的。 git reflog
命令獲取到的內(nèi)容為本地倉庫所有發(fā)生過的變更,可謂恢復利器,既可向前追溯,亦可向后調(diào)整,滿滿的時光追溯器的趕腳啊。。。
(八)不確定哪個分支有自己提交的 commit
工作中會經(jīng)常碰到一種場景,在一個分支中修改了某個東西,進行了提交,因為版本先后等問題,先后合并到了各個分支上,但后來發(fā)現(xiàn)提交的這個修改的東西是有問題的,需要全項目排查,到底哪個分支有用這個提交,然后將其修復掉。
需要先確定有問題的提交的 commit-id :
然后查看本地所有的分支:
可以看到本地有 4 個分支,本地的分支數(shù)量非人為控制的,在使用狀態(tài)的分支直接刪掉也不合適,分支數(shù)量達到一定程度,一個一個分支查找也不現(xiàn)實。Git 提供了一種能夠直接通過 commit-id 查找出包含該內(nèi)容分支的命令。
語法: git branch --contains <commit-id>
命令: git branch --contains 700920
命令執(zhí)行后可以看到包含該問題提交的分支如下圖所示,就可以很方便的在對應(yīng)分支上修復內(nèi)容啦。
總結(jié)
本文介紹的是實際工作場景中可能出現(xiàn)的幾種異常情況及解決方式,希望能夠?qū)Υ蠹矣兴鶐椭蛔阒幘凑堉刚嶋H上現(xiàn)在已經(jīng)有很多 Git 操作對應(yīng)的工具可以使用,需要明白的是工具中的每個操作等同于 Git 命令行的哪個命令,會有什么樣的結(jié)果,以避免一些不必要發(fā)生的錯誤。