Source control in the development procedure is not a luxury, it is essential. Don't think of it necessary only when you work in a team. Pick up good habits early and apply it even if you work alone. It will enhance your work quality and sometimes it will become your saviour. This article will only scratch the surface of this subject. However,it can be a good summary or cheatsheet for some useful and essential commands.
Xcode, since version 5, integrates source control using Git system. You can manage source control using the Xcode IDE for many actions but sometimes you will need to use terminal commands for some more advanced actions yet essentials.
At the beginning, lets configure git with our name and email. This is the info that will identify us as contributors in the source control system. Open the terminal and type the following commands giving your details:
git config --global user.name "yourName" git config --global user.email "yourEmail"
git in a new or existing project
When you begin a new project, in the second drop-down window where you select the save location, you simply enable the source control in the lower part of the window (fig.1).
What if you have an existing project and you want to add source control?
Easy but...you cannot do it using Xcode IDE. Turn to terminal again and navigate to the folder that contains the project. If you execute ls -la you will find the nameOfProject.xcodeproj file and the nameOfProject folder and only those. Nice!
First execute the command:
The response will be:
Initialized empty Git repository in /Users/angelos/Documents/myCode/nameOfProject/.git/
That means that the infrastructure is ready, although it is empty. Since we have git set up, the useful command to retrieve the status of the system is the following:
If we do this, the response will be:
On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) nameOfProject.xcodeproj/ nameOfProject/ nothing added to commit but untracked files present (use "git add" to track)
This informative message tell us that we have to add the files to git in order to be trackable or in other words using the git slang to stage them. Before following the suggestion and adding the files for tracking are you sure that everything is needed to be tracked?
No, these folders include files that you don't need to include in the source control system. For instance, .DS_Store, or Xcode's setting files like xcuserstate. To exclude these files from tracking you need to add a file .gitignore in the project's folder containing all these cases. You can visit github's repository which offers a wide range of .gitignore files depending the language. So, download the appropriate file, rename it to .gitignore, if it is different, and you are ready to add!
Type the following command to the terminal:
git add .
Perfect, now all the wanted files are staged in git. But wait! You haven't finished yet. In order to secure your files and register every change you have to commit. This is easy to do by typing the following command:
git commit -m "Initial commit"
Now we are done. You can check using git status and get as response:
On branch master nothing to commit, working directory clean
to Commit or... discard?
As you develop you code, after every important feature you add or a bug-fix or whenever you decide that is necessary...you have to secure your changes by performing a commit. You can either use the Xcode's menu Source Control/Commit... or the keyboard shortcut alt+cmd+c. On the other hand, if you decide that whatever you changed to a file is wrong and you want to revert to the last commit, you have to select the specific file from the project navigator, right-click and Source Control/Discard changes.... In case that you have broken code in more than one files, select from Xcode's menu Source Control/Discard All Changes...
Sometimes after some hours of work, you realise that something is wrong and you need to change something that you have already committed to git. This time the discard changes option cannot help you. In order to cancel the most recent commit, we have to type in the terminal the following command:
git revert HEAD
When you press return in this command, the vi editor will open automatically so as to write a reasonable message for the revert as you did previously for the commit.
What is HEAD? HEAD is a reference to the currently checked out commit.
To get an overview of the process since the first commit, you can type the following command:
or from Xcode's menu select Source Control/History...
Unfortunately, sometimes you realise that you have to revert in an older commit than the last one. Git is here for the rescue. The procedure is simple. Open the history window of your project's Source Control. In this list you will discover that each commit has a unique hash number assigned. Copy the hash that corresponds to the desired commit and execute the following command:
git reset --hard ef37e2f2ce95
Note: The previous apply for local repositories, if you have local and remote the procedure is different.
Branches is a powerful feature of git. Till now we had only one brach, the master branch. This is supposed to be the stable version of our code. If we want to add new features, fix reported bugs, or experiment with some new ideas is always better to make a new branch and work on this leaving the master one untouched. If everything goes fine, then we can merge and have a new master branch enhanced with the new features.
To create a new branch locally, we have to select from Xcode's menu Source Control/Working Copies/New branch.... After that, type an explanatory name in the text box and automatically Xcode has switched into that.
To switch to a different brach is very easy, select Source Control/Working Copies/Switch to Branch.... After that, in the drop-down window tap to the desired branch. No surprises...
In case that you no longer need a brach you should delete it. First of all, you should switch in a different branch than the one you want to delete. Then from Xcode's menu select Source Control/Working Copies/Configure... and from the drop-down window tap to the third tab called Branches. Finally, select the branch for deletion and click to the minus sign at the bottom of the window and... done!
get a remote project locally
Many times there is the case where you join a team and you should get the project to start working on it. Usually the project will be a remote repository on github (or a similar service). It is extremely easy to get the remote repo to your local machine using Xcode. Start Xcode and go to Source Control menu. You will discover that only Check Out.. is enabled. Click on it and you will get a drop-down window. If it is the first time that you access the remote repo, just copy the given SSH URL and press next. The following window shows the available branches. Choose wisely and in few moments the selected branch exists locally on your machine.
going public...or push to github
Working alone has no joy, sharing and working as a team can produce better results. So, consider the scenario that you have a local project and you want to upload it in github in order to share it with your mates. There are two steps for this:
1. log in to github and pair your mac using ssh keys. Follow this guide if you don't know how to do it.
2. create a new repository without gitignore and readme. Then, copy the SSH URL from the repository's setup page.
Back in our mac now. Select from Xcode's menu Source Control/Working Copies/Configure nameOfProject.... In the drop-down window select the middle tab, Remotes and then click the add sign by selecting the Add Remote... option. In the following window, type a name and copy the SSH URL to the address text box.
Now, everything is set up for uploading or in git slang... push! Select from Xcode's menu Source Control/Push... and then from the drop-down window select the desired branch or the master branch for this time. If you check your github repository, you will find you code published as it is in your local repo!
getting the remote changes to your local copy... or just pull
In this case we are going to perform the opposite from push. This procedure in git is called pull. It is as easy as selecting from Xcode's menu Source Control/Pull... and then from the drop-down window select the specific branch you want to pull. This means that if there are changes remotely, you will have them from now on in your local copy.
merge vs rebase
Merge and rebase are essential commands for every git user. There is no conflict between them, they are used for different tasks. When you have branch the master and work a nice new feature, eventually you completed the tests and realise that functions perfect. At this point it is the correct moment to add this feature to the master branch (fig.2). This is very easy. Depending on what branch you currently work, you should select from Xcode's menu either Source Control/Working Copies/Merge Into Branch... or Source Control/Working Copies/Merge From Branch.... In both cases, before the actual merging you will get a drop-down window with two panels. Each side displays a branch. By adjusting the switches you select from which branch you will use the corresponding code.
Now, consider the following case. You have made your own branch and work on a new feature. Meanwhile, a teammate has fixed a critical bug and the master branch is updated. At this point you don't want to merge but it will be desirable to get this bug fix. The solution is to rebase. Doing this you will get from master branch the new updated commit as a base instead of the old erroneous one (fig.3).
Unfortunately, you cannot rebase using Xcode. So, open your terminal and change to the project's directory. Then type git status
and you will get as response:
On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working directory clean
Nice, imagine that your personal branch that you want to rebase is called myNewBranch1. First, you have to switch on that using the terminal. Type: git checkout myNewBranch1
and the response will be:
Switched to branch 'myNewBranch1'
Next type git rebase master
and success! The response will be:
First, rewinding head to replay your work on top of it... Applying: appDelegate update1
Switch back to your Xcode and you will discover that the bug-fix commit of the master branch called "appDelegate update1" is already integrated in your code base in myNewBranch1.
Be cautious that all the merging and rebasing that you did refer to your local repository.
Now it's time to move on and experiment before you actually use these feature in your projects. Build a sample project and experiment. You can get the basic functionality using Xcode but you can do a lot more using terminal. Git is your friend!