面試中的那些 Git 問題 - 基礎部分

mmoaay發表於2017-10-22

團隊協作能力一直是我們招聘開發人員的重要考核指標之一。而考核這個能力的原因很簡單:一般公司都不會只有一個開發…而一旦涉及多人協作開發,良好的協作能力和習慣能顯著提高整個團隊的開發效率。Time is money!

說到協作,面試中當然就會聊到開發人員日常最需要協作的事情,程式碼協作。因為 Github 在國內的流行,很多公司都已經把程式碼託管到 Github 或者內部的 git 服務上,所以大家也慢慢把 git 技能的考察引入到面試中。

下面就分享一些筆者個人整理的 git 相關問題以及解析。

基礎部分

平時都用什麼 git 工具?

除了 git 自帶的命令列工具,做為 iOS 開發,接觸最多的當然是 Xcode 自帶的 Source Control 功能,但是這兩個工具都有一些自己的不足。

  • Xcode:Xcode 本身自己是支援 git 的,但是它有一個特別坑的點的:那就是卡…而且檔案越大越卡,甚至會 Crash。所以對於 .pbxproj 這種大檔案的衝突,Xcode 基本是蒙圈狀態的,另外它提供的 git 支援也有些單薄。

  • 命令列:只能說十個裡面九個菜,還有一個是大神,雖然命令列提供了全部的功能,但是很多用 GUI 工具可以很便捷解決的問題,命令列做起來都比較麻煩。當然並不是讓大家不要去命令列,通過命令列可以對 git 的功能和原理有一個更深入的瞭解。

因為這些不足,所以我們通常會用一些第三方 GUI 工具來提高我們 git 倉庫管理的效率:

  • SourceTree:筆者日常使用的一個圖形化的 git 增強工具,而最好用的功能就在於它整合了 GitFlow,讓開發者可以更簡單、更規範的去做一些 git 操作;另外它還提供了更友好的 merge 介面,但是操作起來不是很順手,因為它只支援整行刪除;

  • SmartGit

  • Tower:Tower 被譽為 Mac 平臺最好的 git 客戶端。軟體大大簡化了 git 的使用難度,使用者可以通過拖拽完成操作,更方便、更高效。需要注意的是,30 天后還想使用全特性的話,需要 $60。

  • Atom:Atom 本身並不是專門用來做 git 管理的工具,而是一個支援多種開發語言的開源 IDE。提到它的原因是 merge-conflicts, 這個外掛提供的 merge 介面,要比 SourceTree 的更好用,Atom 會在當前內容的基礎上,把有衝突的部分直接對比標示出來,開發人員可以像編輯普通文字一樣在標示的區域內直接進行修改,並最終選擇自己滿意的那個部分作為 merge 之後的內容。

考察關鍵點:
  • 對自己所用 git 工具的瞭解程度;
  • 主觀能動性,是否能主動找方法解決目前工作中的痛點。
回答關鍵點:

不要只說你用什麼。而是要分析優劣勢。為什麼用哪個工具?為什麼不用哪個工具?

git add 和 git stage 有什麼區別

在回答這個問題之前需要先了解 git 倉庫的三個組成部分:工作區(Working Directory)、暫存區(Stage)和歷史記錄區(History):

  • 工作區:在 git 管理下的正常目錄都算是工作區,我們平時的編輯工作都是在工作區完成。
  • 暫存區:臨時區域。裡面存放將要提交檔案的快照。
  • 歷史記錄區:git commit 後的記錄區。

然後是這三個區的轉換關係以及轉換所使用的命令:

然後我們就可以來說一下 git add 和 git stage 了。其實,他們兩是同義的,所以,驚不驚喜,意不意外?這個問題竟然是個陷阱…引入 git stage 的原因其實比較有趣:是因為要跟 svn add 區分,兩者的功能是完全不一樣的,svn add 是將某個檔案加入版本控制,而 git add 則是把某個檔案加入暫存區,因為在 git 出來之前大家用 svn 比較多,所以為了避免誤導,git 引入了git stage,然後把 git diff --staged 做為 git diff --cached 的相同命令。基於這個原因,我們建議使用 git stage 以及 git diff --staged。

