由Richard Critz更新为Xcode 8。Malek Trablesi的原创教程,之前由Felipe Laso-Marsetti更新。
无论您是独立开发人员还是在团队工作,如果您没有为项目使用源代码管理,您应该是。
源代码控制是惊人的,因为它可以帮助您更轻松地恢复到旧版本的代码,添加新功能,而不会对您的工作应用程序造成风险,看看代码如何随着时间的推移而发生变化,并且作为一个团队工作。
而最好的源代码管理系统之一就是Xcode - Git!
Git是最初由Linus Torvalds开发的分布式版本控制系统,Linus Torvalds是Linux内核开发的主要力量。
关于Git的好处是没有任何中央存储库 - 每个人都可以拥有自己的代码视图,并从其他来源引入更改。
在本教程中,您将掌握Git的经验,并学习如何在Xcode中直接使用它。
开始启动
而不是对Git的理论表示赞赏,你将会直接潜水并尝试一下。
您将创建一个新的Xcode项目,并尝试通常使用Git源代码控制进行日常操作的一些任务。
启动Xcode并创建一个新的Single View Application项目。
填写模板选项如下:
产品名称:GitUseExample
团队:您的Apple开发人员团队如果您有一个或无
组织名称:您的姓名
组织标识符:如名称所示,它是您组织的标识符(如果有)。否则,输入任何内容。
语言:Swift
设备系列:iPhone
使用核心数据,包括单元测试和包括UI测试:未选中
现在点击** Next。以下对话框允许您选择保存项目的位置。
选择一个位置,并确保在继续之前选择 Create git repository on My Mac库。一旦这样做,单击 Create**。
注意:如果没有看到复选框,请单击** Options**.
Xcode将创建一个新的项目以及一个新的Git存储库。
包括Git在内的所有源代码管理系统将其数据存储到存储库中,从而可以管理项目版本,并在整个开发周期内跟踪更改。
将存储库视为版本的数据库。

在您的项目工作过程中,您将多次添加文件,修改代码和更改项目。
在进行一系列更改后,您的项目处于“已知状态”(通常每天一次或多次),最好检查您对存储库的更改。
这给你一个可以随时返回的“已知的好”状态的记录。
但是项目模板创建的代码呢?
您的项目仍然只包含模板文件。
没有什么可以让你提交,因为Xcode在你创建项目时为你做了这件事。
要检查,请从菜单中选择Source Control \ History ...

在下拉窗口中,请注意有一个提交以及一些关于它的信息,包括提交标识符,日期和时间,做出提交的人,更改的文件和提交消息。

注意:通常,您可以单击Show modified files按钮,以查看有关提交内容的更多信息。不幸的是,由于Xcode中的错误,这只能在某些时间工作。您将学习一种不同的,更可靠的方式来查看以下信息。
现在,对您的项目进行一些更改。打开AppDelegate.swift并将方法更application(_:didFinishLaunchingWithOptions:)
为以下内容:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print("Application did finish launching")
return true
}
保存文件后,您将注意到,AppDelegate.swift现在在文件名旁边有一个“M”标记:

“M”标记代表“已修改”。这意味着您已修改该文件,但尚未向本地Git存储库提交更改。
接下来,打开ViewController.swift,然后添加以下代码viewDidLoad():
@IBAction func buttonClicked(_ sender: UIButton) {
print("This is a Git tutorial")
}
现在,打开Main.storyboard并从对象库中拖动一个按钮到屏幕。
将按钮的显示文本更改为任何您想要的,如下面的屏幕截图所示。
最后一件事是将动作连接到按钮。
单击View Controller场景中的黄色View Controller图标。
从“连接检查器”(右侧栏中的最后一个选项卡),单击
buttonClicked:
“接收的动作”面板旁边的开放圆圈,然后将其拖动到故事板编辑器中的按钮。从弹出菜单中选择Touch Up Inside
如果您检查项目导航器,您会注意到,您编辑的所有三个文件都有一个“M”标记。
构建并运行以确保项目工作。
验证当您单击按钮时,您会看到“这是一个Git教程”消息记录到控制台。

w00t - 你的代码现在处于“已知的好”状态!
现在是时候承诺了。
做一些commit
提交文件很简单!从菜单中选择Source Control \ Commit ...
将显示一个新窗口,类似于以下内容:

您可以看到,屏幕分为两个窗格。左侧窗格显示该文件处于当前状态,并自上次提交以来进行了所有更改。由于这是您的第一个提交,您将看到自项目创建以来所做的所有更改。
在您进行更改之前,右窗格显示该文件。

