標籤:

技術培訓 | Git,你真的會用么?

1. 開始

大家下午好,歡迎大家參加本次微信技術分享活動。我叫譚賀賀,目前在Coding 主要負責 WebIDE 與 Codeinsight 的開發。我今天帶來的主要內容是 git 的原理與應用。談起 git,大家的第一印象無非是和 svn 一樣的版本控制系統,但其實他們有著非常大的不同,至少 svn 沒有像git一樣這麼多的玩法。下面我舉幾個例子,簡略的說一下。

1.1 搭建博客

阮一峰將寫博客的人分成三個階段

  • 使用免費空間,比如 CSDN、博客園。
  • 發現免費空間限制太多,於是自己購買域名和空間,搭建獨立博客。
  • 獨立博客管理太麻煩,最好在保留控制權的前提下,讓別人來管,自己負責寫文章。

其實第三種階段指的就是使用 Pages 服務。很多公司比如 Coding、Github 等代碼託管平台都推出了 Pages 服務,可以用來搭建個人博客。Pages 服務不需要複雜的配置,就可以完成博客的搭建。

在使用 Pages 的過程中,通過使用標記語言(Markdown)完成博客的編寫,推送到伺服器上,就可以看到新發布的博客了。不需要管理伺服器,降低了搭建博客的門檻,同時又保持了用戶對博客的高度定製權。

1.2 寫書

很多牛人喜歡寫博客,博客寫多了,然後彙集起來就出了本書。比如 Matrix67《思考的樂趣》、阮一峰《如何變得有思想》就是這樣的例子。

其實出書距離我們也並不遙遠,為什麼?因為有 gitbook 這樣的服務。

對於 git + Pages 服務的用戶,gitbook 很容易上手,因為使用 gitbook 就是使用 git 與 Markdown。你完全可以將你 Markdown 的博客複製,彙集起來,形成一本書籍。內容的排版 gitbook 會幫你做,我們只負責內容就可以了。

編寫好內容,我們就能立刻獲得 html、pdf、epub、mobi 四個版本的電子書。這是 html 版的預覽:

在 gitbook 上有 explore 頻道,上面列出了所有公開的書籍(當然也可以直接搜索)。

實際上,除了寫書,還可以連同其他人一起進行外文資料的翻譯。

比如說《The Swift Programming Language》中文版,將英文版分成幾個部分,然後在開源項目中由參與者認領翻譯,每個人貢獻一份自己的力量,這樣以非常快的響應速度完成了跟隨官方文檔更新的操作。

如果你喜歡的一門語言或者技術中文資料缺乏,大家可以發起這樣的活動,完成外文資料的翻譯。

1.3 人才招聘

人才招聘這一塊,至今還並沒有形成一定的規模。但仍舊有很多的公司選擇在代碼託管平台上(比如 Coding、Github)上尋找中意的開發者。有一些開發者看準了這一塊,專門開發了這樣的網站,比如 githuber.cn、github-awards.com。

拿 githuber 舉例,該網站主要提供兩個功能,第一個是星榜,說白了就是將將所有用戶按照語言分類,然後根據星標數進行排序。

我們可以很容易的看到排行榜上前幾位的用戶,他們的開源項目,這在一定程度上能代表這門語言的發展趨勢。比如我對java比較感興趣,然後我看了一下前十名,發現大部分都是 Android 開發,由此可見android開發的火爆程度。

當然你也可以看到你的排名,會讓你有打怪升級的快感。

第二個功能是搜索,輸入篩選條件,搜搜程序員!

1.4 WebIDE

Coding WebIDE 是 Coding 自主研發的在線集成開發環境 (IDE)。只要你的項目在代碼託管平台存放,就可以導入到 WebIDE。之後就可以在線開發。

WebIDE 還提供 Web Terminal 功能,用戶可以遠程操作Docker容器,自由安裝喜歡的軟體包、方便折騰。

看起來是不是還挺好玩的,如果想把這些都玩轉,git 是肯定要好好學的。接下來,我們就看一下 git 的基本原理。

2. Git 原理

我們可以現在想一下,如果我們自己來設計,應該怎麼設計。