考察關鍵點:
  • 對 git 工作區(Working Directory)、暫存區(Stage)和歷史記錄區(History)以及轉換關係的瞭解;
  • 對 git add 和 git stage 的瞭解。
回答關鍵點:
  • 工作區(Working Directory)、暫存區(Stage)和歷史記錄區(History)以及轉換關係不能少;
  • git stage 是 git add 的同義指令;
  • 我用 git stage。

git reset、git revert 和 git checkout 有什麼區別

這個問題同樣也需要先了解 git 倉庫的三個組成部分:工作區(Working Directory)、暫存區(Stage)和歷史記錄區(History)。

首先是它們的共同點:用來撤銷程式碼倉庫中的某些更改。

然後是不同點:

首先,從 commit 層面來說:

  • git reset 可以將一個分支的末端指向之前的一個 commit。然後再下次 git 執行垃圾回收的時候,會把這個 commit 之後的 commit 都扔掉。git reset 還支援三種標記,用來標記 reset 指令影響的範圍:

    • --mixed:會影響到暫存區和歷史記錄區。也是預設選項;
    • --soft:隻影響歷史記錄區;
    • --hard:影響工作區、暫存區和歷史記錄區。

    注意:因為 git reset 是直接刪除 commit 記錄,從而會影響到其他開發人員的分支,所以不要在公共分支(比如 develop)做這個操作。

  • git checkout 可以將 HEAD 移到一個新的分支,並更新工作目錄。因為可能會覆蓋本地的修改,所以執行這個指令之前,你需要 stash 或者 commit 暫存區和工作區的更改。

  • git revert 和 git reset 的目的是一樣的,但是做法不同,它會以建立新的 commit 的方式來撤銷 commit,這樣能保留之前的 commit 歷史,比較安全。另外,同樣因為可能會覆蓋本地的修改,所以執行這個指令之前,你需要 stash 或者 commit 暫存區和工作區的更改。

然後,從檔案層面來說:

  • git reset 只是把檔案從歷史記錄區拿到暫存區,不影響工作區的內容,而且不支援 --mixed、--soft 和 --hard。
  • git checkout 則是把檔案從歷史記錄拿到工作區,不影響暫存區的內容。
  • git revert 不支援檔案層面的操作。
回答關鍵點:
  • 對於 commit 層面和檔案層面,這三個指令本身功能差別很大。
  • git revert 不支援檔案層面的操作。
  • 不要在公共分支做 git reset 操作。

GitFlow 基本流程和你的理解

GitFlow 是由 Vincent Driessen 提出的一個 git操作流程標準。包含如下幾個關鍵分支:

名稱 說明
master 主分支
develop 主開發分支,包含確定即將釋出的程式碼
feature 新功能分支,一般一個新功能對應一個分支,對於功能的拆分需要比較合理,以避免一些後面不必要的程式碼衝突
release 釋出分支,釋出時候用的分支,一般測試時候發現的 bug 在這個分支進行修復
hotfix hotfix 分支,緊急修 bug 的時候用

GitFlow 的優勢有如下幾點:

  • 並行開發:GitFlow 可以很方便的實現並行開發:每個新功能都會建立一個新的 feature 分支,從而和已經完成的功能隔離開來,而且只有在新功能完成開發的情況下,其對應的 feature 分支才會合併到主開發分支上(也就是我們經常說的 develop 分支)。另外,如果你正在開發某個功能,同時又有一個新的功能需要開發,你只需要提交當前 feature 的程式碼,然後建立另外一個 feature 分支並完成新功能開發。然後再切回之前的 feature 分支即可繼續完成之前功能的開發。
  • 協作開發:GitFlow 還支援多人協同開發,因為每個 feature 分支上改動的程式碼都只是為了讓某個新的 feature 可以獨立執行。同時我們也很容易知道每個人都在幹啥。
  • 釋出階段:當一個新 feature 開發完成的時候,它會被合併到 develop 分支,這個分支主要用來暫時儲存那些還沒有釋出的內容,所以如果需要再開發新的 feature,我們只需要從 develop 分支建立新分支,即可包含所有已經完成的 feature
  • 支援緊急修復:GitFlow 還包含了 hotfix 分支。這種型別的分支是從某個已經發布的 tag 上建立出來並做一個緊急的修復,而且這個緊急修復隻影響這個已經發布的 tag,而不會影響到你正在開發的新 feature

