Git實戰進階教程

語言: CN / TW / HK

Git的功能是對文件做版本管理,其底層原理是一個對文件存取的系統,要想掌握Git,最重要的是理解commit tree,也就是提交記錄歷史,平時開發中我們都是通過分支來更新commit tree,Git的基礎就是要學會分支操作,推薦閲讀 圖解Git分支和命令

在日常開發中,只掌握分支操作是不夠的,還需要通過各種命令操作commit tree,本文我們選擇5個典型場景,介紹一下 Git 的進階技巧,如下所示,學會這些技巧,可以極大提高工作中Git使用的效率:

  • 選擇版本
  • 搜索調試
  • 重寫歷史
  • 重置揭祕
  • 高級合併

選擇版本

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

^和~都匹配當前提交的父提交,^和~匹配父提交的父提交,^和~後面跟數字的時候意義是不同的,具體可以看下面的例子,假設有如下圖所示的提交樹:

image.png

如下的命令,可以看到^和~的區別:

bash $ 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

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

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

搜索調試

A:設想這樣一種情況,摸個分支 test,開發完後被刪除了,怎麼找回這個分支呢?

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

bash $ git reflog 0e94c5b [email protected]{0}: commit: 222 7e07aa7 [email protected]{1}: commit: 111 c5aba97 [email protected]{2}: commit: 000

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

bash $ git checkout 7e07aa7 # 或者git checkout [email protected]{1} $ git checkout -b test

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

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

bash $ 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

blame 時可以指定範圍

bash $ git blame -L10,15 README.md # 查看10-15行的信息

C:設想這樣一種情況,你想在 Git 的某個歷史提交中進行搜索?

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

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

D:設想這樣一種情況,你想在 Git 的整個歷史中進行搜索?git log 可以實現這個功能

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

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

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

bash $ git bisect start # 開始 $ git bisect bad # 標記為好的 $ git bisect good # 標記為壞的 $ git bisect reset # 結束

重寫歷史

假設你提交完後發現忘記了一些東西,打算更改上次提交,在 git 中可以使用追加提交,假設現在倉庫狀態如下所示

image.png 修改完後可以再次提交

bash $ git add . $ git commit --amend

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

image.png 如果你進行了幾次提交後後悔了,想重寫之前的好幾次提交,那就只能用 rebase 了,假設目前狀態如下

image.png 假設你想重寫 A1 和 A2

bash $ git rebase -i HEAD~2

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

image.png

重置揭祕

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

reset 全局模式可以用下圖總結

image.png reset 的文件模式可以覆蓋索引區,一個副作用就是用來取消暫存

bash git reset xxx – file

checkout 的全局模式可以用下圖總結

image.png

checkout 的文件模式會覆蓋索引區和工作區,可以用來丟棄修改,屬於不可逆轉的操作

bash git checkout xxx – file

其實下圖就總結兩個命令的區別

image.png

高級合併

合併分支時,很多人非常害怕遇到衝突,其實衝突並不可怕

A:git 默認的衝突顯示包括 our 和 their,如果想得到和 svn 那樣包含 base+our+their 的代碼,可以檢出衝突

bash $ git checkout --conflict=diff3 hello.rb

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

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

C:合併衝突一團亂麻,想撤銷合併

bash $ git merge --abort

D:合併後後悔了?想撤消合併?分為兩種情況

假如還沒推送到遠端,可以 reset 掉

bash $ git reset --hard HEAD~

image.png

如果已經推動到遠端,可以用 revert

bash $ git revert -m 1 HEAD

image.png

總結

歡迎大家閲讀本文,如果你覺得本文對你有幫助,那就點贊加關注作者吧,如果對本文有任何疑問,歡迎在評論區交流。

原創不易,求分享、求一鍵三連

我正在參與掘金技術社區創作者簽約計劃招募活動,點擊鏈接報名投稿