傳統的設計方案我們可以簡單的分成兩塊:工作目錄,遠程倉庫。

但是作為一個目標明確的分散式版本控制系統,首先要做的就是添加一個本地倉庫。

接著我們選擇在工作目錄與遠程倉庫中間加一個緩衝區域,叫做暫存區。

加入暫存區的原因有以下幾點:

  1. 為了能夠實現部分提交
  2. 為了不在工作區創建狀態文件、會污染工作區。
  3. 暫存區記錄文件的修改時間等信息,提高文件比較的效率。

至此就我們本地而言有三個重要的區域:工作區、暫存區、本地倉庫。

接下來我們想一下本地倉庫是如何存放項目歷史版本。

2.1 快照

這是項目的三個版本,版本1中有兩個文件A和B,然後修改了A,變成了A1,形成了版本2,接著又修改了B變為B1,形成了版本3。

如果我們把項目的每個版本都保存到本地倉庫,需要保存至少6個文件,而實際上,只有4個不同的文件,A、A1、B、B1。為了節省存儲的空間,我們要像一個方法將同樣的文件只需要保存一份。這就引入了SHA-1演算法。

可以使用git命令計算文件的 SHA-1 值。

echo test content | git hash-object --stdind670460b4b4aece5915caf5c68d12f560a9fe3e4

SHA-1演算法將文件中的內容通過計算生成一個 40 位的hash值。

SHA-1演算法的特點:

  • 由文件內容計算出的hash值
  • hash值相同,文件內容相同

對於上圖中的內容,無論我們執行多少次,都會得到相同的結果。因此,文件的SHA-1值是可以作為文件的唯一 id 。同時,它還有一個額外的功能,校驗文件完整性。

有了 SHA-1 的幫助,我們可以對項目版本的存儲方式做一下調整。

2.1.1 資料庫中存儲的數據內容

實際上,現在就與git實際存儲的結構一致了。我們可以預覽一下實際存儲在 .git 下的文件。

我們可以看到,在 objects 目錄下,存放了很多文件,他們都使用 SHA-1 的前兩位創建了文件夾,剩下的38位為文件名。我們先稱呼這些文件為 obj 文件。

對於這麼多的 obj 文件,就保存了我們代碼提交的所有記錄。對於這些 obj 文件,其實分為四種類型,分別是 blob、tree、commit、tag。接下來,我們分別來看一下。

  1. blob

    首先 A、A1、B、B1 就是 blob 類型的 obj。

    blob: 用來存放項目文件的內容,但是不包括文件的路徑、名字、格式等其它描述信息。項目的任意文件的任意版本都是以blob的形式存放的。
  2. tree

    tree 用來表示目錄。我們知道項目就是一個目錄,目錄中有文件、有子目錄。因此 tree 中有 blob、子tree,且都是使用 SHA-1值引用的。這是與目錄對應的。從頂層的 tree 縱覽整個樹狀的結構,葉子結點就是blob,表示文件的內容,非葉子結點表示項目的目錄,頂層的 tree 對象就代表了當前項目的快照。
  3. commit

    commit: 表示一次提交,有parent欄位,用來引用父提交。指向了一個頂層 tree,表示了項目的快照,還有一些其它的信息,比如上一個提交,committer、author、message 等信息。

2.2 暫存區

暫存區是一個文件,路徑為: .git/index

它是一個二進位文件,但是我們可以使用命令來查看其中的內容。

這裡我們關注第二列和第四列就可以了,第四列是文件名,第二列指的是文件的blob。這個blob存放了文件暫存時的內容。

第二列就是SHA-1 hash值,相當於內容的外鍵,指向了實際存儲文件內容的blob。第三列是文件的衝突狀態,這個後面會講,第四列是文件的路徑名。

我們操作暫存區的場景是這樣的,每當編輯好一個或幾個文件後,把它加入到暫存區,然後接著修改其他文件,改好後放入暫存區,循環反覆。直到修改完畢,最後使用 commit 命令,將暫存區的內容永久保存到本地倉庫。