更详细地查看提交窗口中Xcode的内容。
左侧面板(1)显示项目中的所有文件中未提交的更改。
默认情况下,Xcode假设您希望将其全部包含在此提交中并检查其框。
如果要从此提交中排除文件,请取消选中。
正如您将在稍后看到的,您还可以决定在此提交中包含文件中的哪些单独更改。
注意代码窗格中的蓝色亮点。这些表示您所做的更改。
任何更改,即使只添加或删除空格,也被跟踪,并将被标记这些蓝色亮点。
尝试一下自己。单击* Cancel按钮,打开ViewController.swift,并在文件末尾添加多条新行。
现在再次选择Source Control \ Commit ...*您的结果应类似于以下内容:
如您所见,Git会仔细跟踪您在整个开发周期中所做的每一个变化。
在两个源窗格之间的区域中,所有的更改都由Xcode(上面标记为“2”)列举。
默认情况下会检查每个更改。要从此提交中排除特定更改,请取消选中。
例如,更改3并不重要,因为它只包含您之前添加的空白行。
取消选中它,以使此更改未提交。
请注意,指示灯已变为灰色,表明此更改现在已从提交中排除。
排除个别变化的另一种方法是点击更改号码旁边的箭头。
将出现两个选项:Don’t Commit(或** Commit,以防更改被取消选中)和 Discard Change。在这种情况下,请选择Don’t Commit**

在您可以完成提交之前,Xcode要求您在屏幕的底部输入提交信息(标记为“3”)。这些消息可以帮助您更好地了解每个提交的目的。
现在点击Commit 4 Files.恭喜,你做了你的第一个提交!
如果您回到历史记录窗格,您应该在日志中看到新的提交:

这个简单的改变过程就是你在90%的时间里做的。很简单,对吧?现在你没有任何借口不要这样做。
注意:仔细的读者会认为“我只更改了3个文件。为什么我提交4个文件?“Git跟踪项目目录中的每个文件,包括Xcode在幕后使用的所有文件。通常,这正是你想要的。您将在以后看到如何在需要时更改此行为。
Branching Out
Xcode支持的Git的另一个功能是将更改提交到特定的分支。但等等,什么是分支?
分支是将一组提交保留在一起的方式。通过在不同的分支机构工作,您可以将功能分开,并降低完全破坏项目的风险。
相信与否,你已经在使用一个分支。当首次创建存储库时,Git还会在该存储库中创建一个名为“master”的分支。
所有的工作到目前为止,都在主分支上。主分支应始终保留项目的主要副本。您使用其他分支作为存储尚未准备发布的进行中的工作的方法。您也可以使用它们来存储可能永远不会被释放的实验。
例如,假设您要在应用中添加新的地图功能,但尚未准备好进行生产。为了模拟这个,创建一个派生自NSObject
它的新类并命名为
MapForItinerary。此时您的项目可能如下所示:

注意新文件MapForItinerary.swift的状态“A” 。这表明这是一个尚未提交到存储库的新文件。
从菜单中选择
Source Control \ Commit ...

如果您选择具有A状态的文件,您将注意到Xcode不提供任何早期版本进行比较。这是因为该文件尚未提交到存储库,所以没有什么可以比较它。
将地图功能添加到您的应用程序代表您的代码很大的变化。这是使用分支的最典型的情况。如果您的新地图代码出现问题,这将有助于隔离风险。
而不是单击Commit 3 Files按钮,而不是单击** Cancel。从菜单中选择Source Control\GitUseExample\New Branch…请注意,当current branch** - ** master** - 显示在菜单中。
Xcode要求您命名新的分支。

命名分支map_feature并单击** Create。
Xcode创建新的分支并切换到它。您可以通过打开Source Control菜单来验证这一点。

选择Source Control \ Commit ...,输入提交消息,然后单击Commit 3 Files**。
请注意,项目导航器中的文件旁边的所有状态信件已被清除。
这意味着您不再有任何未提交的更改。

要查看您的分支,请从菜单中选择Source Control \ GitUseExample \ Configure GitUseExample ...。

在生成的窗格中选择** Branches**选项卡。

Backing Out
您正在处理项目的最新版本,构建最新的酷功能。你休息一下吃了点零食,突然灵感来了,你想到了更好的方法来写代码。此时,您可能希望从源代码控制恢复最新版本,并重新开始。

Git使这样做很简单!
打开Main.storyboard并从Object库将一个新的视图控制器拖到画布上。

打开MapForItinerary.swift并添加方法
sayHello()
。
class MapForItinerary: NSObject {
func sayHello() {
print("Hello from MapForItinerary")
}
}
请注意,修改的文件的状态已更改为“M”,这意味着文件在本地被修改并且正在等待提交。
此时,您可以选择性地丢弃对项目所做的更改。
选择Main.storyboard在Project Navigator,然后选择
Main.storyboard中 选择Source Control\Discard 从菜单中。
Xcode将提示您确认您真的希望丢弃该文件中的所有更改。

