在應(yīng)用程序開(kāi)發(fā)過(guò)程中话原,很重要的一部分工作就是如何進(jìn)行源碼的版本控制蕾管。當(dāng)代碼出現(xiàn)問(wèn)題時(shí)螃诅,我們就需要將代碼恢復(fù)到原先正常的版本啡氢。如果是多個(gè)人共同開(kāi)發(fā)一個(gè)項(xiàng)目,那么代碼的控制就會(huì)非常復(fù)雜术裸。幸運(yùn)的是倘是,開(kāi)發(fā)者不需要自己控制這些,因?yàn)橛袑iT的軟件來(lái)負(fù)責(zé)袭艺,叫做版本控制系統(tǒng)搀崭。
版本控制系統(tǒng),或者說(shuō)修改控制系統(tǒng)猾编,實(shí)際上是一種檢測(cè)源文件的改變并將其保存留作以后參考使用的機(jī)制(軟件)瘤睹。此外,它還能記錄其他有用信息答倡,比如是哪個(gè)開(kāi)發(fā)者修改了代碼轰传,何時(shí)修改的,修改了哪一部分苇羡,以及其他歷史信息绸吸。版本控制系統(tǒng)可以比較不同版本代碼的不同鼻弧,有必要時(shí)能恢復(fù)整個(gè)項(xiàng)目到以前的版本,追蹤有害代碼從而減少產(chǎn)品的錯(cuò)誤锦茁。
通過(guò)版本控制系統(tǒng)攘轩,開(kāi)發(fā)者可以在一個(gè)項(xiàng)目的不同分支上工作,當(dāng)項(xiàng)目的各個(gè)部分開(kāi)發(fā)完備時(shí)码俩,將它們放到一起形成最終的版本度帮,這個(gè)過(guò)程被稱為合并。事實(shí)上稿存,這種做法再團(tuán)隊(duì)和軟件公司中相當(dāng)常見(jiàn):每個(gè)人負(fù)責(zé)項(xiàng)目的一部分笨篷,最終所有部分被整合到一起形成最終產(chǎn)品。
對(duì)于個(gè)人開(kāi)發(fā)者來(lái)說(shuō)瓣履,版本控制系統(tǒng)并不是必需的率翅,但是我們?nèi)匀粡?qiáng)烈推薦開(kāi)發(fā)者使用它,因?yàn)樗梢允勾a方便的在有錯(cuò)誤的版本和可以工作的版本之間轉(zhuǎn)換袖迎。事實(shí)上冕臭,很多開(kāi)發(fā)者從來(lái)不使用類似的工具,他們會(huì)在項(xiàng)目添加新的功能時(shí)手動(dòng)保存原先的項(xiàng)目燕锥。這其實(shí)是一個(gè)很不好的習(xí)慣辜贵,因?yàn)榘姹究刂栖浖梢愿酶咝У赝瓿蛇@項(xiàng)任務(wù)。
Git是一個(gè)常見(jiàn)的版本控制系統(tǒng)归形,它最開(kāi)始是由Liunx之父Linus Torvalds開(kāi)發(fā)的托慨,Git使用虛擬目錄,又稱為repositories暇榴,來(lái)管理一切事物厚棵。Git可以通過(guò)命令行調(diào)用,也有專門為它設(shè)計(jì)的桌面應(yīng)用軟件跺撼。如果Git對(duì)你來(lái)說(shuō)很陌生窟感,我建議你在網(wǎng)上查看一些它的相關(guān)信息。關(guān)于Git更深層次的內(nèi)容都不在本文的討論范圍之內(nèi)歉井。
從Xcode5開(kāi)始引入了使用git的一些新特性柿祈。它將git的各項(xiàng)功能整合到一個(gè)菜單中,并提供子菜單來(lái)進(jìn)行軟件合并的控制哩至。在接下來(lái)的閱讀中你會(huì)發(fā)現(xiàn)躏嚎,使用git來(lái)進(jìn)行版本控制相當(dāng)?shù)暮?jiǎn)單快捷。
我們接下來(lái)的任務(wù)就是學(xué)習(xí)如何在Xcode中使用git菩貌,以及Xcode是如何整合Git的各項(xiàng)功能卢佣。如果你覺(jué)得對(duì)這些很陌生,我建議你先上網(wǎng)搜索一下相關(guān)的內(nèi)容箭阶。在接下來(lái)的教程中虚茶,我會(huì)假定你已經(jīng)了解了版本控制系統(tǒng)和git是什么戈鲁,并將注意力集中在Xcode如何管理它上。
GIT Demo概述(GIT Demo Overview)
與其他教程中的demo app不同嘹叫,這次我們不會(huì)去實(shí)現(xiàn)一個(gè)應(yīng)用來(lái)演示某一項(xiàng)iOS SDK特性婆殿,最終我們也不會(huì)產(chǎn)生一個(gè)示例產(chǎn)品。實(shí)際上罩扇,我們會(huì)新建一個(gè)demo工程婆芦,寫幾行代碼,然后利用這個(gè)工程來(lái)演示Xcode提供的版本管理功能喂饥。換句話說(shuō)消约,我們會(huì)集中注意里于IDE上,而不是iOS本身员帮。
我建議你跟著我一起一步一步實(shí)現(xiàn)這個(gè)實(shí)例項(xiàng)目或粮,在相應(yīng)的地方手動(dòng)添加代碼,不用擔(dān)心集侯,代碼量不是很多被啼。跟著教程的步驟棠枉,我們將執(zhí)行多種重復(fù)的版本控制相關(guān)的操作,并且我們必須實(shí)時(shí)看到結(jié)果泡挺。如果我只是提供了一個(gè)具備所有操作的的應(yīng)用辈讶,那么你無(wú)法體會(huì)到這些改變。
好了娄猫,廢話不多說(shuō)了贱除,讓我們仔細(xì)看看使用Xcode進(jìn)行版本控制的要點(diǎn)吧。
創(chuàng)建一個(gè)Git源(Creating a Git repository)
每次在Xcode中創(chuàng)建新工程的時(shí)候媳溺,都會(huì)提示開(kāi)發(fā)者是否將項(xiàng)目作為一個(gè)本地的git源月幌。在創(chuàng)建工程的最后一步Xcode會(huì)有一個(gè)復(fù)選框,如果選擇了它悬蔽,git源就會(huì)被添加到工程目錄中扯躺。通常這個(gè)選項(xiàng)會(huì)被忽視,或是被認(rèn)為是Xcode的另外一個(gè)沒(méi)用的功能蝎困,尤其是從未用過(guò)git的開(kāi)發(fā)者录语,或是編程新手。
打開(kāi)Xcode禾乘,創(chuàng)建一個(gè)新的工程澎埠。選擇iOS區(qū)的“Application”,在應(yīng)用模板頁(yè)選擇“Single View Application”始藕。
選擇下一步蒲稳,在項(xiàng)目名中輸入GitDemo氮趋,確保下面的Devices菜單選擇iPhone,無(wú)需iPad或者universal app江耀。
點(diǎn)擊下一步凭峡,也就是最后一個(gè)步驟,在這里先選擇一個(gè)要保持工程的目錄决记,然后在窗口底部選上Create git repository on (My Mac ):
默認(rèn)情況下摧冀,這個(gè)選項(xiàng)是被選上的,如果你不想使用git系宫,你可以取消它索昂,但是我不建議這么做。本教程中扩借,你需要將它勾選上椒惨,然后點(diǎn)擊創(chuàng)建按鈕。
創(chuàng)建完項(xiàng)目之后潮罪,打開(kāi)Finder康谆,找到項(xiàng)目存儲(chǔ)的目錄,在目錄中嫉到,有一個(gè).git的子目錄沃暗,時(shí)Xcode為存儲(chǔ)git源相關(guān)數(shù)據(jù)自動(dòng)創(chuàng)建的。
如果你看不到.git目錄何恶,你需要讓隱藏的文件可見(jiàn)孽锥。具體做法就是打開(kāi)一個(gè)Terminal窗口,輸入以下命令:
對(duì)于OS X Mavericks 10.9:
defaults?write?com.apple.finder?AppleShowAllFiles?TRUE
對(duì)于以前的OS X版本细层,
efaults?write?com.apple.Finder?AppleShowAllFiles?TRUE
為了重啟Finder應(yīng)用惜辑,輸入
killall?Finder
這就是本項(xiàng)目在本地git源保存的位置。實(shí)際上疫赎,如果你選上了相應(yīng)的選項(xiàng)盛撑,這個(gè)目錄就會(huì)被創(chuàng)建。相應(yīng)地捧搞,在你創(chuàng)建新應(yīng)用時(shí)抵卫,.git子目錄也會(huì)一同被創(chuàng)建。
顯然使用Xcode創(chuàng)建一個(gè)git源毫不費(fèi)力实牡,然而陌僵,如果你在項(xiàng)目創(chuàng)建時(shí)未創(chuàng)建git源,之后又想加上這個(gè)功能怎么辦呢创坞?好吧碗短,其實(shí)你可以在任何時(shí)候?yàn)槟愕捻?xiàng)目創(chuàng)建源,但是不是使用Xcode题涨。盡管這種情況很少發(fā)生偎谁,我還是會(huì)告訴你該怎么做总滩。
如果你愿意的話,你可以直接跳到本教程的下一部分巡雨。我建議你接著讀下去闰渔,因?yàn)榻酉聛?lái)這些信息還是很有用的。
在進(jìn)行演示前铐望,你需要首先通過(guò)Xcode下載Command Line Tools冈涧,因?yàn)槲覀円赥erminal下操作,并且需要一些額外的工具正蛙。如果你還沒(méi)有下載督弓,那就去Xcode>Preferences…菜單,選擇Download選項(xiàng)卡乒验,展開(kāi)Components區(qū)愚隧,點(diǎn)擊Commond Line Tools右邊下載按鈕。下載完成后锻全,一個(gè)對(duì)勾符號(hào)會(huì)取代下載按鈕狂塘。
現(xiàn)在,為這個(gè)例子再創(chuàng)建一個(gè)工程鳄厌,完事后可以刪了它荞胡。在創(chuàng)建時(shí)取消那個(gè)創(chuàng)建git源的選項(xiàng)。這次我們不想讓Xcode為我們準(zhǔn)備一個(gè)源部翘。把這個(gè)工程命名為NoGitExample硝训,保存到桌面,然后你可以跟我接下來(lái)輸入的命令一樣新思。
一切準(zhǔn)備妥當(dāng)后,打開(kāi)Terminal窗口(如果你之前打開(kāi)了一個(gè)赘风,那就先關(guān)掉它再重啟夹囚,從而使我們安裝的命令行工具生效)。下面切換到新項(xiàng)目的目錄:
cd?/Users/YOUR-USERNAME/Desktop/NoGitExample
別忘了在上邊命令中設(shè)置Mac的用戶名邀窃,接下來(lái)荸哟,輸入:
git?init
這會(huì)初始化一個(gè)空的源,如果你在Finder里面查看或是輸入ls命令瞬捕,你會(huì)看到.git子目錄已經(jīng)被創(chuàng)建鞍历,很好,接下來(lái)輸入:
git?add?.
這樣肪虎,當(dāng)前目錄所有的內(nèi)容就被添加到源里面去了劣砍,最后,輸入以下命令:
git?commit?-m?'Initial?commit'
接下來(lái)會(huì)出現(xiàn)一個(gè)本地git源所執(zhí)行的改變列表扇救,如下圖所示:
現(xiàn)在git源就建好了刑枝,但是如果你回到Xcode香嗓,打開(kāi)Source Control菜單,你會(huì)發(fā)現(xiàn)一切仍然是被禁用装畅。
這是因?yàn)楫?dāng)我們使用命令行工具創(chuàng)建git源時(shí)靠娱,Xcode并未被通知,下面點(diǎn)擊Xcode>Quit Xcode掠兄,然后重新啟動(dòng)它像云,在NoGitExample項(xiàng)目中,如果你再次打開(kāi)Source Control菜單蚂夕,你會(huì)發(fā)現(xiàn)所有的選項(xiàng)已經(jīng)被使能了迅诬,就像一開(kāi)始勾選上創(chuàng)建git源一樣。
現(xiàn)在這個(gè)項(xiàng)目的使命已經(jīng)結(jié)束双抽,你可以在桌面上刪除它百框。
現(xiàn)在你知道如何為你所有的項(xiàng)目添加git源了,即使你在創(chuàng)建時(shí)沒(méi)有添加牍汹,你也可以在以后任何時(shí)候?yàn)樗謩?dòng)添加源铐维。
提交更改(Committing Changes)
提交更改指的是儲(chǔ)存一個(gè)包含所有更改的新版本。一般來(lái)說(shuō)慎菲,當(dāng)我們做了一些有意義的工作嫁蛇,并且項(xiàng)目處于某一個(gè)穩(wěn)定狀態(tài)時(shí),就可以提交一次更改露该。然而具體什么時(shí)候提交更改并沒(méi)有硬性的規(guī)定睬棚。我的建議是:從上次提交更改之后,如果你怕花費(fèi)大量時(shí)間和精力做的新工作被誤刪很難恢復(fù)解幼,你就需要提交更改了抑党。
默認(rèn)情況下,Xcode在項(xiàng)目創(chuàng)建之初會(huì)提交一次更改撵摆,這是為了保存項(xiàng)目初始狀態(tài)底靠。這項(xiàng)工作會(huì)在后臺(tái)完成,不會(huì)打擾你或者要求你進(jìn)行確認(rèn)特铝。如果你在項(xiàng)目創(chuàng)建時(shí)沒(méi)有添加git源暑中,但是之后你手動(dòng)添加了,你可以通過(guò)我們先前使用過(guò)的命令來(lái)進(jìn)行提交:git commit -m ‘Initial commit’
實(shí)際上鲫剿,你如果去Source Control>History…菜單鳄逾,你就會(huì)看到初次提交更改的記錄,以后每次提交更改灵莲,都會(huì)在這里有所記錄雕凹。
接下來(lái)讓我們小幅修改一下我們的工程,在ViewController.m文件中,添加以下屬性聲明:
@interface?ViewController?()
@property?(nonatomic)?int?sum;
@end
接下來(lái)请琳,像下面這樣修改viewDidLoad方法:
12-?(void)didReceiveMemoryWarning
{
[superdidReceiveMemoryWarning];
//?Dispose?of?any?resources?that?can?be?recreated.
int?a?=?5;
int?b?=?10;
self.sum?=?a?+?b;
NSLog("The?result?is:?%d",?self.sum);
}
看一下Project navigator面板粱挡,你會(huì)發(fā)現(xiàn)在ViewController.m文件旁邊,添加了一個(gè)M字母俄精,像下面這樣:
這意味著那個(gè)文件已經(jīng)被修改询筏,相比上一次提交更改,文件有所改變竖慧。一般來(lái)說(shuō)嫌套,你每次改變文件,都會(huì)出現(xiàn)這個(gè)M字母圾旨,提醒你有未提交的更改踱讨。
下面看看如何提交更改,其實(shí)非常簡(jiǎn)單砍的,只需要打開(kāi)Source Control>Commit菜單痹筛,下面窗口就會(huì)出現(xiàn):
讓我們一步步看看它告訴我們了什么。在左邊(標(biāo)1的區(qū)域)廓鞠,列出了所有被更改的文件帚稠,在這個(gè)例子中,只有ViewController.m這個(gè)文件被改變床佳,因此列表中只有它被顯示滋早。如果你仔細(xì)觀察,你會(huì)發(fā)現(xiàn)文件左邊有一個(gè)選擇框砌们,默認(rèn)情況下是被選中的杆麸,如果你取消它,這個(gè)文件的更改就不會(huì)被提交浪感。
在窗口的中間區(qū)域昔头,有兩個(gè)預(yù)覽窗口,左邊那個(gè)是文件當(dāng)前版本影兽,右邊是文件上一次提交更改的版本减细。因?yàn)槲覀兡壳爸皇莿?chuàng)建時(shí)提交過(guò)一次更改,因此右邊顯示的是文件的初始狀態(tài)赢笨。
左邊窗口藍(lán)色區(qū)域標(biāo)出的就是更改的內(nèi)容,這樣的表示讓我們可以清楚地看出所有的修改驮吱。如果你仔細(xì)看茧妒,會(huì)發(fā)現(xiàn)在兩個(gè)窗口之間還有一個(gè)帶數(shù)字的小標(biāo)簽,這個(gè)數(shù)字一一表示了各項(xiàng)更改左冬。在數(shù)字旁邊桐筏,默認(rèn)情況下有一個(gè)小對(duì)勾,表示本更改會(huì)被提交拇砰,如果你點(diǎn)擊右邊的小箭頭梅忌,會(huì)彈出一個(gè)選項(xiàng)菜單狰腌,你可以選擇不提交這個(gè)更改或是忽略它。
如果你選擇了Don’t Commit這個(gè)選項(xiàng)牧氮,小對(duì)勾就會(huì)被一個(gè)停止標(biāo)志取代琼腔,這項(xiàng)更改就不會(huì)被保存到源中。
如果你選擇了Discard Change這個(gè)選項(xiàng)踱葛,會(huì)彈出一個(gè)確認(rèn)窗口丹莲,提示你所做的更改會(huì)被恢復(fù),并且無(wú)法取消這個(gè)操作尸诽。
如果你點(diǎn)擊了OK按鈕甥材,所選區(qū)域的改變就會(huì)消失,就像他們從未出現(xiàn)過(guò)一樣性含。
如果你仔細(xì)觀察上面這個(gè)提交窗口洲赵,你會(huì)看到你所做的所有修改都會(huì)被Xcode看做改變,即使是一個(gè)空行商蕴。實(shí)際上空行相當(dāng)于回車叠萍,在屏幕上是不可見(jiàn)的,因此作為改變也是理所當(dāng)然的究恤。
在本例子中俭令,你不用忽略任何修改,而是允許提交所有更改部宿,因此所有的改變標(biāo)簽旁邊必須都是小對(duì)勾抄腔。
在兩個(gè)窗口下面是一個(gè)空白的區(qū)域,中間顯示了提交更改的信息理张。這個(gè)地方可以添加一些關(guān)于此次更改的簡(jiǎn)短描述赫蛇,點(diǎn)擊它,加入如下內(nèi)容:
書寫有意義的提交信息非常有用雾叭,尤其是當(dāng)你頻繁提交的時(shí)候悟耘。因此,把它當(dāng)做一個(gè)必要的步驟织狐。
現(xiàn)在這個(gè)窗口的基本信息看的差不多了暂幼,是時(shí)候做我們第一次的提交了。在這個(gè)窗口的右下腳移迫,有一個(gè)按鈕上面寫著:Commit 1 file旺嬉。
這個(gè)按鈕會(huì)顯示需要提交的文件總數(shù)合陵。點(diǎn)擊它之后你的第一次提交就完成了讶隐!打開(kāi)Source control > History,你會(huì)發(fā)現(xiàn)它會(huì)被顯示在列表中檬洞。
從上圖中可以看出,我們編寫的信息以及更改的文件數(shù)量會(huì)被顯示出來(lái)雨效。Xcode執(zhí)行初始提交迅涮,所有文件都會(huì)被提交一下,而這次只有我們修改的那個(gè)文件被提交徽龟。
另外叮姑,關(guān)閉歷史窗口,看一下Project Navigator顿肺,你會(huì)發(fā)現(xiàn)ViewController.m旁邊的M符號(hào)已經(jīng)消失了戏溺。
現(xiàn)在,讓我們準(zhǔn)備下一次提交屠尊。這次旷祸,我們給工程添加一些新的文件。添加文件最好的方式就是創(chuàng)建個(gè)新類讼昆,因此托享,按下Command+N組合鍵,添加一個(gè)Objective-C類浸赫。讓這個(gè)類繼承NSObject類闰围,取名叫TestClass,然后添加到工程中既峡。
完成之后羡榴,注意一下Project Navigator,你會(huì)發(fā)現(xiàn)兩個(gè)新的類文件旁邊有個(gè)A的字母標(biāo)識(shí)运敢,這意味著這些文件已經(jīng)被添加到項(xiàng)目中校仑,當(dāng)然,他們還沒(méi)有被提交传惠。
打開(kāi)ViewController.h文件迄沫,導(dǎo)入我們的新類:
#import?"TestClass.h"
下一步,打開(kāi)ViewController.m文件卦方,像下面一樣聲明一個(gè)私有屬性:
@interface?ViewController?()
@property?(nonatomic)?int?sum;
@property?(nonatomic,?strong)?TestClass?*testClass;
@end
看一下項(xiàng)目導(dǎo)航欄羊瘩,這次有四個(gè)文件有待提交。讓我們打開(kāi)Source Control > Commit菜單盼砍,將它們提交尘吗。
需要提交的一共有5個(gè)文件。除了之前修改的四個(gè)之外浇坐,還有一個(gè)項(xiàng)目配置文件摇予。Xcode會(huì)在新類被添加到項(xiàng)目中之后自動(dòng)修改這個(gè)文件。如果你你打開(kāi)TestClass.h或TestClass.m文件吗跋,左邊的窗口沒(méi)有任何顯示,如下圖所示。
這是因?yàn)樵谶@個(gè)文件在之前沒(méi)有被提交的記錄跌宛,因此沒(méi)有一個(gè)可以比較的版本酗宋,在右邊只顯示了File was added。
在消息區(qū)寫上這樣一個(gè)描述:TestClass was added to project.. 之后點(diǎn)擊Commit 5 files按鈕即可疆拘。
這樣第二次手動(dòng)提交就成功了蜕猫。你可以到Source Control > History 菜單查看提交的記錄。
版本之間的比較(Comparing Versions)
當(dāng)你提交了同一工程的不同版本之后哎迄,在他們之間比較回右,追蹤修改信息就會(huì)非常方便。當(dāng)新添加的代碼不能運(yùn)行時(shí)漱挚,這時(shí)與之間版本進(jìn)行比較就非常重要了翔烁,你可以看出新版本相比上個(gè)穩(wěn)定版有了哪些更改。
要比較同一個(gè)文件的兩個(gè)版本旨涝,你可以使用View>Version Editor>Show version editor蹬屹,或是點(diǎn)擊工具欄上的Version Editor按鈕:
點(diǎn)擊之后,編輯器會(huì)分為兩欄白华。最初慨默,兩欄會(huì)顯示相同的內(nèi)容,點(diǎn)擊編輯器下面的那個(gè)小時(shí)鐘圖標(biāo)弧腥,可以選擇之前已經(jīng)提交的版本進(jìn)行比較厦取。
點(diǎn)擊之后,兩個(gè)版本的區(qū)別會(huì)在編輯器中顯示出來(lái)管搪。通常虾攻,左邊顯示的是當(dāng)前版本的文件,右邊顯示的是之前的版本抛蚤。藍(lán)色高亮的區(qū)域顯示了被更改的代碼台谢,因此比較代碼的變化非常容易。繼續(xù)選擇任何此前的版本岁经,并觀察兩欄的區(qū)別朋沮。
你可能會(huì)注意到,在兩個(gè)編輯器中間缀壤,還有在提交窗口看到的小標(biāo)簽樊拓。點(diǎn)擊向下的按鈕可以跳出讓你忽略更改的選項(xiàng)。如果你點(diǎn)擊了忽略更改塘慕,Xcode會(huì)提示你是否同意筋夏。如果你同意忽略,這些被忽略的代碼將會(huì)永遠(yuǎn)消失图呢,無(wú)法再找回來(lái)条篷。所以要注意不要無(wú)意中忽略任何代碼骗随。
除了上面說(shuō)到的方法,還有一種你回到之前版本的方法赴叹。如果你仔細(xì)觀察兩個(gè)編輯器下面的工具欄鸿染,在中間有個(gè)帶箭頭的時(shí)鐘圖標(biāo):
點(diǎn)擊它之后,兩個(gè)面板之間的縱列內(nèi)容就發(fā)生了改變乞巧,變成了一系列表示之前更改的時(shí)間戳涨椒。注意并不是所有的都代表實(shí)際提交。代表先前版本的圓角矩形的數(shù)量取決于提交的次數(shù)绽媒。在這個(gè)例子中蚕冬,只有兩個(gè)這樣的圖形,代表了兩次提交是辕。
在這一列的下面囤热,有兩個(gè)箭頭。左邊的那個(gè)屬于左邊的面板免糕,右邊的箭頭屬于右邊的面板赢乓。將箭頭移動(dòng)到任意之前的版本,你會(huì)看到在相應(yīng)面板中的改變石窑。如果你想比較當(dāng)前版本和之前任意版本的區(qū)別牌芋,讓一個(gè)箭頭指向local行,然后移動(dòng)第二個(gè)箭頭松逊。時(shí)間戳從底部到頂部代表了從新到舊的代碼躺屁。在base行,你會(huì)看到上一次提交的內(nèi)容经宏。繼續(xù)向上移動(dòng)犀暑,你會(huì)看到最初的提交,如下圖所示:
現(xiàn)在你知道如何比較版本之間的區(qū)別了烁兰。再繼續(xù)深入之前耐亏,把前面學(xué)習(xí)的練習(xí)一下玩玩吧。
究竟是誰(shuí)的錯(cuò)沪斟?(Who’s Got the Blame)除了比較文件的版本外广辰,Xcode還可以讓你追蹤文件的提交者,以及是誰(shuí)改變了哪一部分代碼主之。在一個(gè)多人的團(tuán)隊(duì)中择吊,這非常有用。要使用這個(gè)功能槽奕,點(diǎn)擊View > Version Editor > Show Blame View菜單几睛。或是講鼠標(biāo)放在工具欄的Version editor 按鈕上粤攒,選擇Blame選項(xiàng)所森。一個(gè)與上面類似的窗口將會(huì)出現(xiàn):
正如你看到的囱持,當(dāng)前文件依據(jù)不同的提交被水平線分成幾段,每個(gè)代碼段的作者必峰,以及提交信息和其他信息顯示在窗口右邊的一個(gè)特殊面板中洪唐。
如果你還沒(méi)有做過(guò),那自己動(dòng)手打開(kāi)這個(gè)blame視圖吼蚁,注意一下Xcode展現(xiàn)代碼段作者的方式。在這個(gè)視圖中问欠,可以方便地找到某一代碼在何時(shí)被誰(shuí)提交以及其他你想要的信息肝匆。將鼠標(biāo)放在blame面板上,將會(huì)顯示修改的一些其他信息顺献。當(dāng)指針停在提交段上時(shí)旗国,一個(gè)帶圖片的小按鈕就會(huì)出現(xiàn)在它的右邊。點(diǎn)擊選中該段代碼注整,就會(huì)彈出一個(gè)附帶提交信息窗口能曾。在這個(gè)窗口中,你還可以跳轉(zhuǎn)到比較窗口(indication #1)肿轨,以及特定提交的修改文件(indication #2)寿冕。
除了比較視圖和blame試圖,其實(shí)還有一個(gè)日志視圖(Log view)椒袍。你可以通過(guò)View > Version Editor > Show Log View來(lái)打開(kāi)它驼唱。或者如果你在這里就不在詳細(xì)說(shuō)它了驹暑。你可以自己去看看玫恳,畢竟這個(gè)用起來(lái)也沒(méi)那么復(fù)雜。
分支(Branches)試想一下优俘,你現(xiàn)在的工程有一個(gè)即將發(fā)布的版本京办,或是已經(jīng)發(fā)布的版本,你突然想添加一些新的特性帆焕,如何防止這些新添加的代碼讓整個(gè)項(xiàng)目陷入癱瘓呢惭婿?答案很簡(jiǎn)單:你需要使用分支。
如何簡(jiǎn)單的理解分支呢视搏?你可以把你的項(xiàng)目想象成一棵樹(shù)审孽,穩(wěn)定版本就是樹(shù)的主干。任何添加新功能的版本都必須是樹(shù)干的一部分浑娜。分支佑力,就像是樹(shù)的枝干,它從樹(shù)干生長(zhǎng)出來(lái)筋遭,向不同的方向生長(zhǎng)打颤。在git中暴拄,你可以通過(guò)創(chuàng)建分支來(lái)為你的代碼設(shè)置一個(gè)新的路徑來(lái)實(shí)現(xiàn)新特性,而不用擔(dān)心在開(kāi)發(fā)中破壞主干编饺。
實(shí)際上乖篷,在git中默認(rèn)都會(huì)有一個(gè)分支,叫做master透且。Xcode自動(dòng)執(zhí)行的第一次提交中就發(fā)生在這個(gè)分支中撕蔼。通常,單獨(dú)的開(kāi)發(fā)者只在master這個(gè)分支開(kāi)發(fā)秽誊,這其實(shí)不是一個(gè)好習(xí)慣鲸沮。無(wú)論你是單打獨(dú)斗還是組團(tuán)合作,我認(rèn)為在對(duì)項(xiàng)目作出重大改變或添加重大功能時(shí)锅论,使用分支是十分重要的讼溺,它會(huì)為你避免很多麻煩。當(dāng)然最易,在團(tuán)隊(duì)項(xiàng)目中怒坯,為你自己負(fù)責(zé)部分的代碼搞一個(gè)分支幾乎是必須的。
關(guān)于分支藻懒,你必須記住以下兩點(diǎn):
提交到App Store或客戶的最終產(chǎn)品必須是項(xiàng)目中的master分支項(xiàng)目剔猿。
任何在第二分支中實(shí)現(xiàn)的代碼或者功能最終都必須合并到master分支,這樣正式發(fā)布的應(yīng)用程序才是完整的束析。(以后再講這一點(diǎn))
當(dāng)你開(kāi)始一個(gè)新分支時(shí)艳馒,你實(shí)際上是以當(dāng)前工作狀態(tài)作為起點(diǎn),即使你有任何未提交的更改员寇。從這個(gè)時(shí)候起弄慰,所有的改變都會(huì)只體現(xiàn)在分支中。
現(xiàn)在讓我們回到Xcode蝶锋,要?jiǎng)?chuàng)建一個(gè)分支陆爽,點(diǎn)擊Source Control > GitDemo-master > New Brance…這個(gè)菜單,然后會(huì)彈出如下菜單:
為這個(gè)分支起一個(gè)名字扳缕,我就把它起名為AnotherBranch好了』疟眨現(xiàn)在你怎么給它起名其實(shí)都無(wú)所謂。點(diǎn)擊OK按鈕躯舔,等一下新的分支就會(huì)被創(chuàng)建驴剔,而當(dāng)前的代碼也會(huì)復(fù)制到新分支中去。
打開(kāi)Source Control菜單粥庄,你就可以輕松地找出活動(dòng)分支是哪一個(gè):它就在項(xiàng)目名字的旁邊丧失。
現(xiàn)在,讓我們做一次新的分支的提交惜互。在這之前布讹,讓我們添加一些新的代碼琳拭。打開(kāi)類文件,在私有屬性區(qū)添加以下方法聲明:
@interface?ViewController?()
...
-(void)sayHello;
@end
然后實(shí)現(xiàn)它:
1
2
3-(void)sayHello{
NSLog("Hello");
}
最后描验,在viewDidLoad中調(diào)用它:
1
2
3
4
5
6-?(void)didReceiveMemoryWarning
{
...
[self?sayHello];
}
現(xiàn)在白嘁,點(diǎn)擊Source Control > Commit菜單,版本比較窗口將會(huì)出現(xiàn)膘流,你會(huì)看到只有一個(gè)被修改過(guò)的文件--ViewController.m文件絮缅,新添加的部分會(huì)被高亮顯示。
輸入下一個(gè)提交信息:First commit to a new branch呼股,然后點(diǎn)擊commit 1 file按鈕∶蓑迹現(xiàn)在AnotherBrance分支的改變就會(huì)被提交了。
打開(kāi)Version Editor(menu View > Version Editor > Show Version Editor)卖怜,找到右邊編輯面板下面的工具欄,你會(huì)看到被選中的分支是AnotherBranch阐枣,點(diǎn)擊它马靠,你會(huì)看到這個(gè)分支和master分支同時(shí)出現(xiàn),從master分支中選擇任意版本蔼两,Xcode都會(huì)高亮顯示兩者之間的區(qū)別甩鳄。通過(guò)這樣,你可以方便地跟蹤所有分支間代碼的改變额划。
最后妙啃,切換到另一個(gè)分支,或是master分支俊戳,你可以點(diǎn)擊Source Control > GitDemo –AnotherBranch > Switch to Branch…菜單揖赴。
從這個(gè)窗口你可以選擇想要跳轉(zhuǎn)的分支,在這里讓我們跳回master分支:
選擇它并點(diǎn)擊Switch按鈕抑胎,master分支就會(huì)成為當(dāng)然活動(dòng)分支燥滑。你會(huì)發(fā)現(xiàn)在AnotherBranch中做出的改變并沒(méi)有出現(xiàn)在master分支。很好阿逃,我們?cè)诠芾砉こ掏七M(jìn)的同時(shí)铭拧,卻沒(méi)有修改穩(wěn)定版本。
合并分支(Merging Branches)在分支中進(jìn)行開(kāi)發(fā)是一種好習(xí)慣恃锉,然而搀菩,如果代碼改變要體現(xiàn)在發(fā)行版中,那么分支就必須被合并到master分支中破托。這一節(jié)我們將會(huì)告訴你怎樣合并它們肪跋。在Xcode里,將兩個(gè)分支合并成一個(gè)非常簡(jiǎn)單炼团。
讓我們做一個(gè)小實(shí)驗(yàn)來(lái)看看合并是怎樣工作的澎嚣。首先疏尿,確保master分支是現(xiàn)在的活動(dòng)分支。如果不是易桃,趕緊改過(guò)來(lái):Source Control > GitDemo – AnotherBranch > Switch To Branch… menu褥琐,并從展示窗口選擇master分支。
下一步晤郑,創(chuàng)建一個(gè)新的分支:Source Control > GitDemo – master > New Branch… menu敌呈,命名為L(zhǎng)astBranch
先讓Xcode飛一會(huì),然后造寝,到ViewController.m文件中磕洪,再創(chuàng)建一個(gè)私有方法,首先聲明它:
@interface?ViewController?()
...
-(void)sayByeBye;
@end
然后實(shí)現(xiàn)它:
1
2
3-(void)sayByeBye{
NSLog("Bye?-?Bye");
}
最后诫龙,在ViewDidLoad方法中調(diào)用它:
1
2
3
4
5
6-?(void)viewDidLoad
{
...
[self?sayByeBye];
}
在合并之前析显,先提交這些更改。使用Source Control > Commit菜單來(lái)執(zhí)行提交签赃。
終于還是來(lái)到這一步谷异,關(guān)于把兩個(gè)不同的分支合并成一個(gè),你有兩種選擇:
從分支合并:與你選擇的分支相關(guān)的任何改變都會(huì)被合并到現(xiàn)在活動(dòng)分支中锦聊。
合并到分支:當(dāng)前活動(dòng)分支的任何改變都會(huì)被合并到你選擇的分支中歹嘹。
這兩種方式你都可以在Source Control > GitDemo 菜單中找到。注意當(dāng)你的活動(dòng)分支是master分支時(shí)孔庭,第二個(gè)選項(xiàng)是不可選的尺上。
假設(shè)一個(gè)開(kāi)發(fā)者在Anotherbranch分支實(shí)現(xiàn)一個(gè)sayHello方法,另外一個(gè)開(kāi)發(fā)者在LastBranch中創(chuàng)建實(shí)現(xiàn)了sayByeBye方法圆到,現(xiàn)在你需要將兩個(gè)人的工作合并到下一個(gè)穩(wěn)定版本中怎抛,想一想你需要怎么做?很簡(jiǎn)單构资,按以下方法將改變從兩個(gè)分支中合并進(jìn)來(lái):
首先抽诉,確保當(dāng)前活躍分支是master分支。
然后吐绵,打開(kāi)Source Control > GitDemo – master > Merge From Branch…菜單迹淌,選擇AnotherBranch然后點(diǎn)擊Merge按鈕。
接下來(lái)會(huì)出現(xiàn)一個(gè)比較窗口己单,在里面你會(huì)看到合并之后代碼的更改唉窃,看一眼,感覺(jué)差不多了就再點(diǎn)擊Merge按鈕纹笼。
Xcode會(huì)詢問(wèn)你是否保存項(xiàng)目的快照纹份,點(diǎn)擊Enable按鈕。讓Xcode飛一會(huì),然后就好啦蔓涧。AnotherBranch里面添加的內(nèi)容已經(jīng)合并到master分支中件已。
使用同樣的方法來(lái)合并LastBranch。你會(huì)發(fā)現(xiàn)如果你不提交更改元暴,Xcode不會(huì)讓你再次合并篷扩。于是,我們只好先提交一下茉盏。在比較窗口你會(huì)發(fā)現(xiàn)一個(gè)紅色的區(qū)域顯示合并之后的更改鉴未,而不是之前的藍(lán)色。這意味著分支中的代碼將會(huì)替換原先活動(dòng)分支中的代碼鸠姨。
你可以輕松地避免這種現(xiàn)象的發(fā)生铜秆。在編輯面板的下面有幾個(gè)小按鈕,你可以試試他們都有什么作用讶迁,我選了第一個(gè)连茧,它的意思是master分支的代碼會(huì)被放在上面,另一個(gè)分支的代碼會(huì)跟在它后面巍糯。
處理接下來(lái)所有需要更改的代碼梅屉,不要有遺漏。完事后就點(diǎn)擊Merge按鈕鳞贷。
恭喜你!你已經(jīng)成功的學(xué)會(huì)從多個(gè)分支合并了代碼虐唠,類似的情形你也應(yīng)該會(huì)了搀愧。
忽略更改(Discarding Changes)放棄不想要的代碼更改功能非常有用,只需輕輕一點(diǎn)疆偿,自從上一次提交之后的更改都會(huì)被放棄咱筛。當(dāng)你在開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)出了大亂子,你想從上一個(gè)穩(wěn)定狀態(tài)重新開(kāi)始時(shí)杆故,這個(gè)功能就派上用場(chǎng)啦迅箩。注意放棄更改這個(gè)功能沒(méi)有回頭路,點(diǎn)完之后你就沒(méi)有辦法再撤銷這個(gè)操作处铛,所以饲趋,要小心使用啊撤蟆!
之前奕塑,當(dāng)我們?cè)谟懻摪姹颈容^時(shí),我們學(xué)會(huì)了如何忽略某一部分更改的方法家肯,下面龄砰,我們要學(xué)一下如何一下忽略自從上一次提交之后的所有更改。
為了測(cè)試這個(gè)功能,首先寫一些代碼打開(kāi)ViewController.h 换棚,添加一個(gè)公共方法聲明:
1
2
3
4
5@interface?ViewController?:?UIViewController
-(void)aVeryCoolMethod;
@end
現(xiàn)在式镐,讓我們?cè)赩iewController.m中添加一個(gè)這個(gè)方法的實(shí)現(xiàn),簡(jiǎn)單點(diǎn)就行:
1
2
3-(void)aVeryCoolMethod{
NSLog("I'm?feeling?that?you'll?discard?me...?Really?");
}
如果你注意到Project Navigator固蚤,我們剛剛更改的文件旁邊有了一個(gè)M標(biāo)識(shí)娘汞,很好,我們想看看如果忽略這些更改颇蜡,這些文件是否會(huì)回到更改之前的狀態(tài)价说。
這里有一個(gè)重要的細(xì)節(jié):你可以選擇忽略所有文件的更改,也可以選擇忽略單個(gè)文件的更改风秤,這完全取決于你鳖目。如果你想忽略一個(gè)文件的更改,首先選定這個(gè)文件缤弦。在這個(gè)例子里领迈,如果你只選擇ViewController.m文件然后打開(kāi)Source Control菜單,你會(huì)在ViewController.m中發(fā)現(xiàn)Didcard Changes這個(gè)選項(xiàng)碍沐。類似的狸捅,如果你只選擇ViewController.h也是一個(gè)道理。然而累提,如果你想忽視這兩個(gè)文件的更改(這里假定有兩個(gè)以上的更改)尘喝,就在Project Navigator中選中它們,然后再打開(kāi)Source Control菜單斋陪。相應(yīng)的位置就會(huì)顯示Discard Changes in 2 Files朽褪,像下面這樣:
然而,這次我們不會(huì)使用這個(gè)按鈕无虚,我們要用Discard All Changes缔赠。點(diǎn)擊它之后,一個(gè)確定提示框就會(huì)出現(xiàn)友题,這是這部分Xcode防止你誤刪代碼的唯一措施嗤堰。
點(diǎn)擊Discard All Changes, 那你剛才寫的那個(gè)公共方法就永遠(yuǎn)屬于過(guò)去了《然拢看到了吧踢匣,只需幾步就可以讓你從當(dāng)前工作狀態(tài)恢復(fù)到之前的提交,所以我再一次提醒你要在使用Source Control 中小心點(diǎn)戈抄,別誤點(diǎn)了這個(gè)按鈕符糊。