編譯:伯樂在線/聽風(fēng)
如有好文章投稿,請點擊 → 這里了解詳情
本文旨在使用通俗易懂的文字,講解版本控制背后的理論,以便你能對程序員們?nèi)绾喂ぷ饔袀€全局概念。本文不涉及代碼,不用下載啥東西,循序漸進(jìn),不關(guān)注繁復(fù)細(xì)節(jié),只有文字和一些不怎么漂亮的手繪涂鴉。
學(xué)習(xí)任何東西都能在網(wǎng)絡(luò)上找到如此之多的指導(dǎo)教程,這一直令我驚訝不已。Git 和 Github 也不例外,網(wǎng)絡(luò)上有大量優(yōu)秀資源,這些資源要么只對其中一個,要么兼顧二者引導(dǎo)你開始學(xué)習(xí)。以下是我特別喜歡的一些資源:
Treehouse – 寫給設(shè)計師的 Git 入門介紹
Roger Dudler – Git 簡易教程
Pluralsight – Github:初學(xué)者指南
然而,我發(fā)現(xiàn)這些教程總是跳過許多理論知識,直接解釋如何通過命令行或 Github 桌面應(yīng)用程序使用 Git 。坦白說,如果你只是想知道你的開發(fā)團隊談?wù)摰牡降资鞘裁?,這些指導(dǎo)教程也綽綽有余了。如上所述,我的目標(biāo)是對版本控制的整體概念進(jìn)行簡明扼要地講解,同時希望能讓你了解到版本控制是如此酷。
Image credit: weebletheringskite, WordPress
版本控制(Version control):學(xué)習(xí)它,愛上它,享受它。顧名思義,版本控制系統(tǒng)是任何能讓你了解到一個文件的歷史,以及它的發(fā)展過程的系統(tǒng)。之前作為平面設(shè)計師時,我常常會遇到這種文件:
看起來眼熟?盡管上述系統(tǒng)不是一個好用的系統(tǒng) ,但它確實是一個版本控制系統(tǒng)。更復(fù)雜點的例子就像,Google 文檔的 “修訂歷史”或 Photoshop 的“歷史”工具。
Git 是一種專為處理文本文件而設(shè)計的版本控制系統(tǒng)。因為,歸根到底,這就是代碼的本質(zhì):一堆堆以某種方式聯(lián)合在一起的文本文件。Git 是一個可安裝應(yīng)用,它允許你對你自己所做的更改進(jìn)行注釋,用以創(chuàng)建易于導(dǎo)航的系統(tǒng)歷史。
(附: “Git” 也是工程師取的名字,我們對市場部同仁感到抱歉)
那么, Git 做了什么,是簡單地保存文件所做不到的呢?從根本上講,文件保存就是一個簡化的版本控制系統(tǒng),但坦率地說,它并不是一個好用的系統(tǒng),因為它只能前進(jìn)。當(dāng)然,你也許會爭論“撤消”按鈕可以讓你的文件回滾到以前的狀態(tài)。但我們都清楚,“撤消”按鈕有其局限性,最明顯示的是,在關(guān)閉文件時,文件的過去也隨之丟失。
另外,文件保存是非常個人化的。它不能夠顯示整個系統(tǒng)的歷史,只能夠顯示該文件的。針對這一點,你可能會想,“嗯,我不是一個工程師,我不需要為系統(tǒng)煩惱”。我愿意花些時間來解釋一下,很多事情你認(rèn)為不是“系統(tǒng)”,而實際上它們就是。
以 Sally為例,她是一個正在寫下一個大冒險奇幻小說系列的作家。Sally 已經(jīng)寫完該系列小說中的第一本,并把它傳給了她的編輯。此外,由于她才華出眾,在等待編輯的反饋的同時,她還寫了第二本書的前三章。每本書都建立了獨立的 World 文件。
在某個快樂的日子,Sally 等來了她的編輯關(guān)于第一本書的反饋。他擔(dān)心年輕的讀者不想讀一系列專寫獸人故事的書,希望她在這個故事中引入一些精靈。關(guān)于這點,Sally 嘆了口氣,但很快意識到,她的精靈新角色將帶來始料未及的沖突和曲折的情節(jié)。然后,她做了以下事情:
在第一本書中加入新角色,并修改故事情節(jié)。
完成第一本書之后,對第二本書的故事情節(jié),進(jìn)行必要的修改。
所有的這些修改,導(dǎo)致她需要引入某個地理位置到第一本書中,而不是第二本書。
重新編輯第一本書,讓它包含新的地理位置。
終于,她推開了她的鍵盤,確信已經(jīng)把精靈融入到了她的奇幻世界之中。
你瞧,Sally 實際上在處理一個系統(tǒng)。她的兩本書互相影響。角色、地理位置和故事情節(jié)在兩本書中流動交織。然而,遺憾的是,一個月后,她的文件系統(tǒng)里什么都沒有了。Word 的 “文檔歷史”工具,或她曾經(jīng)粘貼在顯示屏邊緣用于記錄修改過程的便簽紙,將把所有的變化過程都揉合在一起。
這正是Git 大放光芒之處。如果 Sally 一直結(jié)合 Git 使用Word,她就能對所有這些相關(guān)的變化做一個關(guān)于“將精靈引入到系列”的簡潔小結(jié)。她可以看到所有穿插在頁、章節(jié)、文件,以及每本書中的修改記錄,讓她真正地了解引入精靈對她的奇幻系列產(chǎn)生的影響。這個“簡潔的小結(jié)”就是我們在 Git 領(lǐng)域中所講的提交(commit)。
回顧一下。 Git 是一個軟件,它允許你通過提交對一個系統(tǒng)(或一組)文件的歷史進(jìn)行注釋。這些提交便是在給定時間點對系統(tǒng)做出的差異“快照”。
那么,如果我是Sally,我的提交歷史看起來是這樣子的:
到目前為止,一切都還不錯。但是,如果 Sally 同時用到兩臺電腦工作,將會發(fā)生什么呢?問得好。這時,就該用到 Github了。注意,不要和 Git 混淆了。Github 獲取 Git 中的提交歷史,并將其存儲在互聯(lián)網(wǎng)上,因此你可以從任一一臺電腦訪問它。你在本機(例如:你當(dāng)前正在使用的電腦)推送(pushing)提交到 Github,然后,從另一臺新的或不同的電腦上拉?。?/strong>pulling)這些提交。
讓我們假設(shè)上圖為 Sally 的工作流程。她在家里的臺式電腦(左邊,橘黃色的)上開啟她一天的工作。接下來,她完成了幾個章節(jié)的寫作,又做了一些編輯工作,等等。整個過程中,她對工作總共進(jìn)行了三次策略性的“快照”(Git 提交)。
下午,Sally 常常喜歡帶著她的筆記本電腦(上圖中的右側(cè),藍(lán)色的)去咖啡館寫作。今天也不例外。因此,在關(guān)閉家里的臺式電腦之前,她需要確認(rèn)當(dāng)前的Git 提交歷史已推送(push)到了在線Github。一旦被上傳到 Github,這些提交記錄就被存儲在遠(yuǎn)程倉庫(remote repository)中。
我們先來分析一下幾個計算機術(shù)語:遠(yuǎn)程(remote)僅僅意味著聯(lián)網(wǎng)(與“本地”的意思相反,和之前我們理解到的意思一樣的,代表當(dāng)前正在使用的電腦)。而倉庫(repository,經(jīng)常簡寫為“repo”),就是一個具備 Git 超級權(quán)限的文件夾。
因此,Github 就是讓你把工作(通過Git提交進(jìn)行注解)存儲在了一個指定的在線文件夾(repo)。明白了吧?簡單。
午餐之后,在當(dāng)?shù)氐囊患铱Х瑞^中,Sally 拿出了她的筆記本電腦。很明顯,她想接著家里的工作進(jìn)度繼續(xù)。因些,她從 Github 倉庫上獲取到最新進(jìn)度的工作?!皬?Github 上獲取她的工作”,這一過程就叫拉?。?/strong>pulling)。再看一下上面這幅圖片,你將看到 Sally 拉取了之前她在家時進(jìn)行的三個提交。
現(xiàn)在,在她的筆記本電腦上,Sally 有整個系統(tǒng)(包含她的幻想系列的所有文本文件)的最新的完整副本,并能夠基于上次的進(jìn)度,繼續(xù)工作。她寫了更多的章節(jié),對工作進(jìn)行了兩次以上的策略“快照”(提交)。最后,Sally 把這些提交推送(push)到 Github 上,結(jié)束了這一天的工作。這樣第二天上午的時候,在家里的臺式電腦上就可以取得這些最新進(jìn)度的工作。
好吧,這一切都能說得通。但是, Sally再如何酷,整個項目也只有她一人而已。工程團隊要如何確保他們的工作不會重疊?
簡而言之,創(chuàng)建分支。將你的 Git 提交歷史想像成一棵樹。樹的主干就是我們談到的主分支。為了讓團隊成員避免彼此牽扯,他們在獨立于他人的隔離區(qū)(在一個功能分支)進(jìn)行工作,然而最終,每個人的工作成果都會被提交到主代碼庫 (主分支)。
現(xiàn)在,回到 Sally 的例子。她加入了奇幻作家協(xié)會,在這里每個人都與他人合作完成這本書——《奇幻系列生物辭典》。這本辭典更像一本教材,由多個作者共同完成:Sally、Tom 和 Adam。
讓我們來看看《奇幻系列生物辭典》項目的在線 Github 倉庫,現(xiàn)在的情況是:
如上圖所示,樹的類比完全適用于奇幻作家協(xié)會在這個項目上的合作情況,倉庫歷史沿主分支向上移動。常規(guī)工作流始于每個作者為完成一個工作任務(wù)(例如編寫章節(jié)內(nèi)容,或排版章節(jié))而在主分支上創(chuàng)建分支。只有當(dāng)更改得到其他合作作家的批準(zhǔn)時,分支才會被合并到主分支上(請謹(jǐn)記,主分支上的內(nèi)容,才是最終要發(fā)布的內(nèi)容)。
當(dāng)一個分支的內(nèi)容合并(merged)到主分支時,意味著該分支的內(nèi)容會覆蓋主分支上的。因此,現(xiàn)有內(nèi)容的任何更改都將會替代之前的。當(dāng)然,任何新添加的內(nèi)容也會添加到主分支。實際上,當(dāng)分支合并到主分支時,該分支的提交歷史被添加到主分支提交歷史的頂部。
然而,你可能正在思考:人們在本機的工作和之后才推送到 Github 的工作變更是如何連接到一起的呢?
關(guān)于這個問題,重點在于:你在 Github 的遠(yuǎn)程倉庫是你本機工作項目的一個鏡像。這意味著,你在自己的電腦里存儲了該項目(例如:一個已設(shè)置可進(jìn)行 Git 提交的文件夾)的本地 Git 倉庫。在這個本地的 Git 倉庫(再次,這是一個特定術(shù)語,指你的電腦里某個啟用了 Git 功能的文件夾)中,你擁有與該項目相關(guān)的所有文件,在本文的例子中,即《奇幻系列生物辭典》。
它的工作原理很像 Dropbox :你在不同的設(shè)備(你的家庭電腦、辦公室電腦,等等)上創(chuàng)建本地文件夾,進(jìn)行工作并更新這些文件。最后,這些操作被同步到網(wǎng)絡(luò)上。然而,我們知道,Git/Github 工作流還包含了一些額外的步驟。首先,你必須有意識地對某一時刻的工作執(zhí)行“快照”(即執(zhí)行一次提交)。然后,你必須特意地推送這些提交(push) 到 Github。只有這樣,你的工作才被同步到網(wǎng)絡(luò)上的位置(Github 版本庫)。
既然如此,為什么不自動化該工作流呢?為什么不讓它像 Dropbox一樣,當(dāng)你更新本地文件時,同時自動更新 Github 上的文件?有很多理由讓我們不這么做。最主要的理由是——bugs 。同出版界一樣,軟件工程中也不是所有寫過的東西都要保留。有時,你希望實驗一下你的想法,如果實驗失敗,你希望有一種簡單的方式能讓工作快速回滾到之前的正確狀態(tài)上。這也是為什么我們提倡這個經(jīng)驗法則,即在你試圖用不同的方法編輯或?qū)嶒炛?,先對?dāng)前你希望保留的修改進(jìn)行提交。頻繁地提交小塊工作有益無害,事實上,許多工程師為自己能做到這一點而感到自豪。
現(xiàn)在,回到《奇幻系列生物辭典》。由于 Sally 對獸族有較深的了解,她被挑選為寫獸族章節(jié)。但她不想在沒有經(jīng)過其它合作人員允許的情況下去修改這本書,于是,她創(chuàng)建了一個本地分支,并在該分支上進(jìn)行寫作和提交。然后,她將本地分支推送到 Github。像往常一樣,Github 的遠(yuǎn)程倉庫是本地庫的一個鏡像,最新進(jìn)展顯示 Sally 已創(chuàng)建了一個包含部分提交的分支(如下圖所示)。
隨著她對本章節(jié)的持續(xù)寫作,Sally 進(jìn)行了更多的提交,并將它們推送到 Github 的在線鏡像分支。終于,她準(zhǔn)備請 Tom 和 Adam 一起對她的工作進(jìn)行評審。因此,她在 Github 上發(fā)布了一個 Pull Request(發(fā)布請求),這是一個 Github 功能,允許她解釋該分支相對于主分支做了哪些修改。Github 還提供了一個簡易平臺,合作人員可以在該平臺上針對分支的修改內(nèi)容進(jìn)行討論,并要求 Sally 在分支合并到主分支之前對一些有異議的內(nèi)容進(jìn)行修改。
在對部分內(nèi)容請求修改后,如上圖所示,Tom 和 Adam 對 Sally 的分支內(nèi)容很滿意,并決定將她的工作成果合并到 Github 的主分支上。此時,他們所要做的就是將 Sally 之前獨立提交的內(nèi)容,添加到主分支的提交歷史頂部:
此時,Sally可以切換(或“check out”)到本地計算機上的主分支,并將先前在功能分支(獸人章節(jié)分支)中的獨立提交拉取下來?,F(xiàn)在她又要在新的主分支上重新開始了:以該主分支為基礎(chǔ)為她的下一步工作創(chuàng)建一個新的本地分支,幫助湯姆編輯有關(guān)妖精的章節(jié)。因此,這一過程又將重復(fù):
創(chuàng)建本地分支
在本地分支上編輯修改,然后提交
推送提交(Push)到 Github
創(chuàng)建發(fā)布請求(Pull Request),說明該分支包含了哪些更改
合并(Merge)分支內(nèi)容到主分支
將主分支上的最新提交拉取(pull)到本地
重復(fù)上述步驟
正如你所看到的,這是一個非常流暢的工作流,完美地結(jié)合了獨立工作與團隊協(xié)作。你本機的 Git 提供了一個絕妙的方法,即通過由你自己控制和策劃的豐富的歷史提交,來創(chuàng)建你工作的各種版本。Github 是一個非常棒的在線版本控制工具,不僅存儲和提供了清晰的可視化歷史記錄,而且還能進(jìn)行協(xié)同工作和質(zhì)量控制。
總而言之,我希望我已經(jīng)說服你去嘗試使用 Git 和 Github 進(jìn)行任何項目。沒有理由只有工程師能從這個很棒的工具中受益。畢竟,我們也想看到更多有關(guān)獸人的故事。
非常感謝 Common Craft 對本文的涂鴉和解釋風(fēng)格的啟發(fā)。還要感謝這個視頻《 saving me from the horror of having to explain Twitter to my mum 》。
Version Control(版本控制): 任何一個能夠讓你了解文件的歷史,以及該文件的發(fā)展進(jìn)程的系統(tǒng)。
Git:一個版本控制程序,通過對變更進(jìn)行注釋,以創(chuàng)建一個易于遍歷的系統(tǒng)歷史。
Commit(提交):在指定時間點對系統(tǒng)差異進(jìn)行的注釋 “快照”。
Local(本地):指任意時刻工作時正在使用的電腦。
Remote(遠(yuǎn)程): 指某個聯(lián)網(wǎng)的位置。
Repository (倉庫,簡稱 repo):配置了Git超級權(quán)限的特定文件夾,包含了你的項目或系統(tǒng)相關(guān)的所有文件。
Github:獲取本地提交歷史記錄,并進(jìn)行遠(yuǎn)程存儲,以便你可以從任何計算機訪問這些記錄。
Pushing(推送):取得本地Git提交(以及相關(guān)的所有工作),然后將其上傳到在線Github。
Pulling(拉?。?/strong>:從在線的Github上獲取最新的提交記錄,然后合并到本地電腦上。
Master (branch):主分支,提交歷史 “樹”的 “樹干”,包含所有已審核的內(nèi)容/代碼。
Feature branch(功能分支/特性分支):一個基于主分支的獨立的位置,在再次并入到主分支之前,你可以在這里安全地寫工作中的新任務(wù)。
Pull Request(發(fā)布請求):一個 Github 工具,允許用戶輕松地查看某功能分支的更改 (the difference或 “diff”),同時允許用戶在該分支合并到主分支之前對其進(jìn)行討論和調(diào)整。
Merging(合并):該操作指獲取功能分支的提交,加入到主分支提交歷史的頂部。
Checking out(切換):該操作指從一個分支切換到另一個分支。
看完本文有收獲?請分享給更多人
關(guān)注「伯樂在線」,看更多精選 IT 職場文章
聯(lián)系客服