然後就是 GitFlow 最經典的幾張流程圖,一定要理解:

feature 分支都是從 develop 分支建立,完成後再合併到 develop 分支上,等待發布。

當需要釋出時,我們從 develop 分支建立一個 release 分支

然後這個 release 分支會發布到測試環境進行測試,如果發現問題就在這個分支直接進行修復。在所有問題修復之前,我們會不停的重複釋出->測試->修復->重新發布->重新測試這個流程。

釋出結束後,這個 release 分支會合併到 developmaster 分支,從而保證不會有程式碼丟失。

master 分支只跟蹤已經發布的程式碼,合併到 master 上的 commit 只能來自 release 分支和 hotfix 分支。

hotfix 分支的作用是緊急修復一些 Bug。

它們都是從 master 分支上的某個 tag 建立,修復結束後再合併到 developmaster 分支上。

考察關鍵點
  • GitFlow 包含的分支型別和功能;
  • GitFlow 的優勢;
  • 對 GitFlow feature、release、hotfix 流程的理解。
回答關鍵點
  • GitFlow 的基本內容以及優勢;
  • 對於 feature 流程,都是從 develop 分支發起,然後通過 PR/MR 的方式合併回 develop 分支;
  • 對於 release 流程,則是要注意幾點:
    • 如果 release 分支上有 bug 需要修復,直接在 release 分支上完成;
    • release 分支上的 bug 修復要持續通過 PR/MR 的方式合併回 develop 分支;
    • 最後確認發版的時候才把 release 分支直接合併到 master 分支。
  • 對於 hotfix 流程,則是要注意幾點:
    • 從 master 分支發起;
    • 修復完要同時合併到 develop 和 master。

解釋下 PR 和 MR 的區別

PR 和 MR 的全稱分別是 pull request 和 merge request。解釋它們兩者的區別之前,我們需要先了解一下 Code Review,因為 PR 和 MR 的引入正是為了進行 Code Review。

Code Review 是指在開發過程中,對程式碼的系統性檢查。通常的目的是查詢系統缺陷,保證程式碼質量和提高開發者自身水平。 Code Review 是輕量級程式碼評審,相對於正式程式碼評審,輕量級程式碼評審所需要的各種成本要明顯低的多,如果流程正確,它可以起到更加積極的效果。

進行 Code Review 的原因:

  • 提高程式碼質量
  • 及早發現潛在缺陷與BUG,降低事故成本。
  • 促進團隊內部知識共享,提高團隊整體水平
  • 評審過程對於評審人員來說,也是一種思路重構的過程,幫助更多的人理解系統。

然後我們需要了解下 fork 和 branch,因為這是 PR 和 MR 各自所屬的協作流程。

fork 是 git 上的一個協作流程。通俗來說就是把別人的倉庫備份到自己倉庫,修修改改,然後再把修改的東西提交給對方稽核,對方同意後,就可以實現幫別人改程式碼的小目標了。fork 包含了兩個流程:

  • fork 並更新某個倉庫

  • 同步 fork

和 fork 不同,branch 並不涉及其他的倉庫,操作都在當前倉庫完成。

所以 PR 和 MR 的最大區別就在於此。

考察關鍵點:
  • Code review;
  • PR 和 MR 所屬流程的細節。
回答關鍵點:

回答這個問題的時候不要單單隻說它們的區別。而是要從 PR 和 MR 產生的原因,分析它們所屬的流程,然後再得出兩者的區別。

進階部分

進階部分請移步:iOS 面試指南

相關文章