BlackFlame33

BlackFlame33

若无力驾驭,自由便是负担。个人博客 https://blackflame33.cn/

Git 實用小抄

Git 實用小抄#

Git - the stupid content tracker.

在專案開發過程中,Git 是非常得力的版本控制管理工具。它使得開發者可以不分時間地點,高效協作。本文簡要說明 Git 的基本用法,並介紹提高效率的小 tips,以及 Git 工作流分支管理。

一圖了解 Git 分區

常用 Git 命令#

git status#

使用git status查看緩衝區(index)和工作目錄(workspace)的狀態,你可以在這裡看到:

  • 當前分支
  • 未跟蹤的文件
  • 已修改的文件
  • 已暫存的文件
  • 附加信息

勤用git status能幫助你隨時掌握倉庫狀態。

git add#

使用git add命令將指定文件提交到緩衝區(index)。建議搭配git status,謹慎查看需要添加至緩衝區的修改,以防將不在 commit log 描述範圍內,或未被.gitignore文件忽略的文件提交上去了。

git commit#

使用git commit將修改提交到本地倉庫(repository)。Git 強制需要給每個 commit 添加描述說明。如果當你提交後,猛然一拍大腿,驚呼 “我提交錯了!”,這時還可以使用git reset來恢復,或使用git commit --amend來修改最新的提交。如果你不在乎新提交一個記錄,那麼也可以使用git revert生成一個新的 commit 來撤銷你的更改。git commit的信息應該規範填寫,最好一看 commit log 便知道這個 commit 做了何種修改。

git commit 規範#

規範要求 commit log 的意義在於可追溯專案歷史記錄,以及更新代碼時用最少的成本獲取提交信息 —— 這個更新做了哪些更改。在一個 commit log 裡盡量通過三個維度描述一個 commit:type(類型)、scope(範圍)、subject(簡介)。

type(必選項)#

type 代表一個 commit 的提交類型。後續追溯歷史記錄時,先通過 type 進行篩選,可以節約不少時間。

type(必須)英文說明
featfeature新增功能
fixfix修復缺陷
docsdocuments文檔更新
stylestyle代碼格式
refactorrefactor代碼重構
perfperformance性能提升
testtest測試相關
buildbuild構建相關
cicontinuous integration持續集成
revertrevert回退代碼
chorechore其他修改
scope(可選項)#

scope 代表一個 commit 修改的範圍,比如視圖層、控制層,模型層等等。

subject(必選項)#

subject 代表一個 commit 的說明,最好不超過 50 字。說明應該準確描述這次修改,方便追溯。為了達成目的,提交的顆粒度可以小一點,後續可以通過git rebase合併多次提交,整理提交記錄。

好的歷史記錄,看著賞心悅目。其實更建議中國人寫 subject 用中文。。。

令人眼前一亮的歷史記錄

壞的歷史記錄,讓人眼前一黑。但人家是大佬,他這樣寫一定是有他的理由的(确信)

令人眼前一黑的歷史記錄

git pull#

使用git pull將遠端更改同步到本地倉庫。建議時常pull一下,保證自己正在修改的是最新的分支。如果你有未commit的更改,則 git pull 命令的合併部分將失敗,而你的本地分支將保持不變。因此,在從遠程倉庫中提取新提交之前,你應該始終在分支中提交你的更改。

要完全理解git pull的工作模式,我們需要了解兩個命令:git fetchgit merge

git fetch#

使用git fetch來更新倉庫中所有遠程倉庫的跟蹤分支。實際上沒有任何更改反映在任何本地工作分支上。這意味著只是你的本地倉庫感知到了遠端倉庫的更新,但還沒有做同步。IDEA有自動fetch的相關插件,建議安裝以及時感知到分支更新。

git merge#

使用git merge target-branch將目標分支合併到當前分支上。merge的合併策略有兩種:fast-forward 和三方合併

  • Fast-forward 合併 如果在兩個分支之間沒有任何變更,則 Git 會直接將目標分支指向源分支的提交對象,這就是所謂的 Fast-forward 合併。該操作不會創建新的提交對象,因為早期的提交已經包含了所有的變更。

