轉(zhuǎn)載請(qǐng)表明本文地址碟狞,此文章介紹了 Xcode 9 使用 Git 進(jìn)行本地版本管理终畅,使用 Git 和 GitHub 進(jìn)行網(wǎng)絡(luò)版本管理戳這里 : 在Xcode9中使用git進(jìn)行版本管理(GitHub篇)
——正文開始
Xcode 9 重新定義了 Git 屈留,在資源導(dǎo)航欄中新增了一個(gè)管理 Git 的按鈕(左二)躺屁,使得其在管理版本方面更加強(qiáng)大和便捷裁赠,現(xiàn)在就讓我們來(lái)看一下這項(xiàng) Xcode 9 的新特性峰髓。
本文雖然長(zhǎng),但是絕大多數(shù)都是圖片完沪,內(nèi)容介紹詳細(xì)域庇,適合新手迅速上手 Git。
無(wú)論你是iOS個(gè)人開發(fā)還是團(tuán)隊(duì)協(xié)作覆积,你都應(yīng)該在你的工程中使用版本控制(Source control)听皿。版本控制的強(qiáng)大表現(xiàn)在它可以幫助你輕松的恢復(fù)到之前的老版本,亦或是低風(fēng)險(xiǎn)的在你的app中添加一個(gè)新的功能宽档,以及直觀地看到新增尉姨、刪減等操作所改變的代碼在工程中的位置。其中吗冤,Xcode自帶的Git工具就是最好的版本控制系統(tǒng)之一又厉。
在本文中九府,你將輕松的學(xué)習(xí)如何使用這項(xiàng)在 Xcode 9 中的強(qiáng)大功能。
——新建程序
與其討論Git的理論馋没,不如直接動(dòng)手操作一遍昔逗。你將新創(chuàng)建一個(gè)功能并且完成一些任務(wù),通過(guò)這些任務(wù)篷朵,你將很快掌握Git勾怒。
我們先建立一個(gè)單頁(yè)面工程
填入以下信息
按下Next,在接下來(lái)的畫面勾選“Create git repository on My Mac”声旺,
再點(diǎn)擊Create笔链,創(chuàng)建成功(如果項(xiàng)目已經(jīng)存在,則在Source Control->Create Git Repositories中創(chuàng)建)腮猖。
Xcode 將會(huì)創(chuàng)建一個(gè)Git倉(cāng)庫(kù)(在你的項(xiàng)目文件下可見(jiàn))鉴扫,所有的控制信息,數(shù)據(jù)都會(huì)存貯其內(nèi)澈缺,Git倉(cāng)庫(kù)會(huì)管理你的程序版本以及跟蹤代碼的改變坪创,可以將Git倉(cāng)庫(kù)看做一個(gè)所有版本的數(shù)據(jù)庫(kù)。
在你開展工作的時(shí)候姐赡,你將添加新文件莱预、改變代碼以及改變程序許多次。
在辛辛苦苦地碼了很多代碼之后项滑,你的程序進(jìn)入了“known good”狀態(tài)(就是說(shuō)當(dāng)前版本無(wú)BUG依沮,運(yùn)行良好),將這些改變存儲(chǔ)進(jìn)Git倉(cāng)庫(kù)將是一個(gè)好主意枪狂,存儲(chǔ)這些“known good”狀態(tài)下的代碼可以在未來(lái)需要的時(shí)候返回到這個(gè)版本危喉。
是不是每新建一個(gè)文件就要進(jìn)行版本存儲(chǔ)呢?完全不用州疾,那些沒(méi)有進(jìn)行版本存儲(chǔ)的文件依然被你的工程所持有辜限,直到你認(rèn)為需要存儲(chǔ)了再把他們一起存進(jìn)Git倉(cāng)庫(kù)。
讓我們來(lái)動(dòng)手試一下严蓖,打開 “Source Control navigator”(左上第二個(gè)按鈕)列粪,點(diǎn)擊展開列表,會(huì)看到Branches谈飒、Tags、Remotes三個(gè)文件,展開Branches态蒂,會(huì)看到一個(gè)分支master杭措,點(diǎn)擊master,你會(huì)看到一個(gè)系統(tǒng)初始化時(shí)自動(dòng)提交的版本(注釋為 Initial Commit)钾恢。
現(xiàn)在手素,為你的程序做點(diǎn)改變鸳址,打開AppDelegate.swift 并按照?qǐng)D示改變方法application(_:didFinishLaunchingWithOptions:)
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("Application did finish launching")
return true
}
在你完成之后,你會(huì)發(fā)現(xiàn)AppDelegate.swift文件右側(cè)會(huì)出現(xiàn)一個(gè)M
“M”意味著“改變了代碼但沒(méi)有提交Git”泉懦。
接下來(lái)稿黍,打開open ViewController.swift然后寫下以下代碼
@IBAction func buttonClicked(_ sender: UIButton) {
print("This is a Git tutorial")
}
現(xiàn)在打開 Main.storyboard 然后拖拉一個(gè)按鈕,改變他的title(隨你便)崩哩。
連接代碼和按鈕(如何連接就不寫了)巡球,并設(shè)置 Touch Up Inside 事件,設(shè)置點(diǎn)擊后會(huì)打印“This is a Git tutorial”信息邓嘹;
如果你確認(rèn)一下工程導(dǎo)航酣栈,你會(huì)發(fā)現(xiàn)現(xiàn)在會(huì)有3個(gè)“M”在你的文件右側(cè)。
Run一下你的程序保證沒(méi)出問(wèn)題汹押。然后點(diǎn)擊按鈕你會(huì)看到控制臺(tái)輸出了 “This is a Git tutorial”信息矿筝。
OK,現(xiàn)在你的程序就是 “known good” 狀態(tài)了,讓我們來(lái)提交一下棚贾。
——提交版本
提交文件很簡(jiǎn)單窖维,在菜單中選擇 Source Control\Commit 。
會(huì)出現(xiàn)一個(gè)窗口妙痹,和下面的圖片類似:
你可以看到铸史,屏幕被分成了兩塊,左邊的是目前尚未存儲(chǔ)的版本细诸,右邊是最近一次提交的版本沛贪。
屏幕(1)包含了那些尚未提交的改變,默認(rèn)情況下震贵,Xcode會(huì)認(rèn)為你希望將所有的改變提交Git利赋,如果你想將某處代碼取消提交,就取消(2)處的勾選猩系,你可以自己決定哪些改變會(huì)被提交媚送。
藍(lán)色高亮的區(qū)域就是你改變代碼所在的位置,任何改變寇甸,包括一個(gè)空格塘偎,也會(huì)被Git跟蹤并顯示藍(lán)色高亮。
你可以自己試試拿霉,打開 ViewController.swift, 增加幾行空行吟秩,你的結(jié)果就會(huì)如下所示:
如你所見(jiàn),Git跟蹤任何細(xì)節(jié)的改變绽淘。
在兩個(gè)窗口中間(2區(qū)域)涵防,所有的改變都由Xcode枚舉展示。
你可以取消勾選改變3沪铭,這樣他就不會(huì)被提交了壮池。
在你提交之前偏瓤,Xcode會(huì)要求你在底部輸入提交信息,這是為了幫助你更好的記憶版本信息。
現(xiàn)在按下 Commit 3 Files 椰憋。這樣你就完成了第一次提交厅克!你可以返回Source Control navigator 然后看見(jiàn)它。
以上操作已經(jīng)占據(jù)了你操作Git的90%橙依,很簡(jiǎn)單吧证舟?現(xiàn)在你已經(jīng)沒(méi)有理由不去使用Git了(哈哈哈)。
——新建分支
另一個(gè)Git版本管理的特色就在于可以允許你將改變提交到不同的分支之中票编。
等等拷姿,分支是啥卜朗???
分支是一種保存一系列Git提交的方式闰蚕。通過(guò)使用不同的分支比吭,你可以將不同功能分隔以減少破壞程序的風(fēng)險(xiǎn)逞怨。
無(wú)論你相不相信捌省,你已經(jīng)使用分支了。當(dāng)Git倉(cāng)庫(kù)被創(chuàng)建時(shí)互订,Git創(chuàng)建了一個(gè)名叫 “ master ” 的分支吱肌,至今為止你的工作都在這個(gè)分支中進(jìn)行。
工程的主要功能應(yīng)該提交至 “ master ” 分支仰禽,你可以使用其他分支來(lái)管理那些暫未有計(jì)劃發(fā)布的功能代碼氮墨,也可以用來(lái)管理永遠(yuǎn)不會(huì)發(fā)布的功能代碼。
舉個(gè)栗子吐葵,假設(shè)你要在你的app內(nèi)加入一個(gè)地圖功能规揪,但是他近期不會(huì)發(fā)布到產(chǎn)品上∥虑停看起來(lái)如下所示:
注意 "A" 代表文件 MapForItinerary.swift 還沒(méi)有加入Git倉(cāng)庫(kù)猛铅。
選擇 Source Control\Commit 提交。
如果你選擇了帶有 "A" 的文件凤藏,你會(huì)發(fā)現(xiàn)右側(cè)沒(méi)有任何東西奸忽,這是因?yàn)榇宋募奈催M(jìn)行存儲(chǔ)。
新增一個(gè)地圖功能可能對(duì)你的app來(lái)說(shuō)是一個(gè)很大的改變揖庄,所以這最好使用其他分支栗菜。這將降低地圖代碼所帶來(lái)的風(fēng)險(xiǎn)。
現(xiàn)在我們先取消提交蹄梢,去新建一個(gè)分支疙筹,用來(lái)存儲(chǔ)地圖功能的版本,打開 Source Control navigator ,在 “master” 上右擊腌歉,點(diǎn)選 “ Branch from “master ”。
Xcode 要求你輸入新分支的名稱齐苛。
我們將其命名為 map_feature 然后創(chuàng)建翘盖。
選擇新建的分支,你會(huì)發(fā)現(xiàn)原本在 “master” 分支右側(cè)的 current 的文字移到了 “map_feature” 分支上凹蜂。
現(xiàn)在我們?cè)俅翁峤烩裳保瑫?huì)提交至“map_feature” 分支上。
注意提交完成后所有的字母提示信息都消失了玛痊,這意味著你不再有任何沒(méi)有提交的改變汰瘫。
——返回上一個(gè)歷史版本
你坐在辦公室碼著代碼,構(gòu)建最新需求所要求的功能擂煞。你覺(jué)得有點(diǎn)累混弥,去拿了點(diǎn)零食坐在旁邊休息,這時(shí)你的眉頭一皺对省,忽然發(fā)現(xiàn)需求有一種更好的實(shí)現(xiàn)方式蝗拿,此時(shí)此刻,你可能希望能夠返回到上一個(gè)版本重構(gòu)新需求蒿涎。
Git 讓這個(gè)過(guò)程變得無(wú)比方便哀托。
我們來(lái)模擬一下這個(gè)過(guò)程,打開 Main.storyboard 并拖進(jìn)一個(gè)新的試圖控制器劳秋。
打開 MapForItinerary.swift 然后新加一個(gè) sayHello() 方法仓手。
func sayHello() {
print("Hello from MapForItinerary")
}
注意這時(shí)文件右側(cè)出現(xiàn)了 “M”,表示文件已被修改但尚未提交玻淑。
此刻嗽冒,你可以選擇性的取消一些文件的改變。選擇 Main.storyboard 然后在菜單中選擇 Source Control\Discard Changes in “Main.storyboard”…
Xcode 會(huì)向你確認(rèn)時(shí)候返回狀態(tài)至上次存儲(chǔ)此文件時(shí)岁忘。
點(diǎn)擊 Discard Changes 辛慰,你會(huì)發(fā)現(xiàn)剛剛創(chuàng)建的視圖控制器不見(jiàn)了。這項(xiàng)功能在你新增了一連串的代碼卻BUG頻出的時(shí)候十分管用干像,你可以隨時(shí)返回到一個(gè) “known good” 狀態(tài)帅腌。
除了丟棄整體實(shí)體文件的改變之外,你還選擇性的丟棄文件內(nèi)的一些局部改變麻汰。
MapForItinerary.swift 依然有個(gè) “M” ,選擇 Select Source Control\Commit… 速客,點(diǎn)擊改變區(qū)域的下拉箭頭選擇 Discard Change:
哇!你成功去掉了這個(gè)改變五鲫,這里再也沒(méi)有什么東西可以提交了溺职,點(diǎn)擊 Cancel 關(guān)閉提交窗口。
既然你嘗試了兩種丟棄改變的方式,你可能會(huì)好奇這兩種方式有什么區(qū)別浪耘。
盡管兩種方式的結(jié)果是一樣的乱灵,但他們還是存在很大的不同:
在提交界面丟棄掉改變并不會(huì)刪除代碼,代碼依然存在于工程之內(nèi)七冲。
另一種方式在不提交代碼的同時(shí)痛倚,還會(huì)在工程內(nèi)刪除這些導(dǎo)致改變的代碼。
——比較多個(gè)歷史版本
丟棄改變確實(shí)是一種好的回溯方式澜躺,但是蝉稳,在某些情況下,這種方式有一定的局限性掘鄙。
Git 允許你為你的工程中所擁有的多個(gè)改變保存修正方式耘戚。這些全部由 Git倉(cāng)庫(kù) 管理。
如果你選擇拋棄某個(gè)文件的所有改變(discard changes)操漠,Git會(huì)恢復(fù)此文件最后一個(gè)提交的版本收津,這正是這種方式(discard changes)的局限所在。
隨著時(shí)間流逝颅夺,你的Git倉(cāng)庫(kù)將會(huì)保存大量的歷史版本朋截。假設(shè)你希望某個(gè)特定的文件恢復(fù)到第一個(gè)或者第二個(gè)版本, discarding change就無(wú)法做到了吧黄。不用氣餒部服,Xcode 和 Git 自有辦法。
選擇 ViewController.swift拗慨,然后在菜單選擇 View\Version Editor\Show Comparison View廓八。或者選擇右上角的第三個(gè)按鈕赵抢。
現(xiàn)在你的界面將會(huì)分割成兩個(gè)窗口
這種模式可以使你能夠比較當(dāng)前版本與之前任意版本之間的變化剧蹂,整體界面看起來(lái)就像提交界面一般。默認(rèn)情況下烦却,你當(dāng)前的資源文件會(huì)顯示在左側(cè)屏幕宠叼,最后一次保存的資源文件會(huì)出現(xiàn)在右側(cè)屏幕。(Git 將管理的這些版本稱呼為HEAD)
點(diǎn)擊右下角底部的按鈕其爵,就可以自由選擇之前存儲(chǔ)的版本冒冬,從而實(shí)現(xiàn)當(dāng)前文件與之前存儲(chǔ)的版本文件之間的對(duì)比。
如下圖所示摩渺,你可以選擇之前的HEAD简烤,你可以看到之前的各個(gè)版本信息。
現(xiàn)在摇幻,只需要點(diǎn)擊一下就可以在右側(cè)屏幕顯示出不同版本的文件了横侦,真簡(jiǎn)單~~
一旦你恢復(fù)到了一個(gè)之前的版本挥萌,你就需要將這個(gè)“新”版本提交Git,現(xiàn)在就試試吧~
如何選擇一個(gè)你想要的之前版本枉侧?你可以使用 Source Control navigator 就像文章之前操作的那樣引瀑。還有另外一個(gè)方法,長(zhǎng)按版本編輯按鈕然后選擇 Log榨馁。你也可以在菜單選擇View\Version Editor\Show Log 伤疙。
Xcode 會(huì)列出含有改變(相對(duì)當(dāng)前文件)的提交版本。注意列表中的提交信息都帶有一個(gè)提交標(biāo)識(shí)(commit identifier)辆影。
這些標(biāo)識(shí)和你的列表中的歷史修訂是一一對(duì)應(yīng)的。
你可以點(diǎn)擊 Show modified files 去展開更多的細(xì)節(jié)黍特。
另外一個(gè)令人稱奇的功能叫做 Blame View 蛙讥。此視圖展示了提交版本中哪些行發(fā)生了改變。
切換到 Blame View 灭衷,長(zhǎng)按版本編輯按鈕然后選擇 Blame次慢。你也可以從在菜單中選擇 View\Version Editor\Show Blame View。
你的屏幕看起來(lái)如下圖所示:
為了看到更多改變的細(xì)節(jié)翔曲,你可以按下日期旁邊的 info 按鈕迫像。彈出來(lái)的氣泡會(huì)展示此處改變是由誰(shuí)提交的,何時(shí)提交的以及提交的時(shí)候提交時(shí)攥寫的描述信息瞳遍。右下角有一個(gè) Open in Comparison 的按鈕闻妓,點(diǎn)擊會(huì)切換到 Comparison 界面,然后將此版本的文件置于右側(cè)屏幕掠械。
——合并分支
你在之前的文章中學(xué)到了Git允許你使用多條分支進(jìn)行版本管理由缆。你也知道了使用多分支的好處。接下來(lái)猾蒂,如果你想將其他的分支功能加入到當(dāng)前版本呢均唉?簡(jiǎn)單!你可以將你的其他分支融入到你的主分支中肚菠。假設(shè)你的 map_feature 分支還沒(méi)完成但是你的老板讓你在主界面上加一個(gè) label 舔箭,為了滿足需求,你將離開 map_feature 分支然后從 “known good” 狀態(tài)的 master 分支中創(chuàng)建一個(gè)新分支蚊逢。
切換到 Source Control navigator 层扶,右擊 master branch 然后點(diǎn)選
Branch from “master”….
就將新的分支命名為 new_label 吧 ,點(diǎn)擊創(chuàng)建
注意时捌,你依然在 map_feature 分支上工作怒医,右擊 new_label 分支然后點(diǎn)擊 Checkout ,現(xiàn)在你的提交工作都會(huì)在new_label 分支下進(jìn)行奢讨。
Xcode 會(huì)向你確認(rèn)是否切換分支稚叹,這里我們點(diǎn)擊 Checkout焰薄。
通過(guò)檢查 Source Control navigator 下的 (current) 標(biāo)簽,你可以確認(rèn)現(xiàn)在的提交都會(huì)提交至 new_label 分支中了扒袖。
現(xiàn)在讓我們加入老板要求的 label 塞茅。切換回標(biāo)準(zhǔn)編輯界面,打開Main.storyboard 季率,然后在主界面上拖一個(gè) UILabel野瘦。
在保證沒(méi)有什么問(wèn)題之后,我們需要將改變提交至 Git倉(cāng)庫(kù)飒泻,別忘了下方的攥寫提交信息”薰猓現(xiàn)在切換到 master 分支(checkout)運(yùn)行一遍,你會(huì)發(fā)現(xiàn)泞遗,剛剛加的 UILabel 不見(jiàn)了惰许,現(xiàn)在我們要將這個(gè)新的分支融入到 master 分支中。
在 Source Control navigator 下右擊 new_label 分支點(diǎn)擊 Merge “new_label” into “master”….
Xcode 會(huì)向你確認(rèn)行動(dòng)史辙,點(diǎn)擊 Merge
融合界面會(huì)出現(xiàn)汹买,你可以在此為融合“加工”。目標(biāo)分支會(huì)出現(xiàn)在屏幕右側(cè)聊倔,你的當(dāng)前文件會(huì)出現(xiàn)在左側(cè)晦毙。使用底部的按鈕可以控制出現(xiàn)沖突的時(shí)候融合的選擇(左邊,右邊耙蔑,還是兩邊都要)见妒。對(duì)于本例來(lái)說(shuō),Xcode 默認(rèn)設(shè)定為 correct one (沒(méi)有出現(xiàn)沖突)甸陌。
最終徐鹤,點(diǎn)擊 Merge 按鈕來(lái)開始融合過(guò)程。如果沒(méi)有毛病邀层,你就會(huì)在Main.storyboard 上看到改變(新增了一個(gè) UILabel )返敬,現(xiàn)在你的改變已經(jīng)融合進(jìn) master 分支了。使用這些方法來(lái)檢閱你的提交歷史寥院,你將學(xué)會(huì)如何查實(shí)歷史版本都有哪些改變劲赠。
——忽略配置文件
回到你第一次提交 Git 的時(shí)候,除了你寫的資源文件外秸谢,Git 也跟蹤了一些由 Xcode 管理的文件凛澎,這些文件是工程能夠順利開展的必備條件,你需要這些文件重構(gòu)你的 app 或者和其他人進(jìn)行合作估蹄。
盡管它們很有用塑煎,我們卻不一定將他們提交到 Git 進(jìn)行管理,因?yàn)槊看胃淖?Xcode 都會(huì)重新創(chuàng)建它們臭蚁。事實(shí)上最铁,保存它們會(huì)令 Git 做一些無(wú)用功讯赏,甚至讓我們?cè)诓檎覛v史版本的改變時(shí)更加麻煩。
Git 提供了一個(gè)機(jī)制去忽略這些文件:這類文件后綴名為 .gitignore 冷尉。因?yàn)樗麄兊拿Q導(dǎo)致了 macOS 將這類文件視作一個(gè)隱藏文件漱挎,一般在你的工程中或者 Finder 中看不到。不用擔(dān)心雀哨,Git 會(huì)找到他們并且使用他們磕谅。
與其自己動(dòng)手寫一個(gè) .gitignore 文件,不如去 gitignore.io.下載一個(gè)雾棺。
首先膊夹,打開終端然后輸入以下命令,你只需要做一次便可以一勞永逸了(復(fù)制注意去掉$)捌浩。
$ git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi'
現(xiàn)在割疾,對(duì)于任何使用 Git 的工程,輸入以下命令行(如果是OC項(xiàng)目嘉栓,將下面代碼的swift 替換為 Objective-C )
cd <directory where your project is stored>
git ignore swift,macos >.gitignore
git add .gitignore
git commit -m "Add .gitignore file"
這會(huì)為 macOS 上的 Swift code 下載一個(gè) .gitignore 配置文件,你的終端可能會(huì)看起來(lái)如下所示
你已經(jīng)將一個(gè) .gitignore 文件加入了你的 Git 倉(cāng)庫(kù)拓诸,從現(xiàn)在開始侵佃,他會(huì)過(guò)濾掉那些不必要的文件。
注意:趁早加入一個(gè) .gitignore 文件是一個(gè)好主意奠支。
——結(jié)束語(yǔ)
使用 Git 和 GitHub 進(jìn)行網(wǎng)絡(luò)版本管理戳這里 : 在Xcode9中使用git進(jìn)行版本管理(GitHub篇)
本文由作者翻譯馋辈,原文地址“https://www.raywenderlich.com/153084/use-git-source-control-xcode-9”,內(nèi)容較原文有少許刪減倍谜。
有什么翻譯不對(duì)的地方和不理解的地方可以在回復(fù)中提出迈螟。