Quick branch switching without confusing Xcode
15 Nov 2020Xcode doesn’t always like it when you swap branches, especially when there are a lot of code changes between the branches. This can cause all kinds of build caches to become invalid forcing your Xcode to do lots of work. What’s worse is now your mental resources are concentrated on getting your project compiling again instead of solving interesting problems.
The work I’ve been doing recently has been very bitty with helping colleagues by jumping on screen shares, reviewing PRs or even finding new requirements in my tickets that need work playing before I can continue. All of these scenarios require me to checkout a different branch, which leads to the problems mentioned above.
Solution
Use git worktree
to get multiple checkouts of a project using a single git repo.
If I have a project called epic-todo-list-app
and a colleague asks for help on their branch named feature/allow-users-to-complete-tasks
, I can run the following command:
git worktree add ../epic-todo-list-app-tmp feature/allow-users-to-complete-tasks
Now on disk I’ll have both projects
ls -1 src/ios
epic-todo-list-app
epic-todo-list-app-tmp
The original project folder will just be my repo in whatever state I was in.
The new project folder epic-todo-list-app-tmp
will have the repo checked out to feature/allow-users-to-complete-tasks
.
At this point I can now open both projects independently in Xcode and they’ll have their own derived data, which means I don’t need to deal with the time sink of getting Xcode to compile the new branch and then my original branch when I switch back.
NB - this technique is really helpful when working with different Xcode versions. I can have one checkout for the beta and one for the GM version and they won’t destroy each other’s derived data.
Why use git worktree
?
I’ve been using a variation of this technique for a long time now where I was just keeping multiple complete copies (full clones) of the repo. This isn’t great for a few reasons:
- This is wasteful if you have a repo with a large history as you have two complete copies of the history
- The repos are independent - changes made in one are not reflected in another (unless you push/pull using local paths [not everyone knows you can do this])
- It’s really easy to
git fetch
on one copy and forget to fetch on others so you end up with inconsistent states
git worktree
solves the above problems by the fact that each project folder is backed by the same git repo on disk.
So any operations like fetch
, checkout -b
, merge
…. are all reflected in each place you invoke git
.
Cleanup
Once you’ve finished with the worktree you can easily remove it using the remove
command.
If I wanted to get rid of the worktree I created earlier I’d call
git worktree remove ../epic-todo-list-app-tmp
It’s worth exploring the docs as they aren’t long or too scary looking https://git-scm.com/docs/git-worktree.