iShot_2023-03-25_09.09.51

  • 三方合併 如果兩個分支之間存在變更衝突,則需要進行三方合併。在三方合併中,Git 會創建一個新的提交對象,該對象包含兩個分支之間的共同點和每個分支相對於共同點的變更。Git 還會嘗試將衝突解決為一致的變更。

    iShot_2023-03-25_09.14.25

git push#

使用git push將修改上傳至遠程倉庫(remote)。建議時不時pull一下代碼。

其他實用 Git 命令#

git diff#

使用git diff查看工作空間還未被添加至緩衝區的修改;使用git diff --cached查看緩衝區尚未被提交的修改;使用git diff branch1 branch2查看兩個分支間的差異。

git stash#

git stash系列命令帶來了一個新的區域 —— 暫存區(stash entry)。使用git stash push將你尚未提交的修改壓進暫存區,你的工作空間和緩衝區將恢復成最新 commit 的修改。使用git stash pop彈出暫存區栈頂的修改。使用git stash list查看暫存區保存的修改列表。

git stash經常用來提示不能 pull 的情況時,這通常代表工作空間或緩衝區還有修改沒有提交。這時可以先將修改壓進暫存區,恢復工作空間和緩衝區,待 pull 操作完成後,再彈出修改。

git stash也很適合切換分支。例如當我們在自己負責的 feature 分支開發時,線上突然有 bug 需要你搞定,你需要立即切換分支到 master 新建 hotfix 分支修復。可你當前的修改還未提交,因為功能尚未完成,也不能提交。這時就可以使用git stash命令將修改壓進暫存區,切換分支進行開發,完事再回到壓入暫存區時的分支彈出修改即可。

git rebase#

git rebase系列命令使我們有機會重新整理我們的提交,使歷史記錄乾淨清爽,非常易於追溯歷史。對此,Vue 作者尤雨溪曾在知乎上提到:

image-20230325095828583

攻擊性還是很強啊 2333

git rebase target-branch的本質是:找到當前分支與目標分支的共同祖先,先將我當前分支的修改 “拋到一邊”,使我的當前分支與目標分支的歷史提交記錄一致,再將 “拋到一邊” 的 commit 應用回當前分支。這種合併分支的策略與git merge的區別是:

  • git merge會留下無用的 commit log 信息,污染歷史記錄。
  • git rebase為了整理歷史記錄,理所當然會修改當前分支的 commit 。所以在一條分支上,當你 rebase 後,這條分支的順序已經和之前不同了,倘若此時別人也在這條分支上,當他 push 時,可能會遇到錯誤,甚至可能會丟失更改。

所以建議git rebase只用來修改還未 push 到遠端倉庫的 commit,或在只有你自己使用的分支上應用。

iShot_2023-03-25_10.24.13

當然git rebase除了拿來合併分支,還可以合併多個 commit 。我們使用git rebase -i [startpoint] [endpoint]通過選項-i—— 即--interactive開啟交互式編輯界面。這裡[startpoint] [endpoint]是一個左開右閉的區間,必須指明[startpoint],默認[endpoint]HEAD指向的 commit 。例如我們通過git rebase -i HEAD~3來編輯最新的 3 次提交。

pick 54f88ff 第一次提交
pick 41346f3 第二次提交
pick 3b9307e 第三次提交