這個過程其實就是構建項目快照的過程,當我們提交時,git 會使用暫存區的這些信息生成tree對象,也就是項目快照,永久保存到資料庫中。因此也可以說暫存區是用來構建項目快照的區域。

2.3 文件狀態

有了工作區、暫存區、本地倉庫,就可以來定義文件的狀態了。

文件的狀態可以分為兩類。一類是暫存區與本地倉庫比較得出的狀態,另一類是工作區與暫存區比較得出的狀態。為什麼要分成兩類的願意也很簡單,因為第一類狀態在提交時,會直接寫入本地倉庫。而第二種則不會。一個文件可以同時擁有兩種狀態。

比如一個文件可能既有上面的 modified 狀態,又有下面 modified 狀態,但其實他們表示了不同的狀態,git 會使用綠色和紅色把這兩中 modified 狀態區分開來。

2.4 分支

接下來,看一個很重要的概念,分支。

分支的目的是讓我們可以並行的進行開發。比如我們當前正在開發功能,但是需要修復一個緊急bug,我們不可能在這個項目正在修改的狀態下修復 bug,因為這樣會引入更多的bug。

有了分支的概念,我們就可以新建一個分支,修復 bug,使新功能與 bug 修復同步進行。

分支的實現其實很簡單,我們可以先看一下 .git/HEAD 文件,它保存了當前的分支。

cat .git/HEAD=>ref: refs/heads/master

其實這個 ref 表示的就是一個分支,它也是一個文件,我們可以繼續看一下這個文件的內容:

cat .git/refs/heads/master=> 2b388d2c1c20998b6233ff47596b0c87ed3ed8f8

可以看到分支存儲了一個 object,我們可以使用 cat-file 命令繼續查看該 object 的內容。

git cat-file -p 2b388d2c1c20998b6233ff47596b0c87ed3ed8f8=> tree 15f880be0567a8844291459f90e9d0004743c8d9=> parent 3d885a272478d0080f6d22018480b2e83ec2c591=> author Hehe Tan <xiayule148@gmail.com> 1460971725 +0800=> committer Hehe Tan <xiayule148@gmail.com> 1460971725 +0800=> => add branch paramter for rebase

從上面的內容,我們知道了分支指向了一次提交。為什麼分支指向一個提交的原因,其實也是git中的分支為什麼這麼輕量的答案。

因為分支就是指向了一個 commit 的指針,當我們提交新的commit,這個分支的指向只需要跟著更新就可以了,而創建分支僅僅是創建一個指針。

3. 高層命令

在 git 中分為兩種類型的命令,一種是完成底層工作的工具集,稱為底層命令,另一種是對用戶更友好的高層命令。一條高層命令,往往是由多條底層命令組成的。

不知道的人可能一聽高層感覺很厲害的樣子,其實就是指的是那些我們最常使用的git命令。

3.1 Add & Commit

add 和 commit 應該可以說是我們使用頻率最高的高層命令了。

touch README.mdgit add README.mdgit commit -m "add readme」

touch 指的是創建一個文件,代表了我們對項目文件內容的修改,add 操作是將修改保存到暫存區,commit 是將暫存區的內容永久保存到本地倉庫。

每當將修改的文件加入到暫存區,git 都會根據文件的內容計算出 SHA-1,並將內容轉換成 blob,寫入資料庫。然後使用 SHA-1 值更新該列表中的文件項。

在暫存區的文件列表中,每一個文件名,都會對應一個SHA-1值,用於指向文件的實際內容。最後提交的那一刻,git會將這個列表信息轉換為項目的快照,也就是 tree 對象。寫入資料庫,並再構建一個commit對象,寫入資料庫。然後更新分支指向。

3.2 Conflicts & Merge & Rebase

3.2.1 Conflicts

git 中的分支十分輕量,因此我們在使用git的時候會頻繁的用到分支。不可不免的需要將新創建的分支合併。

在 git 中合併分支有兩種選擇:merge 和 rebase。但是,無論哪一種,都有可能產生衝突。因此我們先來看一下衝突的產生。