点击Discard Changes你应该看到刚刚添加的视图控制器(和黄色警告图标)消失了!当您添加一些更改但不起作用,并且您想要回到最后一个已知的良好状态时,这可能非常有用。
除了丢弃整个文件的更改外,您还可以放弃单个更改。MapForItinerary.swift仍然有“M”标记。从菜单中选择Source Control \ Commit ...。单击更改号码旁边的向下箭头,然后选择Discard Change:

哇!你的改变已经消失 因为没有什么可以提交,只需点击** Cancel关闭提交窗口。
现在你已经尝试了Discard Change,你可能会想知道与之前
选择的Do not Commit**选项有什么区别。
虽然这两个选项都可以导致更改不被记录在存储库中,但是存在很大的区别:
Don’t Commit允许您跳过更改,使其不会与其他更改一起提交,但仍将保留在本地源代码中。
丢弃更改不仅可以跳过更改,还可以从本地源代码中删除它。
Time Travel
放弃更改是恢复工作代码并节省时间的好方法。但是,在某些情况下可能会有一些限制。
Git允许您为每个版本具有特定更改的项目保存多个修订版本。这些都存储在由Git为您管理的存储库中。
如果选择放弃对文件的更改,Git将恢复文件的最后一个提交版本,并且只保留最后一个。那就是限制的所在。
随着时间的推移,您的项目库将包含反映您开发历史的多次修订。假设您希望还原到特定文件的第一个或第二个版本。没有办法,只是通过丢弃变化。不要绝望,然而,随着Xcode和Git做容易做的。
在Project导航器中选择ViewController.swift。现在从菜单中选择View \ Version Editor \ Show Comparison View。或者,您可以单击Xcode窗口右上角工具栏上“编辑器”部分的第三个按钮。

版本编辑器分为两个窗格,如下所示:

这允许您比较所选文件的两个修订版本,并且与提交窗口中的比较视图完全相同。
默认情况下,您当前的源文件显示在左侧,存储在存储库中的最新修订版本 - Git称为HEAD - 显示在右侧。
要从存储库显示早期版本,请单击右窗格底部的时钟图标(以下标记为红色),然后选择较早的版本。

在HEAD版本之前选择修订版本,如下所示。您看到的确切信息将与截图不同。
现在,要恢复到该文件版本,只需单击比较窗格中更改号码旁边的箭头,然后选择Discard Change。这很容易!

完成还原到较早版本后,您将需要将此“新”版本的文件提交为最新版本。现在去做吧。
你怎么知道哪个早期的提交是你想要的?虽然你可以肯定地使用你之前学到的历史命令,但是有一个更好的方法。单击并按住版本编辑器按钮,然后选择** Log,您还可以从菜单中
选择View \ Version Editor \ Show Log View。

Xcode将列出包含对当前文件的更改的提交。请注意,每个提交的列表包含提交标识符。

这些标识符与您之前使用的修订历史列表中显示的标识符相匹配。

您还可以单击Show modified files 来更详细地探讨差异。现在就试试!
另一个令人难以置信的有用的视图在您的项目被称为怪异视图。此视图显示您的文件的每一行提供哪些提交。
切换到Blame视图。
单击并按住版本编辑器按钮,然后选择Blame。您还可以从菜单中选择View \ Version Editor \ Show Blame View**。

您的屏幕将如下所示:

要查看有关承诺更改的更多详细信息,请按日期旁边的信息按钮。所产生的弹出窗口显示您做出提交的时间,提交时间,提交消息和提交标识符。它还有一个按钮来显示提交中修改的所有文件以及一个按钮以打开比较视图中的当前文件,并将此提交与HEAD提交进行比较。

Merging Branches
您以前学到Git允许您处理称为分支的多个修订流。您还了解到,除了主分支之外,在一个分支上进行所有开发都是一个很好的做法。那么当你完成一个功能的开发并且想要整合它时,你要做什么呢?简单!您将开发分支合并到您的主分支。
您的新地图功能尚未完成,但您的设计师在主界面上要求另一个标签。要实现这一点,您将需要将map_feature分支留在现在,并从您的master分支的“已知的”状态创建一个新的分支。
从菜单中选择Source Control \ GitUseExample \ Switch to Branch ...
从可用分支列表中选择master并单击Switch。

确保您从正确的“已知良好”状态开始您的新分支是很重要的。现在,从菜单中选择Source Control \ GitUseExample \ New Branch ...

将分支命名为new_label,然后单击创建。

您可以通过单击Source Control 并查看Working Copies.下的分支的名称来验证您正在处理new_label分支。

现在是时候添加您的设计师要求的新标签。
切换回标准编辑器视图,选择Main.storyboard,然后拖动UILabel到主视图。

