Git超實用總結,再也不怕記憶力不好了

Git 是什麼?
Git 是一個分佈式的代碼管理容器,本地和遠端都保有一份相同的代碼。 Git 倉庫主要是由是三部分組成:本地代碼,緩存區,提交歷史,這幾乎是所有操作的本質,但是爲了文章更加簡單易懂,就不圍繞這塊展開了,有興趣的可以去了解下。 開門見山,我們直接來說說 Git 有哪些常見的操作。

Git 有哪些常規操作?
我們簡單說說Git有哪些常規操作,能夠讓我們應付簡單的開發需求。

克隆代碼

✦ 克隆遠端代碼

git clone + 遠程庫地址
✦ 查看本地的代碼狀態

// 可以明確的呈現出本地倉庫的狀態
// 哪些文件發生改動,哪些文件已經提交到本機
// 以及一些操作指示。
git status

Git超實用總結,再也不怕記憶力不好了
✦ 同步遠端分支變化

// 拉取指定分支的變化
git fetch origin master 
// 拉取所有分支的變化
git fetch 
// 拉取所有分支的變化,並且將遠端不存在的分支同步移除【推薦】
git fetch -p

✦ 同步遠端代碼變化。

// 都是先 git fetch,然後執行合併操作
// 不同的是,git pull 執行的是 git merge,git pull -r 執行的是git rebase
git pull origin master 
git pull -r origin master

關於 git merge 和 git rebase 各自的優劣,後文會詳細介紹。

這部分主要介紹了關於代碼克隆,同步遠端代碼變化的相關操作。接下來,我們看看關於本地代碼的一些操作。

操作 commit

首先我們要明確一個概念:就是每個 commit 都是一份完整的代碼狀態,用一個 commitID 來唯一標誌。
Git超實用總結,再也不怕記憶力不好了
Git超實用總結,再也不怕記憶力不好了
Java的小本家 2018-10-28 15:29
Git 是什麼?
Git 是一個分佈式的代碼管理容器,本地和遠端都保有一份相同的代碼。 Git 倉庫主要是由是三部分組成:本地代碼,緩存區,提交歷史,這幾乎是所有操作的本質,但是爲了文章更加簡單易懂,就不圍繞這塊展開了,有興趣的可以去了解下。 開門見山,我們直接來說說 Git 有哪些常見的操作。

Git 有哪些常規操作?
我們簡單說說Git有哪些常規操作,能夠讓我們應付簡單的開發需求。

克隆代碼

✦ 克隆遠端代碼

git clone + 遠程庫地址
✦ 查看本地的代碼狀態

// 可以明確的呈現出本地倉庫的狀態
// 哪些文件發生改動,哪些文件已經提交到本機
// 以及一些操作指示。
git status

✦ 同步遠端分支變化

// 拉取指定分支的變化
git fetch origin master
// 拉取所有分支的變化
git fetch
// 拉取所有分支的變化,並且將遠端不存在的分支同步移除【推薦】
git fetch -p
✦ 同步遠端代碼變化。

// 都是先 git fetch,然後執行合併操作
// 不同的是,git pull 執行的是 git merge,git pull -r 執行的是git rebase
git pull origin master
git pull -r origin master
關於 git merge 和 git rebase 各自的優劣,後文會詳細介紹。

這部分主要介紹了關於代碼克隆,同步遠端代碼變化的相關操作。接下來,我們看看關於本地代碼的一些操作。

操作 commit

首先我們要明確一個概念:就是每個 commit 都是一份完整的代碼狀態,用一個 commitID 來唯一標誌。

從某個角度上來說,Git維護的就是一個commitID樹,分別保存着不同狀態下的代碼。 所以你對代碼的任何修改,最終都會反映到 commit 上面去。

✦ 新增 commit

// 添加文件到緩存區,然後提交到本地倉庫
git add files
git commit -m '提交備註'

✦ 撤銷 commit

// 會將提交記錄回滾,代碼不回滾
git reset b14bb52
// 會將提交記錄和代碼全部回滾
git reset --hard b14bb52
// 將部分代碼文件回滾
git checkout -- files

✦ 合併 commit 合併 commit,本質上合併兩份不同狀態下的代碼。

