起底Git Git進(jìn)階

2018-06-15 20:09 更新

這是起底Git系列的第六篇,本篇我們來介紹一下Git的進(jìn)階技巧。

  • 選擇版本
  • 搜索調(diào)試
  • 重寫歷史
  • 重置揭秘
  • 高級合并

選擇版本

假設(shè)當(dāng)前版本庫如下圖所示,有時我們可能先找到當(dāng)前提交的父提交和祖先提交,^和~可以滿足我們的需求

^和~都匹配當(dāng)前提交的父提交,^^和~~匹配父提交的父提交,^和~后面跟數(shù)字的時候意義是不同的,具體可以看下面的例子

$ git log HEAD^ 
A2
$ git log HEAD^^ 
A1
$ git log HEAD^2 
B1
$ git log HEAD~ 
A2
$ git log HEAD~~
A1
$ git log HEAD~2 
A1

有時候我們可能會想選擇一個區(qū)間,比如A1,A2,A3,下面通過例子說明..,…和^的區(qū)別

$ git log master..test
C0 C1
$ git log ^master test
C0 C1
$ git log master…test
A1 A2 A3 C0 C1

搜索調(diào)試

A:設(shè)想這樣一種情況,摸個分支test,開發(fā)完后被刪除了,怎么找回這個分支呢?

其實git會在本地記錄每次HEAD的變化,通過reflog命令可以拿到這些記錄

$ git reflog
0e94c5b HEAD@{0}: commit: 222
7e07aa7 HEAD@{1}: commit: 111
c5aba97 HEAD@{2}: commit: 000

比如111是test分支最后一個提交,我們可以去111這個提交,然后在新建一個分支就ok了

$ git checkout 7e07aa7 # 或者git checkout HEAD@{1}
$ git checkout -b test

B:設(shè)想這樣一種情況,某天你突然發(fā)現(xiàn)某行代碼寫錯了,你想快速找到這個bug的始作俑者?

blame可以快速顯示文件的每一行最后一次修改是誰

$ git blame README.md
f6ffa8f4 (yanhaijing 2016-08-03 19:54:42 +0800 1) 123
f6ffa8f4 (yanhaijing 2016-08-03 19:54:42 +0800 1) 456

C:設(shè)想這樣一種情況,你想在Git的某個歷史提交中進(jìn)行搜索?

grep只能搜索工作目錄,git grep可以在指定提交中進(jìn)行搜索

$ git grep yanhaijing HEAD~27 fis-conf.js
HEAD~27:fis-conf.js: * @author yanhaijing.com

D:設(shè)想這樣一種情況,你想在Git的整個歷史中進(jìn)行搜索?git log可以實現(xiàn)這個功能

$ git log -Syanhaijing --oneline
0a191c message aaa

E:設(shè)想這樣一種情況,某一天你突然發(fā)現(xiàn)線上代碼掛了,但你找不到原因,你想快速找到是哪一個版本引入的bug?

git bisect是一個非常有用的調(diào)試工具,它通過自動進(jìn)行一個二分查找來找到哪一個特定的提交是導(dǎo)致 bug 或者問題的第一個提交

$ git bisect start # 開始
$ git bisect bad # 標(biāo)記為好的
$ git bisect good # 標(biāo)記為壞的
$ git bisect reset # 結(jié)束

重寫歷史

假設(shè)你提交完后發(fā)現(xiàn)忘記了一些東西,打算更改上次提交,在git中可以使用追加提交,假設(shè)現(xiàn)在倉庫狀態(tài)如下所示

修改完后可以再次提交

$ git add .
$ git commit --amend

就可以修改上次提交,需要注意的是上一次提交并沒有被刪除,只是沒有分支引用,變成了游離狀態(tài),在未來的某個時間會被git自動回收

如果你進(jìn)行了幾次提交后后悔了,想重寫之前的好幾次提交,那就只能用rebase了,假設(shè)目前狀態(tài)如下

假設(shè)你想重寫A1和A2

$ git rebase -i HEAD~2

需要注意的是已經(jīng)push到遠(yuǎn)端的提交,就不要再重寫了,不然世界人民會恨你,因為你需要git push -f

重置揭秘

重置有兩種方法,reset和checkout,這兩個方法非常容易混淆,兩個命令都分為全局模式和文件模式

reset全局模式可以用下圖總結(jié)

reset的文件模式可以覆蓋索引區(qū),一個副作用就是用來取消暫存

git reset xxx – file

checkout的全局模式可以用下圖總結(jié)

checkout的文件模式會覆蓋索引區(qū)和工作區(qū),可以用來丟棄修改,屬于不可逆轉(zhuǎn)的操作

git checkout xxx – file

其實下圖就總結(jié)兩個命令的區(qū)別

高級合并

合并分支時,很多人非常害怕遇到?jīng)_突,其實沖突并不可怕

A:git默認(rèn)的沖突顯示包括our和their,如下所示

xxx

如果想得到和svn那樣包含base+our+their的代碼,可以檢出沖突

$ git checkout --conflict=diff3 hello.rb

B:如果在沖突時想想svn一樣得到,base+our+their三個文件的代碼

$ git show :1:xxx > xxx.base
$ git show :2:xxx > xxx.our
$ git show :3:xxx > xxx.their

C:合并沖突一團亂麻,想撤銷合并

$ git merge --abort

D:合并后后悔了?想撤消合并?分為兩種情況

假如還沒推送到遠(yuǎn)端,可以reset掉

$ git reset --hard HEAD~

如果已經(jīng)推動到遠(yuǎn)端,可以用revert

$ git revert -m 1 HEAD

總結(jié)

如果你有任何疑問的話,歡迎留言討論;如果本系列文章對你有幫助的話,那我很榮幸,別忘了打賞哦,O(∩_∩)O哈哈~

最后感謝你的閱讀,O(∩_∩)O哈哈~

繼續(xù)學(xué)習(xí)

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號