# 變基 edb3a72..3b9307e 到 edb3a72(3 個提交)
#
# 命令:
# p, pick <提交> = 使用提交
# r, reword <提交> = 使用提交,但編輯提交說明
# e, edit <提交> = 使用提交,但停止以便修補提交
# s, squash <提交> = 使用提交,但擠壓到前一個提交
# f, fixup [-C | -c] <提交> = 類似於 "squash",但只保留前一個提交
#                    的提交說明,除非使用了 -C 參數,此情況下則只
#                    保留本提交說明。使用 -c 和 -C 類似,但會打開
#                    編輯器修改提交說明
# x, exec <命令> = 使用 shell 運行命令(此行剩餘部分)
# b, break = 在此處停止(使用 'git rebase --continue' 繼續變基)
# d, drop <提交> = 刪除提交
# l, label <label> = 為當前 HEAD 打上標記
# t, reset <label> = 重置 HEAD 到該標記
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       創建一個合併提交,並使用原始的合併提交說明(如果沒有指定
# .       原始提交,使用註釋部分的 oneline 作為提交說明)。使用
# .       -c <提交> 可以編輯提交說明。
# u, update-ref <引用> = 為引用 <ref> 設置一個佔位符,以將該引用更新為此處的新提交。
#                       此 <引用> 在變基結束後更新。
#
# 可以對這些行重新排序,將從上至下執行。
#
# 如果您在這裡刪除一行,對應的提交將會丟失。
#
# 然而,如果您刪除全部內容,變基操作將會終止。

註釋中詳細解釋了可用的命令。在此場景中,假設我們希望合併這三個 commit,我們如此修改:

r 54f88ff 第一次提交
f 41346f3 第二次提交
f 3b9307e 第三次提交

接下來我們修改 commit log 信息:

重複向控制台輸出“HelloWorld”

# 請為您的變更輸入提交說明。以 '#' 開始的行將被忽略,而一個空的提交
# 說明將會終止提交。
#
# 日期:  Sat Mar 25 11:28:26 2023 +0800
#
# 交互式變基操作正在進行中;至 edb3a72
# 最後完成的命令(1 條命令被執行):
#    reword 54f88ff 第一次提交
# 接下來要執行的命令(剩餘 2 條命令):
#    fixup 41346f3 第二次提交
#    fixup 3b9307e 第三次提交
# 您在執行將分支 'master' 變基到 'edb3a72' 的操作時編輯提交。
#
# 要提交的變更:
#       修改:     HelloWorld.java

完成修改後查看git log此時歷史記錄已成功合併:

image-20230325113207939

通過git rebase命令,我們可以在將 commit push 上遠端倉庫前,對本地倉庫的 commit 進行編輯、重組、合併、編排,來獲得乾淨整潔,合理顆粒度的歷史記錄。切忌修改已經 push 過遠端倉庫的 commit !!!

git cherry pick#

使用git cherry pick命令,你可以明確將某幾個 commit 應用到當前分支上。例如現在分支情況為:

image-20230325132314042

現在我想直接將這個 commit 應用到 main 分支上。輸入:

git cherry pick C2(這個 commit 的 Hash 值)

image-20230325132449907

這就已經生效了,這會在 main 分支上新建一個 commitC2'。這兩個 commit 內容一樣,但 Hash 值是不一樣的。

Git 工作流#

最後簡要描述下 Git 工作流,Git 工作流工作流展示了一個專案為了隔離不同狀態的代碼,需要通過多種不同種類的分支配合,達成快速迭代的目的。目前流行的分支模型有特性分支開發模式、主幹開發模式等。

特新分支開發模式#

img

  • 分支管理複雜;
  • 開發周期相對較長;
  • 視時長,與 master 分支的差距會越來越大,最終可能會導致難以解決衝突甚至不可能解決衝突。

主幹開發模式#

img

  • 分支管理簡單;
  • 開發周期可以很短,隨時都能簽出新版本的分支;
  • 代碼質量要求高。

最後#

  1. 掌握 Git 工具,幫助提高開發效率和協作效率;
  2. 常用的幾大命令:addcommitpushpullstatus應該熟練掌握,並可通過[option]可選項進行功能的增強;
  3. commit log 規範是為了方便追溯歷史,以及記錄專案變更,更重要的是,可以讓人通過查看歷史記錄快速了解專案;
  4. 常 pull。經常 pull 保證你是在最新分支上修改,這可以通過頻繁 commit 保證。而最後 push 時,應該考慮是否可以通過 rebase 整理歷史記錄後再 push 上遠端倉庫;
  5. 使用 stash 暫存區保證緊急切換代碼時忘了 commit 導致可能的代碼污染;
  6. 根據實際使用的分支模型。一旦決定,就應該積極貫徹,否則由於破窗效應,良好的分支管理將被打破,專案質量與迭代速度也將得不到保障。
相關鏈接

只會 git log ? 其實 git 還有兩個好用的 log 命令

三行代碼讓你的 git 記錄保持整潔

如何規範你的 Git commit?

Google 和騰訊都採用什麼樣的開發模式?

Git 沙盒練習

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。