圖上的情況,並不是移動分支指針就能解決問題的,它需要一種合併策略。首先,我們需要明確的是誰和誰的合併,是 2,3 與 4,5,6的合併嗎?說到分支,我們總會聯想到線,就會認為是線的合併。其實不是的,真實合併的是 3 和 6。因為每一次提交都包含了項目完整的快照,即合併只是 tree 與 tree 的合併。

我們可以先想一個簡單的演算法。用來比較3和6。但是我們還需要一個比較的標準,如果只是3和6比較,那麼3與6相比,添加了一個文件,也可以說成是6與3比刪除了一個文件,這無法確切表示當前的衝突狀態。因此我們選取他們的兩個分支的分歧點(merge base)作為參考點,進行比較。

比較時,相對於 merge base(提交1)進行比較。

首先把1、3、6中所有的文件做一個列表,然後依次遍歷這個列表中的文件。現在我們拿列表中的一個文件進行舉例,把在提交1、3、6中的該文件分別稱為版本1、版本3、版本6。

  1. 版本1、版本3、版本6的 SHA-1 值完全相同,這種情況表明沒有衝突
  2. 版本3或6至少一個與版本1狀態相同(指的是SHA-1值相同或都不存在),這種情況可以自動合併。比如1中存在一個文件,3對該文件進行修改,而6中刪除了這個文件,則以6為準就可以了
  3. 版本3或版本6都與版本1的狀態不同,情況複雜一些,自動合併策略很難生效,需要手動解決。我們來看一下這種狀態的定義。

衝突狀態定義:

  • 1 and 3: DELETED_BY_THEM;
  • 1 and 6: DELETED_BY_US;
  • 3 and 6: BOTH_ADDED;
  • 1 and 3 and 6: BOTH_MODIFIED

我們拿第一種情況舉例,文件有兩種狀態 1 和 3,1 表示該文件存在於 commit 1(也就是MERGE_BASE),3 表示該文件在 commit 3 (master 分支)中被修改了,沒有 6,也就是該文件在 commit 6(feature 分支)被刪除了,總結來說這種狀態就是 DELETED_BY_THEM。

可以再看一下第四種情況,文件有三種狀態 1、3、6,1 表示 commit 1(MERGE_BASE)中存在,3 表示 commit 3(master 分支)進行了修改,6 表示(feature 分支)也進行了修改,總結來說就是 BOTH_MODIFIED(雙方修改)。

遇到不可自動合併衝突時,git會將這些狀態寫入到暫存區。與我們討論不同的是,git使用1,2,3標記文件,1表示文件的base版本,2表示當前的分支的版本,3表示要合併分支的版本。

3.2.2 Merge

在解決完衝突後,我們可以將修改的內容提交為一個新的提交。這就是 merge。

merge 之後仍可以做出新的提交。

可以看到 merge 是一種不修改分支歷史提交記錄的方式,這也是我們常用的方式。但是這種方式在某些情況下使用起來不太方便,比如當我們創建了 PR、MR 或者將修改補丁發送給管理者,管理者在合併操作中產生了衝突,還需要去解決衝突,這無疑增加了他人的負擔。

使用 rebase 可以解決這種問題。

3.2.3 Rebase

假設我們的分支結構如下:

rebase 會把從 merge base 以來的所有提交,以補丁的形式一個一個重新達到目標分支上。這使得目標分支合併該分支的時候會直接 fast forward,即不會產生任何衝突。提交歷史是一條線,這對強迫症患者可謂是一大福音。

如果我們想要看 rebase 實際上做了什麼,有一個方法,那就是用「慢鏡頭」來看rebase的整個操作過程。rebase 提供了互動式選項(參數 -i),我們可以針對每一個patch,選擇你要進行的操作。

通過這個互動式選項,我們可以「單步調試」rebase操作。

經過測試,其實 rebase 主要在 .git/rebase-merge 下生成了兩個文件,分別為 git-rebase-todo 和 done 文件,這兩個文件的作用光看名字就可以看得出來。git-rebase-todo 存放了 rebase 將要操作的 commit。而 done 存放正在操作或已經操作完畢的 commit。比如我們這裡,git-rebase-todo 存放了 4、5、6,三個提交。