// Git 提供了兩種合併 commit 的方式
git merge master
git rebase master
```**
那麼 git rebase 和 git merge 到底有什麼區別呢? merge是兩個分支處理衝突後,新增一個 commit 追加到master上。 rebase是將someFeature分支上的commit記錄追加到主分支上,值得注意的是,這個時候他的commit其實已經發生變化。
![](http://i2.51cto.com/images/blog/201810/28/1723859bcd9d6581125873c45e2fd4ca.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
相對來說,git merge 處理衝突更直接,而git rebase 能夠保證清晰的 commit 記錄。

合併 commit 的時候,通常會發生衝突。 可以全局搜索特殊字符比如<<<,找到需要處理的代碼位置,然後認真分析應該保留哪一部分代碼。
![](http://i2.51cto.com/images/blog/201810/28/3f2baaccf186da4a8593916ec18a080e.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
在團隊協作的時候,分支是必不可少的。那麼應該如何對分支進行操作呢?

**操作分支**

所謂的分支其實就是一個指向 commitID 的指針,你可以去.git/refs/heads裏去看看。
![](http://i2.51cto.com/images/blog/201810/28/203d808a77528a1fe65564c44125bc3d.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
通常情況下,我們建議分支至少能夠明確的標記功能名稱,如果能標記用戶就更好了,比如qixiu/feature。

✦ 查看分支
![](http://i2.51cto.com/images/blog/201810/28/1ef036a49e4188ed33419bb51ee26e66.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
可以同時看到本地分支和遠端分支,配合上前文介紹的git fetch -p可以第一時間查看到最新的分支信息。

✦ 新增本地分支 其實就是創建一個指針指向某一個 commitID。

// git branch qixiu/feature + git checkout qixiu/feature
// 從當前分支新增一個新的分支qixiu/feature
// 一般情況下,我們應該從master或者其他穩定分支來新增分支
git checkout -b qixiu/feature // 新建分支
git checkout qixiu/feature // 切換分支

✦ 刪除本地分支 其實就是移除一個指向 commitID 的指針。

// 刪除本地分支,如果本地還有未合併的代碼,則不能刪除
git branch -d qixiu/feature
// 強制刪除本地分支
git branch -D qixiu/feature

✦ 新增遠端分支 通常情況下,我們是新建本地分支,然後更新到遠端的方式來新增一個遠端分支
`git push origin qixiu/feature`
✦ 刪除遠端分支 同樣,我們也是通過更新到遠端的方式來刪除一個遠端分支

// 等同於git push origin -d qixiu/feaure
git push origin :qixiu/feature

簡單彙總一下

上面說的可能有些分散,這兒簡單總結一下有哪些經常使用的操作:

git status // 查看本地代碼狀態
git add files // 添加代碼到緩存區
git commit -m '提交內容的備註' // 提交代碼到本地倉庫
git checkout -b branchName // 不加-b就是普通切換分支
git fetch -p // 同步遠端分支狀態
git pull -r origin branchName // fetch遠端代碼到本地,並且以rebase的方式合併代碼
git push origin branchName // 更新本地代碼到遠端

以上幾條命令已經能夠應付日常的操作,稍微複雜一些的場景後文會介紹

基於基本操作,在實際項目中,我們應該怎麼利用 Git 實現協作呢?
Git 有哪些比較好的實踐?
Git 有一些成熟的開發流程,比較主流的有兩種:基於功能分支的開發流程 和 GitFlow開發流程。 相對來時,我更推薦前者,如果是複雜的大型項目,推薦GitFlow開發流程。 接下來,簡單介紹下這兩種協作模式。

**基於功能分支的協作模式**

基於功能分支的開發流程其實就是一句話:用分支來承載功能開發,開發結束之後就合併到 master 分支。 他的優點是能夠保證master分支的整潔,同時還能讓分支代碼邏輯集中,也便於 CodeReview。

**分支命名規範**

推薦使用如下格式:ownerName/featureName。 這樣既便於知道分支覆蓋的功能,也便於找到分支的負責人。以後清理分支的時候也很方便。

**開發流程**

✦ 從 master 切出一個新分支

`git checkout -b qixiu/newFeature`
✦ 開發一些新功能,然後提交 建議較多頻次的提交代碼到本地倉庫,以便能夠更靈活的保存或撤銷修改。 此外爲了保證提交日誌的清晰,建議備註清楚的註釋。

git status
git add files // 挑選需要提交的文件,或者全部提交
git commit -m '提交備註'
git push origin qixiu/newFeature

✦ 如果功能開發完成,可以發起一個CodeReview流程 ✦ 如果代碼測試通過,合併到 master,然後準備上線

// 冗餘版 合併到 master
git checkout master
git pull -r origin master
git checkout qixiu/newFeature
git rebase master // 處理衝突
git checkout master
git merge qixiu/newFeature
git push origin master
// 精簡版 合併到 master
git checkout qixiu/newFeature
git pull -r origin master // 將master的代碼更新下來,並且rebase處理衝突
git push origin master // 將本地代碼更新到遠端


有幾點需要注意: 不要在master合併代碼,保證master的可用性很重要。 確保在正確的分支執行正確的操作。 無論是處理衝突還是更新遠端代碼,請保有敬畏之心。

到此,一個正常的基於功能分支的開發流程就完成了。接下來看看另外一個開發流程。

**GitFlow 開發流程**

GitFlow 比前文講的基於功能分支的開發流程要複雜得多,它更適合大型的複雜項目。 它圍繞項目發佈流程定義了一個嚴格的分支模型,所有的開發流程都是圍繞這個嚴格的分支模型進行。 而這個模型約定了每個分支的角色,以及他們如何溝通。

我們先來看看 GitFlow 開發流程中幾個約定的分支,以及他們各自承擔的角色是怎麼樣的?
![](http://i2.51cto.com/images/blog/201810/28/35de170094692927545bf83a0663e203.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
✦ Master分支:用於存放線上版本代碼,可以方便的給代碼打版本號。 ✦ Develop分支:用於整合 Feature 分支。 ✦ Feature分支:某個功能的分支,從 Develop 分支切出,並且功能完成時又合併回 Develop 分支,不直接和 Master 分支交互。 ✦ Release分支:通常對應一個迭代。將一個版本的功能全部合併到 Develop 分支之後,從 Develop 切出一個 Release 分支。這個分支不在追加新需求,可以完成 bug 修復、完善文檔等工作。務必記住,代碼發佈後,需要將其合併到 Master 分支,同時也要合併到 Develop 分支。 ✦ Hotfix分支:緊急修復的分支,是唯一可以從 Master 切出的分支,一旦修復了可以合併到 Master 分支和 Develop 分支。

從每個分支的功能和約定可以看出,它流程多約束多,對於小規模應用並不適合。 當然 GitFlow 有一些輔助工具 gitflow 可以自動化的完成這些任務,對於大型項目也很有幫助。

前面講了 Git 有哪些基本操作,然後介紹了兩個主流的工作流程。 接下來我們看看 Git 有哪些特別的技巧值得一提。

**Git 有哪些小技巧?**
Git 操作除了基本的代碼管理功能,還有一些小技巧能夠讓你眼前一亮。

git reflog,查看操作記錄

這個我一定要放在第一個介紹,因爲它曾經數次解救了我的代碼
![](http://i2.51cto.com/images/blog/201810/28/c6e8353586ed35209f30c84095c61f25.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
仔細看上圖,reflog 記錄了你所有的 git 命令操作,對於復原某些莫名其妙的場景或者回滾誤操作有極大的幫助。

試想一個場景:你使用 git reset --hard commitID 把本地開發代碼回滾到了一個之前的版本,而且還沒有推到遠端,怎麼才能找回丟失的代碼呢? 你如果使用 git log 查看提交日誌,並不能找回丟棄的那些 commitID。 而 git reflog 卻詳細的記錄了你每個操作的 commitID,可以輕易的讓你復原當時的操作並且找回丟失的代碼。 當然,如果你丟失的代碼都沒有提交記錄,那麼恭喜你,你的代碼真的丟了。

**壓縮提交記錄**

這也是一個很實用的功能,前文提過,我們在開發中的時候儘量保持一個較高頻率的代碼提交,這樣可以避免不小心代碼丟失。但是真正合並代碼的時候,我們並不希望有太多冗餘的提交記錄,而且 rebase 合併代碼的時候,會把每個 commit 都處理一下,有時候會造成冗餘的工作。 所以,壓縮日誌之後不經能讓 commit 記錄非常整潔,同時也便於使用 rebase 合併代碼。

那麼,如何壓縮commit記錄呢? ✦ 使用 git log 找到起始 commitID ✦ git reset commitID,切記不要用 --hard 參數 ✦ 重新 git add && git commit ✦ git push -f origin branchName,因爲會有衝突,所以需要強制覆蓋遠端分支,請務必謹慎。 ✦ 合併到 master 中,然後更新遠端 master。

此外還有兩種壓縮日誌的辦法: git commit --amend:追加 commit 到上一個 commit 上。 git rebase -i:通過交互式的 rebase,提供對分支 commit 的控制,從而可以清理混亂的歷史。
![](http://i2.51cto.com/images/blog/201810/28/1a31b276a6b82e2ddf7585caa73b71d1.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
從實際應用來說,三種日誌壓縮都很優秀,git reset 更簡單,git rebase -i 更細膩。

**git rebase,合併代碼**

前文簡單介紹了 git rebase 和 git merge 的區別,坦率講,他們各有優劣。 git rebase 能讓你的 commit 記錄非常整潔,無論是線上回滾還是 CodeReview 都更輕鬆;但卻是一個有隱患的操作,使用時務必謹慎。 git merge 操作更安全,同時也更簡單;但卻會增加一些冗餘的 commit 記錄。

這兒簡單說說 rebase 的合併流程和注意事項吧。看下圖
![](http://i2.51cto.com/images/blog/201810/28/051c1cab863516abb6db9eee3bb952cd.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
有三個點需要注意: ✦ rebase 先找出共同的祖先節點 ✦ 從祖先節點把 pay 分支的提交記錄摘下來,然後 rebase 到 master 分支 ✦ rebase 之後的 commitID 其實已經發生了變化 尤其是第三點,經常會讓人誤操作,所以務必注意。

試想一下,開發過程中,如果我們頻繁的 rebase master 分支,會有什麼後果呢?
![](http://i2.51cto.com/images/blog/201810/28/d29bed882ea72ebf82046b94388521fa.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
當你不斷 rebase master 的時候,其實你本地的 d 都變成了 d` ,再要和遠端 pay 分支保持一致,你的本地分支 commit 記錄已經不堪入目了。

