還記得我剛開始用git,還沒了解rebase和merge的差別時,就看到隊友童鞋飛一樣地打指令,幾秒鐘把事情搞定了,然後在我還沒看清楚他幹了啥就清理了界面😂(這貨有強迫症)。那時起,我開始意識到漂亮的GUI不一定有打指令快捷友善。
這篇我想分享一些我感覺很好用的方法,包括:
- git指令 - 建議通過
來檢視更多的細節和選項git --help
- Oh-my-zsh的快捷指令 - 這裡有完整的Cheatsheet
- VSCode擴充插件
目錄
-
- 開始工作之前
-
- 将倉庫克隆到本地
- 切換到某個分支
- 建立新分支
- 分支重命名
- 檢視分支狀态
- 保持分支最新
- 完成并送出修改
-
- 送出前驗證一下自己的改動
- 送出改動
- 修改送出資訊
- 把修改推送到遠端
- 解決沖突
-
- 第一選項是rebase
- Rebase或merge之前考慮先壓縮一下commits
- 比較複雜的情況下選用merge
- 解決沖突
- 為啥代碼寫成這樣
- 清理不需要的分支
-
- 清理遠端的分支記錄
- 本地分支的清理
開始工作之前
将倉庫克隆到本地
大部分時候隻需要将git網站提供的clone指令複制黏貼就好,或者用指令:
用Oh-my-zsh可以更為簡短:
并且它還包括了一個遞歸clone所有submodule的選項。
不過現在我更喜歡用VSCode的git指令工具來clone,這樣就可以順便打開新clone的倉庫開始工作:
- Mac用
+command
+shift
,Windows用p
+ctrl
+shift
打開指令面闆,輸入p
來找到git
Git: Clone
用指令行和VSCode插件高效使用git代碼倉庫、處理日常工作 - 粘貼倉庫位址: 如果是github的倉庫可以直接用"Clone from Github"功能(需要github賬号登陸)
用指令行和VSCode插件高效使用git代碼倉庫、處理日常工作 - 選擇目的位址:
- 克隆完成後,右下角彈窗會提示打開倉庫:
用指令行和VSCode插件高效使用git代碼倉庫、處理日常工作
切換到某個分支
我通常用指令行加
tab
自動完成分支名來切換自己的分支:
git checkout <分支名>
// In Oh-my-zsh
gco <分支名>
需要檢視别人分支而我不熟悉分支命名的時候,就用VSCode git擴充在左下角狀态條上放的分支切換入口:
點選後會彈出指令行選擇分支:
![VSCode status bar - switch git branch]
建立新分支
新分支的建立隻需加上
-b
選項:
git checkout -b <分支名>
// Oh-my-zsh:
gco -b <分支名>
分支重命名
有時候我不小心打了錯别字或者有更好的名字,就用以下方式重命名:
git branch -m <新名字>
// Oh-my-zsh:
gb -m <新名字>
檢視分支狀态
如果一個分支已經推送到遠端,并且存在有多人協作、或是一個人用多裝置(公司電腦和家裡電腦)寫代碼,那時不時檢視一下現在分支狀态是個不錯的習慣。這樣可以避免因為沒有基于最新代碼開始工作而導緻的一些麻煩。
指令:
git fetch
git status
// Oh-my-zsh:
gf
gst
然後就會列印類似這樣的資訊:
有時候感覺這資訊太簡單了,不夠清晰。那我就會檢視git曆史。大多數時候隻需要最基本的指令就行了:
git log
不過這指令提供了不少有意思的選項(說實話太多了記不住啊),比如
--stat
會顯示變化的檔案,
--graph
會畫個醜醜的分支圖,
--oneline
把每個commit的資訊壓縮成一行顯示……很多都太長了,還是用Oh-my-zsh别名吧,比如:
glg // git log --stat
glgg // git log --graph
glo // git log --oneline --decorate
保持分支最新
如果我的分支沒有任何修改,但
git status
告訴我這個分支上有更新:
這時隻需要用指令:
git pull
// Oh-my-zsh
gl
來更新本地的分支。
如果不巧遠端分支有更新的話,會稍稍麻煩一些。我們會在稍後的"解決沖突"部分作詳細讨論。
完成并送出修改
送出前驗證一下自己的改動
在送出代碼前,我通常會再看一眼自己的改動來降低送出不必要的代碼(比如測試用的console.log)和錯誤的幾率。這時就感到VSCode自帶的git diff非常好使:
點選“重新整理”圖示來顯示更新,然後可以點選“樹狀清單”圖示切換為更清晰的目錄,點選其中的檔案會顯示非常容易看清楚改動的比較視窗。
送出改動
驗證完畢後,在這個“SOURCE CONTROL”裡可順便選擇這次需要送出的檔案(點檔案或檔案夾右側的➕号):
再輸入适當的送出資訊,點選✅圖示送出。
然而這兒有個比較麻煩的地方是,送出經常會因為配置了commit hook樣式驗證、type類型驗證而失敗,并且失敗後在VSCode OUTPUT面闆列印的錯誤資訊不如直接在指令行運作時列印的好閱讀。是以我更喜歡指令行送出:
git commit -m 'My commit message'
// Oh-my-zsh
gc -m 'My commit message'
如果想跳過手動stage檔案,直接送出所有改動,則可以加
-a
選項:
git commit -am 'My commit message'
// Oh-my-zsh
gc -am 'My commit message'
// 或
gcam 'My commit message'
注意
-a
選項時不會包括新建立,以前沒有送出過的檔案的。這時候需要多加一步:
// 把所有目前目錄下的檔案都stage:
git add .
// Oh-my-zsh:
ga .
// 如果就想把所有倉庫下的更改加入也可以這樣:
git add --all
// Oh-my-zsh:
gaa
修改送出資訊
同分支名,有時發現拼寫錯誤或漏加了一些檔案。那我就通過以下指令修改:
git commit --am
// Oh-my-zsh
gc --am
把修改推送到遠端
如果推送的是個新分支,或是從來沒設定過遠端上遊分支的話,推薦使用
-u
設定上遊:
git push -u origin <分支名>
// Oh-my-zsh:
gpsup
然後就可以在檢視分支狀态時看到本地分支跟遠端分支的差異(就像在“檢視分支狀态”一節中提到的一樣)。并且下次推送的時候就不再需要這樣的操作了:
git push
// Oh-my-zsh:
gp
解決沖突
第一選項是rebase
當分支的修改量不大的時候,
rebase
是我的第一選項。因為它會確定我的更新是建立在最新代碼上的,避免很多問題。
rebase上遊可以通過
git pull
實作:
git pull --rebase
// Oh-my-zsh:
ggu
不過我更多情況下會rebase最新的主分支:
git rebase origin/master
// Oh-my-zsh:
grb origin/master
// 或
grbm
指定從
origin
這樣的上遊會確定git從遠端拉取最新的代碼再rebase。
Rebase或merge之前考慮先壓縮一下commits
有時我在開發中送出了多個小改動,這些送出在主分支中沒啥存在意義,或者存在一些對某個子產品的反複修改。然而這些commits會在我試圖rebase或者回過頭來檢視修改的緣由時造成一定的麻煩,是以我會考慮在合并代碼前将這些commits壓縮成一個。
如果在自己的分支,我隻想簡單地把所有此次修改壓縮成1個commit的話,我就:
- 通過合并請求看一下有多少commits(像這個),或在git log裡檢視 (參照檢視分支狀态 一節)
-
或git reset --soft HEAD~<commit數>
(注意這兒的commit SHA是需要保留的最新的commit SHA)來把那些commits移除,所有改動恢複為staged狀态 - 需要注意的是reset一個合并分支的commit會同時reset所有被合并的commits,是以這裡的commit數量跟數出來的可能不同。git reset --soft <commit_SHA>
-
來創新一個新的commitgc -m <new_commit_message>
-
- 如果這些送出之前已經被推送到遠端,那這時因為我們修改了原本的git曆史樹結構,是以需要加gp -f
來強制推送。這其實挺危險的,請確定這樣做的安全性。-f
如果需要保留原有的消息,和作者的資訊。那就考慮用git的互動模式:
-
或git rebase -i HEAD~<commit_counts>
git rebase -i <commit_SHA>
- 然後它會打開指令行編輯器如
:vi
根據提示資訊修改每行commit消息頭部的操作指令詞(打開時候都是用指令行和VSCode插件高效使用git代碼倉庫、處理日常工作 pick
)。
假設這邊我就把3個送出合成1個,那我需要保持第一個commit為
,并修改剩餘兩個為pick
或squash
。s
- 儲存退出。修改成功則會顯示如下确認資訊編輯界面:
用指令行和VSCode插件高效使用git代碼倉庫、處理日常工作 - 再度儲存退出就完成了。
比較複雜的情況下選用merge
如果想更新一個共享分支(多人基于這個分支上開發),rebase就不是一個很好的選項,因為它會導緻所有基于它的其他分支都遇到很嚴重的沖突。
還有一種情況是在開發一個比較大的項目,為了更好地控制版本,特意分了多次送出。這時用rebase就會遇到需要多次解決代碼沖突,而我通常解決2個沖突之後就開始迷失自我不知道這是哪兒了。
這時用
merge
比較好:
如果隻是要合并上遊分支的話
git pull
就可以了:
git pull
// Oh-my-zsh:
gl
更多情況下我需要合并主分支, 那就用:
git merge origin/master
// Oh-my-zsh:
gm origin/master
解決沖突
一想到解決沖突就想到Webstorm那個超贊的沖突解決工具。但是,我幾年前還是抛棄了Webstorm,因為它特别能把我的記憶體和CPU吃光,系統異常卡頓,然後我一去不複返。這邊還因為沒有能媲美的工具導緻我有個比較長的适應期,現在感覺VSCode自帶的git工具也挺好的。
合并或rebase的時候,如果遇到沖突,切換到“SOURCE CONTROL”面闆點選“重新整理”圖示就能看到用“C”标注出來的沖突檔案:
選擇打開這些檔案,然後就在編輯器裡看到高亮顯示和
Current Change
、
Incoming Change
這些選項。講真,這比通常git工具顯示的
ours
和
theirs
要好了解多了。
這兒不太友善的地方是它是上下顯示的,而不是像Webstorm這樣左右比較的,是以在沖突區域大的時候就感覺不太好使了。這兒我暫時還沒有更好的辦法,也不想因為這個較少遇到的情況單獨裝個軟體,先就這樣用着吧。
為啥代碼寫成這樣
當有地方壞了或看起來很奇怪,這時有意義的送出資訊和可追溯的git曆史樹就顯得特别有用。這裡我超愛用VSCode的GitLens插件:
它提供了特别多的功能來幫我們檢視曆史,不過我幾乎隻用
LINE HISTORY
和
FILE HISTORY
來幫我了解這塊代碼是怎樣一步步變成現在的模樣的:
清理不需要的分支
清理遠端的分支記錄
如果有在本地打開一些遠端分支,在這些分支被合并之後,本地關于這個分支的記錄是不會自動清理的。大多情況下這沒什麼,就讓它在那好了。但在大型代碼倉庫有一定幾率遇到奇怪的問題而導緻無法做任何git操作的麻煩。是以我會隔段時間清理一下:
git remote prune origin
// 或者可以用fetch來跑:
git fetch --all --prune
// Oh-my-zsh會比較友善:
gfa
本地分支的清理
本地分支清理起來比較麻煩。我有很長一段時間都隻依靠像這樣手動删:
git branch | cat // 列印出所有本地分支
git branch -D <分支名>
後來我發現Oh-my-zsh的一個快捷指令,它可以删掉所有已經被合并到
master
/
develop
/
dev
的分支:
gbda