首先 git 將 SHA-1 為 4 的 commit 放入 done。表示正在操作 4,然後將 4 以補丁的形式打到 3 上,形成了新的提交 4』。這一步是可能產生衝突的,如果有衝突,需要解決完衝突之後才能繼續操作。

接著講 SHA-1 為 5 的提交放入 done 文件,然後將 5 以補丁的形式打到 4』 上,形成 5』。

再接著將 SHA-1 為 6 的提交放入 done 文件,然後將 6 以補丁的形式打到 5』 上,形成 6』。最後移動分支指針,使其指向最新的提交 6』 上。這就完成了 rebase 的操作。

我們看一下真實的 rebase 文件。

pick e0f56d9 update gitignorepick e370289 add a# Commands:# p, pick = use commit# r, reword = use commit, but edit the commit message# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit# f, fixup = like "squash", but discard this commits log message# x, exec = run command (the rest of the line) using shell# d, drop = remove commit

該文件一共有三列,第一列表示要進行的操作,所有可以進行的操作,在下面注釋里都列了出來,比如 pick 表示使用該提交,reword 表示使用該提交,但修改其提交的 message,edit 表示使用該提交,但是要對該提交進行一些修改,其它的就不一一說了。

而 done 文件的形式如下,和 git-rebase-todo 是一樣的:

pick e0f56d9 update gitignorepick e370289 add a

從剛才的圖中,我們就可以看到 rebase 的一個缺點,那就是修改了分支的歷史提交。如果已經將分支推送到了遠程倉庫,會導致無法將修改後的分支推送上去,必須使用 -f 參數(force)強行推送。

所以使用 rebase 最好不要在公共分支上進行操作。

3.3 Checkout、Revert、Reset

3.3.1 Checkout

對於 checkout,我們一般不會陌生。因為使用它的頻率非常高,經常用來切換分支、或者切換到某一次提交。

這裡我們以切換分支為例,從 git 的工作區、暫存區、本地倉庫分別來看 checkout 所做的事情。Checkout 前的狀態如下:

首先 checkout 找到目標提交(commit),目標提交中的快照也就是 tree 對象就是我們要檢出的項目版本。

checkout 首先根據tree生成暫存區的內容,再根據 tree 與其包含的 blob 轉換成我們的項目文件。然後修改 HEAD 的指向,表示切換分支。

可以看到 checkout 並沒有修改提交的歷史記錄。只是將對應版本的項目內容提取出來。

3.3.2 Revert

如果我們想要用一個用一個反向提交恢復項目的某個版本,那就需要 revert 來協助我們完成了。什麼是反向提交呢,就是舊版本添加了的內容,要在新版本中刪除,舊版本中刪除了的內容,要在新版本中添加。這在分支已經推送到遠程倉庫的情境下非常有用。

Revert 之前:

revert 也不會修改歷史提交記錄,實際的操作相當於是檢出目標提交的項目快照到工作區與暫存區,然後用一個新的提交完成版本的「回退」。

Revert 之後:

3.3.3 Reset

reset 操作與 revert 很像,用來在當前分支進行版本的「回退」,不同的是,reset 是會修改歷史提交記錄的。

reset 常用的選項有三個,分別是 —soft, —mixed, —hard。他們的作用域依次增大。

我們分別來看。

soft 會僅僅修改分支指向。而不修改工作區與暫存區的內容,我們可以接著做一次提交,形成一個新的 commit。這在我們撤銷臨時提交的場景下顯得比較有用。

使用 reset --soft 前:

使用 reset --soft 後:

mixed 比 soft 的作用域多了一個 暫存區。實際上 mixed 選項與 soft 只差了一個 add 操作。

使用 reset --mixed 前:

使用 reset --mixed 後:

hard 會比 mixed作用域又多了一個工作區。

使用 reset --hard 前:

使用 reset --hard 後:

hard 選項會導致工作區內容「丟失」。

在使用 hard 選項時,一定要確保知道自己在做什麼,不要在迷糊的時候使用這條選項。如果真的誤操作了,也不要慌,因為只要 git 一般不會主動刪除本地倉庫中的內容,根據你丟失的情況,可以進行找回,比如在丟失後可以使用 git reset --hard ORIG_HEAD 立即恢復,或者使用 reflog 命令查看之前分支的引用。

