其實上一篇寫的內容僅僅是Git的冰山一角,如果你認為Git就是簡簡單單的幾行命令,那隻能說明你還沒有真正瞭解Git這個強大的內容定址文件系統。這篇文章,還是接著介紹一些實用但是很少有人知曉的一些命令,好比說具有魔性的Git變基(git rebase)以及常用的GUI。 我之前詢問過一些人,討論到Gi ...
其實上一篇《開發中關於Git那些事》寫的內容僅僅是Git的冰山一角,如果你認為Git就是簡簡單單的幾行命令,那隻能說明你還沒有真正瞭解Git這個強大的內容定址文件系統。這篇文章,還是接著介紹一些實用但是很少有人知曉的一些命令,好比說具有魔性的Git變基(git rebase)以及常用的GUI。
我之前詢問過一些人,討論到Git這塊,他們當中有的直接使用GUI,說簡單省事。其實,每一個GUI都有它的側重點,並不是所有的GUI都適合用。我倒是建議大家使用命令行。何況有些功能GUI不一定支持,而且有時候一行命令的事,還要點來點去,也不省事。之前看到過一篇文章,是關於如何使用Vim編輯器的,對,大家平時開發習慣了IDE,愛上了IDE。但是好的程式員怎麼會因為簡單省事而放棄學習呢。這樣說可能更好提現,學習任意一款IDE,你都需要耗時很久,但是如果你平時習慣了使用Vim編輯器,愛上用Vim編輯器寫代碼,那麼任意一款集成Vim編輯器的IDE,一上來就會非常順手。同樣的道理,如果你瞭解了Git內部原理,平時習慣使用命令處理,那麼給你任意一款GitGUI,相信你一看就會用,而且很快就上手。所以,學習順序有時候很重要,基礎扎實了,才不會被問題難倒,地基決定高度。
1.客戶端配置
1.1 修改預設編輯器
預設使用Vim編輯器,當然可以使用core.editor修改
git config --global core.editor emacs
1.2 修改log分頁
預設使用less,可以使用core.pager來設置為more或則其他,也可以使用空字元串,關閉分頁,一次性載入所有內容
git config --global core.pager ''
1.3 Git 中的著色
使用到color.ui,預設auto,如果你不喜歡可以使用false關閉。
git config --global color.ui false
其實如果想具體到某些特定命令,都是有true、false 或 always可以設置的,比如以下
color.branch
color.diff
color.interactive
color.status
以上每個配置項都有子選項,它們可以被用來覆蓋其父設置,以達到為輸出的各個部分著色的目的。例如,為了讓 diff 的輸出信息以藍色前景、黑色背景和粗體顯示,你可以運行
git config --global color.diff.meta "blue black bold"
你能設置的顏色有:normal、black、red、green、yellow、blue、magenta、cyan 或 white。正如以 上例子設置的粗體屬性,想要設置字體屬性的話,可以選擇包括:bold、dim、ul(下劃線)、blink 、reverse(交換前景色和背景色)。
2.實用命令
git branch -v
該命令顯示本地分支最後一次提交說明
* dev cdc7241a fixbug
master f586f6b5 ****
如果需要顯示本地和遠程,加上-a即git branch -v -a
* dev cdc7241a fixbug
master f586f6b5 ****
remotes/origin/HEAD -> origin/master
remotes/origin/dev cdc7241a fixbug
remotes/origin/master f586f6b5 ****
remotes/origin/oldIm 97d131bb 2.5.1 封版
git branch -vv
除了具有git branch -v
命令的作用,還可以顯示出每一個分支正在跟蹤哪個遠程分支,以及本地分支與遠程分支是否是領先、落後。同樣,如果想看遠程加上-a
,也就是all(所有),反正我就是這麼記憶的
* dev 6512ef90 [origin/dev: ahead 1] test
master 78b4b30a [origin/master] 171227122 2.12.2 封版
3.Git變基(Rebasing)
實用舉例1
其實在Git當中整合兩個分支的方式除了merge,還有一種方式,那就是rebase。如上圖,現在要合併C3和C4,如果使用merge合併是這樣子的。它會把兩個分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)進行三方合併,合併的結果是生成一個新的快照(並提交)。
但是如果使用rebase:你可以提取在 C4 中引入的補丁和修改,然後在 C3 的基礎上再應用一次。在 Git 中,這種操作就叫做變基。你可以使用 rebase 命令將提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一樣。
執行步驟就是,首先切換的experiment分支git checkout experiment
,然後運行git rebase master
,此時準備“重演”,接下來就是看你要在哪個分支重演,就切換到哪個分支,這邊在主分支重演,切換到主分支git checkout master
,然後整合即可git merge experiment
。其實此時的merge和之前的merge不一樣,這邊的merge只需要進行一次fast-forward,就是快速合併,head快速前進到C4'。
它的原理是首先找到這兩個分支(即當前分支 experiment、變基操作的目標基底分支 master)的最近共同祖 先 C2,然後對比當前分支相對於該祖先的歷次提交,提取相應的修改並存為臨時文件,然後將當前分支指向目標基底C3, 最後以此將之前另存為臨時文件的修改依序應用。
git checkout experiment
git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
git checkout master
git merge experiment
此時,C4' 指向的快照就和上面使用merge命令的例子中 C5 指向的快照一模一樣了。這兩種整合方法的最終結果沒有任何區別,但是變基使得提交歷史更加整潔。你在查看一個經過變基的分支的歷史記錄時會發現,儘管實際的開發工作是並行的,但它們看上去就像是先後串列的一樣,提交歷史是一條直線沒有分叉。
實用舉例2
直接看下圖,現在我有這樣的需求,就是將C8,C9提交到主分支,但是不要C3,你如何做?
其實辦法總是有的,在前篇文章中,有講到git stash命令,其實,我們可以在client分支找到C3的哈希值直接執行git reset 哈希值(C3)
然後把C8,C9的修改直接git stash 貯存起來,切換到master分支,來個git stash pop
搞定。現在我們使用變基來操作,感受下變基的魔性。
git rebase --onto master server client
以上命令含義:取出 client 分支,找出處於 client 分支和 server 分支的共同祖先之後的修改,然後把它們在 master 分支上重演一遍。
現在可以快進合併 master 分支了。
git checkout master
git merge client
實用舉例3
再舉一個例子,也是關於git rebase --onto的使用
H---I---J topicB
/
E---F---G topicA
/
A---B---C---D master
git rebase --onto master topicA topicB
H'--I'--J' topicB
/
| E---F---G topicA
|/
A---B---C---D master
This is useful when topicB does not depend on topicA.
這樣的例子好多,感興趣可以使用git rebase --help
查看。
註意事項
這點一定要看,不要對在你的倉庫外還有副本的分支執行變基。也就是說,一個人開發隨便搞,多人開發有原則的搞。如果你不遵循這個原則,多人開發出現問題別來找我。
為什麼呢?假如有個人在本地使用了merge合併分支後,push到了遠程伺服器,後來他感覺不爽,想通過變基處理,恰是這個時候你pull了伺服器的代碼,那就會出現問題。問題就是,以後看記錄會出現相同的提交,本來張三想丟棄的東西被你保留了。如果想看詳細舉例,推薦查看Pro Git這本書中關於Git變基一節。
總之,只要是你的代碼和你建立的分支,還沒有執行push之前,隨意搞,push後就不要再想著使用變基了,避免出問題。如果你更喜歡merge,喜歡看Git實際發生的事,那就使用merge吧。反之,你更喜歡流水線一樣的記錄,從前到後,沒有一堆堆複雜的合併,那就用rebase。
4.GitGUI
十幾款GUI,點開查看即可。
SourceTree
GitHub Desktop
TortoiseGit
GitUp
......
我比較喜歡GitUp,簡潔些。但是我仍舊在使用命令行,就當為了給電腦省空間吧。