Transcript
[ Music ]
>> Hi. I'm Eric Dudiak, an
engineer on the Xcode team.
And today we're going to talk
about source control workflows
in Xcode.
Now, developing apps requires
making lots of changes in your
source code and projects.
To help manage that change Xcode
provides a number of source
control tools.
So, today we're going to take a
look at a few of them.
To start, we're going to take a
look at how you create your
first project using source
control.
Next, we'll look at making and
viewing changes to your project
using source control.
We're also going to look at how
you host and share your
repositories with your team,
including synchronizing changes.
We'll take a brief look at
resolving and avoiding
conflicts.
And finally, take a quick look
at pull requests and forking.
So first, let's take a look at
creating a new project using
Git, the industry standard
source control system, supported
and included in Xcode.
The first step to using Git is
to set up your author name and
email.
This identifies you in Git
commits and makes it easy to
identify who made what changes
when working on a team.
Xcode supports quickly setting
this up in the preferences under
the Git options of the Source
Control tab.
When creating a new project in
Xcode, you can also choose to
create a Git repository.
During the Save operation for a
new project you can simply check
the box shown here, and Xcode
will create one automatically.
Now let's look at what that does
and what a Git repository is.
So you may be familiar with the
typical Xcode project,
represented here by a folder on
disk.
This includes your source files
and things like that.
Now, when you check the box to
also create a Git repository,
you'll get a .Git folder.
This represents the repository
for your project and will be
hidden from you normally.
Now it gets put into your
project folder, making it a
working copy.
The first thing that happens
with a new repository created in
Xcode is that the whole copy of
your project is made and
snapshotted at a point in time.
This snapshot of your project is
known as a commit.
Each commit in Xcode gets a
unique identifier.
As you make changes to our
project source code you can
create commits, which will take
further snapshots of your
project throughout time, while
you see those changes at the
point they were created.
These snapshots make up your
project's history.
As you make more, they form
something of a timeline.
And this information is what
makes up your repository.
So now that we've discussed
conceptually how this works,
let's take a look at making
changes and easily tracking them
in Xcode.
One of the easiest ways to do
this is with the Source Control
Change bar.
It highlights the lines of code
you change as you change them.
The change bar makes it easy to
see where in a file you've made
changes when you come back
later.
As changes are made, the bar
highlights the lines of files
with modifications.
In large files, it also makes it
quick to jump between your
changes.
In fact, you can quickly jump
between them from the Navigate
menu in Xcode.
In addition to the change bar,
you'll see status flags in the
project navigator telling you
which files have changed since
you last committed.
So now that we've made some
changes, let's talk about
committing.
These are snapshots of your
project at a point in time that
you can reference later.
Let's take a brief look at
creating these commits in Xcode.
So we've seen you can easily see
changes as you make them in your
project.
Now, when you're ready to record
these changes to your
repository, use the Source
Control menu to create a commit.
The commit sheet will show all
of the changes currently in your
project.
They show the side-by-side
comparison for you to review.
You can select which files and
even which specific changes to
include in the commit.
With the appropriate changes
selected, enter a message to
record the reason for your
changes.
This message makes it easy to
understand the reason for the
changes later when going back to
review them.
Now that we've made a couple
commits, let's talk about
viewing them.
You may want to refer back to
them to better understand how
your code and project have
changed over time.
This can be useful for
discovering the timeline of when
code was introduced in your
project, and why specific
changes were made.
Xcode offers several ways to
view this history.
First is the comparison mode,
which we just saw a little bit
in the commit sheet.
Xcode lets you view every file
in your project as it has
changed through time in this
way.
To access it, use the Version
Editor mode from the toolbar,
seen here.
Clicking and holding the
selector will let you jump to a
specific mode of the version
editor.
The comparison mode provides a
side-by-side view of source code
changes, allowing you to compare
the file between two points in
time.
While in the comparison mode,
you can change what version of
the file you are viewing using
the jump bar at the bottom.
Next is the Author View of the
version editor.
It is accessed in the same way
in the toolbar.
The Author View groups code by
the author who made the most
recent change to a particular
line in the file.
It shows the author, message,
and date of the commit.
Additional information about the
commit can be seen by clicking
on one of the slices.
Last, it is possible to see a
log of each change made to a
file.
Just like authors and
comparison, it is accessed from
the toolbar.
The source control log looks at
a file's entire history so you
can see who made changes and why
over the entire history of the
file.
Now, sometimes you want a way to
see changes made using source
control across not just a single
file, but your entire project.
To see this, you can select the
Source Control Navigator as the
second navigator in Xcode.
The Source Control Navigator
provides a view of your whole
repository by listing branches
and tags.
Branches are the individual
streams of history that make up
your project, such as the
current in development work.
When you start a new project,
you'll have just one branch,
typically named Master.
Selecting it will show the
history of that branch, which
can be seen here.
In this history view, you can
see the history is marked with
tags shown in purple.
Tags are bookmarks of
particularly important points in
your project such as shipped
versions.
For more information on
branches, viewing history, and
tags, please see the 2017 WWDC
Session, GitHub, and the new
Source control Workflows in
Xcode 9.
Now that we've looked at the
benefits of having a project
under source control, let's look
at taking things to the next
level.
So far we've seen what happens
when a project is just locally
managed by Git on your machine.
But in many cases, you'll want
to store a copy on a server.
This provides an off-site backup
as well as a means to
synchronize your changes from
one machine to another.
This is also the basis of
collaboration in Xcode projects.
Xcode works with any server that
supports hosting Git
repositories.
In these cases, the features are
limited to standard Git
operations such as push and
pull.
And there is no account to sign
into.
You just authenticate on demand
as needed.
Xcode also supports many common
hosting solutions such as
GitHub, BitBucket, and
GitLab.com.
With these services, additional
features are supported, such as
searching for repositories to
clone and creating new
repositories on the server
directly from Xcode.
In addition to the cloud
versions of these services,
self-hosted and enterprise
versions used on premise by
larger teams are also supported
in Xcode.
So let's take a look at adding
one of these hosted accounts.
You can add this account type
from Xcode's preferences under
the Account Preference pane.
You just sign into the account
using your username and
password, just like you would on
the website.
If you're signing into a
self-hosted version, you'll also
get a chance to provide the URL
for the specific server that you
want to connect to.
Now that Xcode is signed into a
hosted source control account,
we can start sending our changes
up to the server and getting
other changes from it.
But before we start pushing and
pulling code in Xcode, let's
take a brief moment to discuss
how Git and these hosting
solutions handle security.
Git supports two main methods
for securing changes when
connecting to a server.
The first, HTTPS, is the same
way most websites are secured.
It trusts the server based on a
certificate and uses a username
and password to authenticate you
as a user.
The other method, SSH, works a
bit differently, particularly
with these hosted solutions.
In general, SSH connections for
Git are secured using a public
and private key pair that is
generated on each machine.
The public portion of the pair
is then uploaded to the hosting
site.
This means that it is easy to
have one set of keys per
machine.
And often even one per service
so they can be managed and
revoked much more easily than a
password.
Xcode can help you easily do
these setup steps for SSH.
When you sign into an account
but have not created an SSH key
pair locally, Xcode will offer
to create a pair.
The private portion of the SSH
key should be protected by a
pass phrase.
This adds an additional layer of
security and prevents it from
being used even in the event
someone else were to get a copy
of your private key.
Once the key pair has been
created, Xcode can also upload
the public portion of the key
directly to the hosting site.
With the public key upload
complete, Xcode can transmit Git
data securely to the server over
the SSH protocol in addition to
HTTPS.
That also means we can now
create new repositories on the
server and clone existing ones.
So let's take a quick look at
that.
If we go back to our local only
repository, we can now create a
new remote for it.
This is a full copy of that
repository up on the hosted
site.
We can do this from the Source
Control Navigator in the Context
menu by selecting Create New
Remote.
We then have a few options
depending on the hosting site.
And we can choose to make it
either public or private, based
on our exact needs for this
project.
It can then be shared with other
developers or synched across
machines.
And when you want to download a
project that has already been
hosted on a server, such as on a
new machine or when joining a
team, you can browse and search
for a repository in the clone
window, accessed from the source
control menu in Xcode.
If you already had the URL to
use for the repository, you can
directly enter it in the search
field.
Additionally, all of the hosting
solutions supported in Xcode
offer the option to clone
projects directly in Xcode via a
button on their websites.
For additional information on
using hosted services including
creating remote repositories and
the varies clone workflows,
please refer to the 2017 WWDC
session GitHub and the New
Source control Workflows in
Xcode 9.
Now that we have a local and
remote copy of our project, we
need to make sure that they stay
in sync.
In Git that is done by
operations known as pulling and
pushing.
After you commit one or more
changes locally, you will want
to push to upload them to the
server.
This can be done either directly
while committing, right in the
commit sheet, or from the Xcode
source control menu.
The push sheet allows you to
select exactly what branch you
want to push to and optionally
allows you to include tags
you've created locally during
the push.
Now, when working with others,
it'll often be necessary to get
their changes locally.
For this you'll need to do what
is referred to in Git as a pull.
This, similarly, can be done
from the source control menu.
Now, Xcode offers two options
for pulling, either the Git
default of using a merge, or
Xcode can pull using a rebase
operation.
These work slightly differently
in Git.
So let's take a look at them.
Here we will look at a
conceptual timeline of commits.
If you've made local changes and
others have also made changes
while you were working, you will
have to pull before you push.
In this situation, your work,
shown in green, has diverged
from your coworker's work, shown
here in blue.
To rectify this, you'll have two
options in Git: merging and
rebasing.
Let's take a look at both.
So again, in this scenario you
have two changes to push and
three to pull.
When merging, this situation is
resolved by creating a new
commit, after both yours and
your coworker's, that indicates
how the divergence should be
handled.
With the commits now unified
back into a single branch, this
can be pushed up to the server
and synchronized across all your
machines.
A rebase pull works a little
differently.
Instead of creating a new merge
commit, your local changes are
set aside and then replayed
after the changes you just
pulled.
This can make looking back at
history much more simple, as
there is no merge commit or
divergence in history.
Sometimes when pulling, you will
have made local commits that
change something in the same
place as someone else is making
changes.
This can cause what is known in
Git as a conflict, where it is
unclear how to have both changes
coexist.
Xcode allows you to resolve
conflicts when pulling or
merging a branch.
Xcode will present a sheet
similar to the commit sheet with
options to take your change, or
the other change.
It is also possible to manually
edit the file, or take both
changes if there are better ways
to combine the work.
In this case, we see that two
users have both made changes on
the same line.
It seems that the local changes
are a bit more up to date, so
the easiest way to resolve this
is to take the left changes.
Now, with all the conflicts
resolved, the pull can continue.
If this were a merge pull,
conflicts are all resolved at
once and the resolution is
stored in the merge commit.
If we were doing a pull rebase,
it is possible to have to
resolve a set of conflicts
multiple times as each
individual commit is replayed on
top of your coworker's changes.
The resolution information in
this case is stored on the
original commit as if it never
occurred.
Now, because conflicts can be a
bit annoying to resolve, it can
be very useful to anticipate
conflicts and avoid having them
happen in the first place.
In Xcode Source Control
Preferences, the Change bar can
optionally be shown to show
coworker's changes as they push
them.
This makes it easy to tell what
part of a file is out of date.
The changes are fetched from the
server at a 10-minute interval.
Here we see the Change bar that
we saw before, when upstream
changes are showing, turns to
red to indicate where our
coworkers have been making
changes.
This indicates a conflict will
have to be resolved to
reintegrate the local changes.
In many cases it can be easier
to pull before making changes to
a file that already has changes
upstream.
Some details about the
conflicting commit can be seen
by clicking on the Change bar.
All of the hosting solutions
supported in Xcode also support
two other common workflows, pull
requests and forks.
These are based on Git concepts
and features, but are distinct
from Git's feature set.
Pull requests are a method for
doing code reviews.
It is usually best practice to
do all disruptive work to a
project on a branch.
This is an isolated line of
commit history that is separate
from the other history of a
project.
Just like when pulling, the work
done on a branch will diverge
from the main branch of code.
So a merge will be necessary to
resolve any conflicts and
reintegrate the work.
A pull request, shown here in
yellow, is a way to see what
will be merged and allow the
commenting on that work by other
individuals.
Often this will mean making
additional changes on the branch
before merging and integrating
it.
Since pull requests are built on
Git's branching model, you can
always locally check out that
branch from the source control
navigator in Xcode when
reviewing it.
This lets you build and test the
work on your local machine
before approving it and merging
it back into the main branch.
Forks take advantage of the
distributed nature of Git.
Just like how the server copy of
the repository and the local
copy on your machine are two
copies of the same repository,
you can create multiple copies
of a repository on the same
server.
This is often useful when there
is a canonical copy that is
tightly managed, such as a large
open-source project.
A fork can be useful for making
experimental changes without
disrupting the main copy.
This can be more useful than a
branch when there are many
contributors, because each fork
can have its own named branches,
minimizing the amount of noise
in the main repository.
Just like the local copy, the
fork can be synced with the main
copy.
This is often done in the form
of PR's and is where pull
requests get their name.
Xcode and Git allow setting
multiple remotes on your local
repository.
So you can sync with both the
name and the fork from the same
local copy on your machine.
So that covers the basics of
using source control and Git in
Xcode.
We've seen how to use Git
locally to manage your project.
We've taken a look at making and
viewing changes in your project.
We also saw how repositories can
be hosted and changes
synchronized when working with
teams.
And when syncing those changes,
how you resolve and even avoid
conflicts.
And last, we took a brief look
at some additional hosting
features like pull requests and
forks.
More information for this
session is available at
Developer.apple.com.
And thank you.