3.4 Stash

有時,我們在一個分支上做了一些工作,修改了很多代碼,而這時需要切換到另一個分支幹點別的事。但又不想將只做了一半的工作提交。在曾經這樣做過,將當前的修改做一次提交,message 填寫 half of work,然後切換另一個分支去做工作,完成工作後,切換回來使用 reset —soft 或者是 commit amend。

git 為了幫我們解決這種需求,提供了 stash 命令。

stash 將工作區與暫存區中的內容做一個提交,保存起來,然後使用reset hard選項恢復工作區與暫存區內容。我們可以隨時使用 stash apply 將修改應用回來。

stash 實現思路將我們的修改提交到本地倉庫,使用特殊的分支指針(.git/refs/stash)引用該提交,然後在恢復的時候,將該提交恢復即可。我們可以更進一步,看看 stash 做的提交是什麼樣的結構。

如圖所示,如果我們提供了 —include-untracked 選項,git 會將 untracked 文件做一個提交,但是該提交是一個遊離的狀態,接著將暫存區的內容做一個提交。最後將工作區的修改做一個提交,並以untracked 的提交、暫存區 的提交、基礎提交為父提交。

搞這麼複雜,是為了提供更靈活地選項,我們可以選擇性的恢復其中的內容。比如恢復 stash 時,可以選擇是否重建 index,即與 stash 操作時完全一致的狀態。

3.5 Bisect

最後要講到一個曾經把我從「火坑」中救出來的功能。

項目發布到線上的項目出現了bug,而經過排查,卻找不到問 bug 的源頭。我們還有一種方法,那就是先找到上一次好的版本,從上一次到本次之間的所有提交依次嘗試,一一排查。直到找到出現問題的那一次提交,然後分析 bug 原因。

git 為我們想到了這樣的場景,同樣是剛才的思路,但是使用二分法進行查找。這就是 bisect 命令。

使用該命令很簡單,

git bisect startgit bisect bad HEADgit bisect good v4.1

git 會計算中間的一個提交,然後我們進行測試。

根據測試結果,使用 git bisect good or bad 進行標記,git 會自動切換到下一個提交。不斷的重複這個步驟,直到找到最初引入 bug 的那一次提交。

我們知道二分法的效率是很高的,2的10次方就已經1024了,因此我們測試一般最多是10次,再多就是11次、12次。其實這就要求我們優化測試的方法,使得簡單的操作就能使 bug 重現。如果重新的操作非常簡單,簡單到我們可以使用腳本就能測試,那就更輕鬆了,可以使用 git bisect run ./test.sh,一步到位。

如果某一個提交代碼跑不起來,可以使用 git bisect skip 跳過當前提交或者使用 visualize 在 git 給出的列表中手動指定一個提交進行測試。

Q&A

1、處理衝突時,Rebase 和 Merge 各有啥優缺點? by 李任充

首先,rebase、merge 並不是用來處理衝突的。rebase、merge操作會產生衝突。但這兩個命令產生的衝突的方式不一樣的。

我們剛才講了,merge 是將兩次提交的 tree 合併,然後作為新的提交。因此 merge 只會產生一次衝突。

rebase 是將差異的提交,以補丁的形式,一個一個打到目標分支上。

某一次提交出現問題,解決完後,後面的提交仍可能產生衝突。因此與 merge 相比,rebase 可能會產生多次衝突。

2、從原理上看,Git 屬於 P2P 網路應用嗎?支持最優路徑和備份功能嗎? by 何文甲

這是一個比較新穎的觀點。

想了想,似乎是的。因為 git 允許我們從個人倉中克隆、推送、拉取代碼。

但實際上,git 並不鼓勵我們這樣操作,因為這些操作可能會破壞他人的倉庫,還不易跟蹤項目的開發進度,導致項目管理混亂。為此 git 提供了引入了遠程倉庫的概念。