另外要注意,絕不要在公共的分支上使用 rebase!!!
![](http://i2.51cto.com/images/blog/201810/28/bb847e185eeff61c56513328789aa5a8.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
所以,爲了安全,團隊可以考慮採用 merge。

**pull request,方便CodeReview**

Git 不僅提供了代碼託管以及代碼開發的幫助,還提供了代碼審覈類似的功能。 當我們在功能分支開發完成之後,可以發起一個 pull request 請求,選擇需要對比的兩個分支
![](http://i2.51cto.com/images/blog/201810/28/d24658b2c8eaebd0fa1d5754ec99f77b.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
它會創建一個 pull request,制定相關人員來對代碼進行 review。 通常情況下,團隊應該鼓勵交叉 review,涉及到公共代碼的時候,一定要讓相關人 review。

**git hook,Git 的生命週期**

這個大多數人應該都,聽說過,git操作有它自身的生命週期,在不同的生命週期,我們可以做一些自動化的事情。

舉兩個簡單的例子: ✦ pre-commit的時候我們可以做 eslint ✦ post-commit的時候,我們可以做利用 jenkins 類似的工具做持續集成

當然還有更多的聲明週期,具體可以參考 Git 鉤子

git submodule && git subtree,管理第三方模塊

這兩個命令通常用來管理公用的第三方模塊。比如一些通用的底層邏輯、中間件、還有一些可能會頻繁變化的通用業務組件。 當然,兩者還是有區別的。 git submodule 主要用來管理一些單向更新的公共模塊或底層邏輯。 git subtree 對於部分需要雙向更新的可複用邏輯來說,特別適合管理。比如一些需要複用的業務組件代碼。在我之前的實踐中,我也曾用subtree來管理構建系統邏輯。

**git alias,簡化 Git 命令**

我們可以通過配置 git alias 來簡化需要輸入的 Git 命令。 比如前文的 git subtree 需要輸入很長的 Git 命令,我們可以配置 .git/config 文件來解決。
// git stpull appfe demo/xxx
// git stpush appfe demo/xxx
[alias]
 stpull = !git subtree pull --prefix=$1 appfe $2 \
 && :
 stpush = !git subtree pull --prefix=$1 appfe $2 \
 && git subtree split --rejoin --prefix=$1 $2 \
 && git subtree push --prefix=$1 appfe $2 \
 && :
**總結說點啥?**
該文首先介紹了 Git 常規操作 ✦ 包括克隆代碼、操作 commit、操作分支等。其實 Git 常規操作的命令並不多,請看第一部分的簡單總結。

其次介紹了 Git 開發流程 ✦ 該部分主要介紹了兩種主流的開發模式:比較輕量的 基於功能分支的開發流程 和適合複雜項目的 GitFlow 開發流程 ,兩種模式各有使用的場景,對於常規使用,前者就已經足夠了。

最後介紹了一些 Git 實用技巧 ✦ 主要包括:reflog 操作,壓縮日誌,rebase 的注意事項,利用 pull request 做 codeReview,利用 git hook 做一些自動化工作等。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章