构建并运行以确保所有都可以,然后将更改提交到存储库。确保添加提交消息。
现在切换到主分支并再次运行应用程序。正如预期的那样,UILabel您在分行中添加
的新功能不在此。最后的工作就是将新的分支机构合并回主机。
从菜单中选择Source Control \ GitUseExample \ Merge from Branch ...。

从可用分支列表中,选择new_label,然后单击** Merge。

将出现合并窗口,允许您控制合并进程。合并源(“合并从”分支)将显示在右侧。
合并修改的当前来源将显示在左侧。使用屏幕底部的按钮来控制合并的方向。
对于这样的简单合并,Xcode的默认设置将是正确的。

最后点击 Merge按钮开始进程。
如果一切顺利UILabel当您单击Main.storyboard**或运行应用程序时,应该会看到
新分支中的更改在用户界面中显示。现在你的更改是在主分支,因为合并!使用您学习的查看提交历史记录的其中一种方法来验证此更改是否显示在历史记录中。

Ignoring generated files 忽略生成的文件
回过头来,在你第一次把你看到的,除了你的源文件,跟踪修订由Xcode的文件。这很重要,因为这些文件与你的源文件一样是你的项目所必需的。你需要他们重建你的应用程序或与他人合作。
然而,作为它的工作,还产生了其他文件,改变各建。它不是拯救这些Xcode重要可以自动恢复。事实上,保存它们会使Git做不必要的工作,并使您更难在提交历史中发现重大变化。
Git提供了一种机制,忽略这些文件:适当命名的.gitignore文件。在其名字初使MacOS视它为一个隐藏文件,所以一般不会出现当你看在Xcode或查找你的项目。但是,不要害怕,因为Git会发现并使用它没有问题。
而不是为自己做的一切放在你.gitignore* file, 你可以从此下载 gitignore.io.
首先,打开终端窗口并输入以下命令。你只需要做这一步一次,而不是每一个项目
$ git config --global alias.ignore '!gi() { curl -L -s https://www.gitignore.io/api/$@ ;}; gi'
现在,对于任何使用Git的项目,在终端窗口中执行以下操作:
cd <directory where your project is stored>
git ignore swift,macos >.gitignore
git add .gitignore
git commit -m "Add .gitignore file"
这下载最新的。写银行代码在MacOS .gitignore配置。您的终端会话应该看起来类似:
注意你说的.gitignore文件到您的库Git跟踪由于过滤了也是你项目的一个重要组成部分
Xcode和GitHub
您迄今为止所做的所有工作一直在使用您计算机上保存的本地存储库。GitHub网站允许您将项目发布到保存在GitHub服务器上的远程存储库。这是伟大的,因为它允许您轻松地与他人共享您的代码,并以项目作为一个组。如果您还没有GitHub帐户,请转到GitHub并注册一个。
一旦完成,在GitHub上为您的项目创建一个存储库。单击GitHub站点右上角的+按钮,然后选择* New repository。

GitHub将向您显示一个类似于以下内容的屏幕:

填写存储库名称,然后单击* New repository。GitHub将创建您的存储库并带您进入快速设置屏幕。您可以忽略大部分屏幕。您需要将存储库的HTTPS URL保存到剪贴板。确保选中了HTTPS按钮,然后单击剪贴板图标。

在Xcode中,从菜单中选择Source Control \ GitUseExample \ Configure GitUseExample ....选择 Remotes选项卡,然后单击+按钮,然后选择Add Remote….。

遥控器的名称将默认为“origin”。保留原样并将您的GitHub HTTPS字符串粘贴到 Address字段中。单击 Address。

最后点击 Done。您现在可以在GitHub上发布您的项目!
从菜单中选择Source Control \ Push ....Xcode将提示您输入远程的名称和分支。由于您只配置了一个远程配置,默认值将是正确的。

点击 Push。Xcode将提示您输入您的GitHub登录凭据。

输入您的凭据,然后单击 OK。
Xcode将您的凭据保存到macOS钥匙串。您可以在Xcode首选项中的 Accounts**选项卡上管理它们。几秒钟后,Xcode将完成推送。
检查您的GitHub页面以验证您的文件是否在那里。

注意:如果您在GitHub上设置了SSH凭据(请参阅GitHub SSH指令),Xcode支持使用SSH连接到GitHub。只需使用SSH连接信息而不是HTTPS字符串添加您的远程。
现在是对您的项目进行最后一次更改的时候了。打开ViewController.swift并更改buttonClicked()
方法如下:
@IBAction func buttonClicked(_ sender: UIButton) {
print("You finished!")
}
从菜单中选择Source Control \ Commit ....输入提交信息,然后检查左下角的Push to remote:。再次,由于您只有一个远程配置,默认值将是正确的。
单击Commit 1 File and Push。几秒钟后,Xcode将完成提交和推送。在您的GitHub页面上查找您的新提交。