有了遠程倉庫,我們並不需要從他人電腦上克隆項目,而是搭建一個伺服器,用來作為遠程倉庫,該倉庫用於彙集項目成員的提交,同時所有項目成員從該遠程倉庫中拉取代碼。

另外,問題中提到的最優路徑,應該是傳輸協議需要考慮的問題,而非 git 本身。

git 使用傳輸數據的協議有四種。1. 本地協議 2. HTTP 協議 3. SSH 4. Git 協議。感興趣的可以了解下。

3、團隊成員之前用的 SVN、VSS 等,現在要求用 Git,但總是有人不去做,特別是用慣了其他源代碼管理工具的成員,年輕的反而好點。有些成員即使用,也是用 Windows 下那個 Gui 界面去搞,還成天抱怨如何繁鎖、如何不直觀、命令記不住等。請問對於用慣了其他工具的團隊,如何更好的轉到 Git ? by 李奎

git 與 svn 基於完全不同的理念,從 svn 轉變為 git 會非常的不適應。這是正常的。

我們可以從簡單的開始。大多數人使用 git,涉及到的命令不會很多, add、commit、checkout、pull、push,這幾個命令就夠了。

遇到問題,通過這些命令解決不了問題的時候,學習新的能解決問題的命令即可。

比如我們講到的 bisect,就是我在試遍所有的方法都解決不了一個項目的 bug 時才學的。

git 中的很多命令,都對對應了使用場景,到了該場景下,發現 git 命令能夠更優雅的解決這些問題,我們自然會主動去學。

另外,年輕程序員,比較能接受新鮮事物,可以通過一些有趣的方式來學習 git,比如我們談到的搭建博客、或者直接通過「打遊戲」(http://www.jianshu.com/p/482b32716bbe) 等方式學習。

4、如何自定義 Hook 來觸發本地事件,來實現自動化的運行或者部署呢? by ?? Tata _M ?? ?

這個實現起來比較簡單,可以參考我們公司的一篇博客 blog.coding.net/blog/Gi

5、Git 團隊協作工作流有哪些?小團隊開發適合用哪種工作流 Git Flow Or Fork ? by maowei

關於工作流的一些知識,向你推薦公司的一篇博客,希望能幫到你 blog.coding.net/blog/gi

6、能否通過一些問題場景來對 Git 命令進行講解。如有了問題才有了解決問題的方法,以這樣的方式講出來,Git 不再是單純的命令,而是與實際問題聯繫緊密的。 by 243845305

很遺憾,我們選用了原理視角對 git 進行講解,希望的是能把 git 的核心概念講出來,為聽眾學習其它命令打下基礎。如果以後還有機會,會考慮使用場景對 git 講解,thks。

7、想請問一個問題,小型的開發團隊,開發公司自用的小系統,用 Svn 好還是 Git 好?兩者優缺點是什麼? by珏墉

我們是完全推薦 git 的。我列舉幾點 git 的優點。

git 比 svn 多了本地倉庫的概念,因此無論是檢出代碼、提交代碼、切換分支等操作都不需要網路的支持,這意味著可以進行離線開發。

git 中的分支較 svn 輕量的多,可以瞬間完成分支的切換。

git 不會輕易刪除加入到本地倉庫的內容,這在很多時候可能會成為挽救項目的最後一道曙光。

Coding、Github等託管平台都是以對 git 的支持程度來作為賣點的。即使他們也兼容 svn,但使用 git 會獲得更好的體驗。

8、請問如何加強本地搭建的 Git 伺服器的安全性的同時能夠不減弱 Git 的好可用性和方便性。 by 開心綠茶

首先,並不推薦你自己搭建git伺服器,建議使用 Coding、Github 這類更專業代碼託管服務商。

當然,如果你真的需要自己搭建,也是可以的,推薦使用開源的gitlab等。


推薦閱讀:

在華為的十年
離子通道對藥物研發有哪些意義?
孫亞飛的live——如何做好化學工業研發項目
請問豌豆莢的研發團隊有沒有infrastructure組或團隊,承擔怎樣的開發角色?
研發驅動產業北京遠不如上海,「創新熱土」徒有虛名?

TAG:Git | 研发 |