139

Storyboards are rather a royal pain from a git workflow perspective when multiple people are collaborating on them. For example, the XML in the .storyboard file has its starting <document> tag's toolsVersion and systemVersion attributes altered by whatever configuration the most recent file manipulator happens to be running. Synchronizing everybody's Xcode versions precisely seems to help with toolsVersion, but systemVersion changes no matter what, depending on the specific Mac and/or OS X version the developer is running.

This is idiotic, but mostly harmless. What worries us, though, is that at other times some other changes are automatically made to the storyboard just by opening them after a git pull. That is to say, Alice makes changes to a storyboard, commits and pushes them to the repository. Bob then pulls Alice's changes and opens up the storyboard to make further changes. The moment he opens the storyboard, the file icon immediately changes to a modified-but-unsaved state, and a git status shows that any number of weird changes have occurred. All this without Bob having changed anything or saved the file himself.

The most common automated change we're seeing is the disappearance or reappearance of the entire <classes> tag hierachy near the end of a storyboard file. We haven't figured out what is causing this. We may have several localized versions of a storyboard in various .lproj directories, and when opening them inside Interface Builder, the class hierarchy may spontaneously be removed from some and added into others, or left alone in some. This causes a lot of noise in git diff, but it doesn't actually break any functionality. We will often selectively add the actual changes we made into git's index, commit those, and then just discard the spontaneous, nonsensical <classes> changes. This is to keep commits small and nice, as they should be. Eventually, though, it just becomes too much to bother with since Xcode keeps re-doing the changes, and someone just ragecommits them along with some other stuff... which is fine until someone else's Xcode decides to want to change them back for no apparent reason. (Our commit history has a lot of swearing over this.)

Is anyone else seeing this behaviour? Is this an Xcode bug or a configuration issue on one or more of our developer Macs? We've seen some similar behaviour when collaborating with XIB files, but storyboards seem more susceptible to this.

6
  • Indeed the Xcode projects and Git are not doing very well together. I don't think you can avoid this mess other way than discarding the changes which are unnecessary - that are almost always the project files changes for me and other xml files I'm sure I've not changed. Will be glad if there's any sort of 'solution'. I like Perforce for convenient lock functionality not allowing Xcode to change too much, that probably might be done manually for the files that you are not going to change but only to review.
    – A-Live
    Commented Nov 5, 2012 at 13:43
  • 3
    Not worth using storyboards with git or anything else. THey are not designed to be commit friendly. We gave up and went with .xib which isn't all that great either but at least it's granular.
    – ahwulf
    Commented Nov 5, 2012 at 14:30
  • We've found storyboards pretty neat for quite a lot of things actually, though it is often necessary to mix them with XIBs. If this bug ever gets fixed, we'd be quite happy working with them the vast majority of the time.
    – JK Laiho
    Commented Nov 6, 2012 at 7:11
  • I just have to comment on ahwulf's comment: what in the world do you mean they are not commit friendly? They are XML/text files, thats about as commit friendly as you can get. And i have had 'no' problem with the storyboard's and a versioning system, the only problem is of course that xcode sometimes deletes the <classes> tag and then readds it later, but you can see this easily if you look at the changes with a git GUI or git -p or equivalent for whatever dvcs. I have never had this happen with the .pbxproj file as a fyi.
    – mgrandi
    Commented May 24, 2013 at 4:56
  • I can't understand why xcode put the classes blocks inside the storyboard if he can just generate those blocks by reading the classes files? are they a sort of "cache"? if so they should be put in a classes.cache file so we could exclude it from the versioning... Commented Jun 9, 2013 at 21:59

6 Answers 6

84

This is not a bug, this is a consequence of how Xcode processes storyboard files. I am writing a diff and merge program for storyboard files (GitHub link) and I have spent hours analyzing the storyboard files logic and how Xcode processes it. This is what I discovered:

  • Why do weird changes occur in storyboard files? Xcode uses the NSXML API to parse storyboard files into some NSSet-based logical tree structure. When Xcode needs to write changes it creates an NSXMLDocument based on the logical tree structure, clears the storyboard file and calls XMLDataWithOptions: to fill the file again. Because sets do not preserve the order of their elements, even the slightest modification could change the whole storyboard XML file.

  • Why does the class tag disappear or reappear randomly? The <class> section is nothing more than an internal Xcode cache. Xcode use it to cache information about classes. The cache changes often. Elements are added when class .h/.m files are opened and removed when Xcode suspects they are outdated (at least older Xcodes behave like this). When you save the storyboard, the current version of the cache is dumped, which is why the <class> section often changes or even disappears.

I have not reverse-engineered Xcode; I made these observations by experimenting with Xcode and storyboard files. Nevertheless, I am almost 100% sure it works this way.

Conclusions:

  • Cache section is unimportant; you can safely ignore any change in it.
  • Contrary to what you can find on all forums, merging storyboards files is not a complicated task. For example, let’s assume you changed MyController1 view controller in a storyboard document. Open the storyboard file, and find something like this <viewController id=”ory-XY-OBM” sceneMemberID=”MyController1”>. You can safely commit only changes in this section and ignore everything else. If you changed segues or constraints, also commit anything that has “ory-XY-OBM” inside. Simple!
13
  • 9
    Any update on the xcode diff / merge tool? Sounds like it'll be super useful for this community.
    – Tony
    Commented Oct 16, 2013 at 8:03
  • 1
    You could get the app from my web page (see profile). The app is 100% free. Commented Oct 24, 2013 at 10:36
  • 1
    For me spliting storyboards as much as possible == using XIBs. If you want to have everything sliced, it easier and better to use XIBs Commented Jun 12, 2014 at 13:00
  • 7
    "I have not reverse-engineered Xcode; I made these observations by experimenting with Xcode and storyboard files." That is (shallow) reverse-engineering, and it's cool. :-) Commented Sep 22, 2014 at 12:17
  • 20
    "This is not a bug, this is a consequence of how Xcode processes storyboard files. " Respectfully, the 2nd half of this sentence in no way explains nor rationalizes the first. I'd amend it to: "This is a bug. It is a[n unfortunately unresolved and highly annoying] consequence of how XCode processes .xib files." From XCode 5.x through 6.2 (today, 150311) .xib files in no way modified by the developer, merely viewed in IB, suffer gratuitous xml changes. This is a gross bug that impacts productivity. Responses like "NBD, just deal w/ chunks in git" leave me speechless.
    – cweekly
    Commented Mar 12, 2015 at 2:48
19

This is a bug in XCode 4.5+, I hope it gets fixed, and yes its a PITA.

Here's the full bug at Apple

How to avoid Xcode gratuitous edits to storyboard files?

9
  • 1
    Same thing in 4.6. Maybe it's not a bug.
    – Thromordyn
    Commented Mar 22, 2013 at 13:02
  • 4.6.3 still has it. Can't say that storyboard/xibs ever worked well though
    – houbysoft
    Commented Jul 15, 2013 at 19:53
  • 1
    "It's not a bug, it's a feature" :-S
    – MrTJ
    Commented Jul 19, 2013 at 7:53
  • There is no evidence that this is a bug - an annoyance yes, but it might just be how Xcode does stuff Commented Aug 19, 2013 at 14:59
  • 1
    7.0.1 has not brought any changes to this. Commented Oct 13, 2015 at 18:05
11

This issue can be mitigated somewhat by extremely judicious use of git add -p on any of Xcode's generated files, including storyboards, XIBs, Core Data models, and project files, all of which suffer from similar transient modifications that have no impact on the actual interface/model/project.

The most common junk changes I've seen on storyboards are the system version numbers (as you mention) and the constant addition and removal of the <classes> section, the omission of which I have never seen cause problems. For XIBs, it's the addition and removal of <reference key="NSWindow"/>, which isn't even a class in Cocoa Touch. Just wow.

Think of it like the sea: there is both a high and low tide. Let it wash over you.

Ahh. That's it.

You can ignore these modifications when staging your changes, reset the junk changes, and make a clean commit.

The single advantage I've seen with storyboards over XIBs from a technical standpoint is that Apple has not yet neutered FileMerge to refuse to merge conflicted storyboards. (FileMerge used to be able to merge XIBs, but newer versions broke that. Thxxxx guys 💜!!!)

Please file lots of bugs about all of these problems at http://bugreporter.apple.com/! And don't forget to create entries on OpenRadar.

6

Throwing on another answer here because this situation has improved greatly. The XML for the XIB file that represents the StoryBoard has been greatly simplified.

I have also recently bitten the bullet and started to use the interface in Xcode to Source Control. I have been on the command line for years and happy there, but the interface is nice and it lets you split commits, which is really important if you use a ticketing system that links to commits.

Anyway, I noticed today that there was a change on the storyboard and the built in diff showed me it was a single attribute in the document tag (systemVersion). So not a big deal.

I have read articles where people say SBs were outlawed on their teams because of merging issues. Total madness. They are so amazing, especially now that they have intelligent autolayout built in, you are really missing out if you are not using them.

3

It's helpful to know why this insanity is happening, but for those who believe in keeping their projects free of warnings and who just want a quick-and-dirty to get their projects back to a healthy state:

  1. Don't commit anything until explicitly instructed.

  2. Open Xcode and create a new storyboard (Command+N > iOS > User Interface > Storyboard). I'll assume you call it the default name of Storyboard.storyboard.

  3. Open the storyboard that Xcode has violated. I'll assume this is Base.lproj/Main.storyboard.

  4. Select and copy everything on the storyboard (Command+A then Command+C).

  5. Open Storyboard.storyboard.

  6. Copy and paste everything into Storyboard.storyboard.

  7. Close Xcode.

  8. Open a terminal and change directories to your repository.

  9. Replace Main.storyboard with Storyboard.storyboard (mv Storyboard.storyboard Base.lproj/Main.storyboard).

  10. git add Base.lproj/Main.storyboard; git commit -m "Fix Xcode's insanity."

  11. Disregard the changes to project.pbxproj via git checkout -- project.pbxproj. If you git diff the file, you'll see that it has just added information about our temporary storyboard (which no longer exists).

  12. Open Xcode back up and see that the warnings has disappeared.

  13. Breathe.

0

Working on same storyboard is not a problem. But working on same viewcontroller which creates conflicts on pull/merge is frightening. we can not really avoid that working in same viewcontroller for a large team.

Good thing is, most of the time we can fixed the same viewcontroller conflicts if we understand the xml structure. I never failed to merge these while working in team. Suppose you are working with a viewcontroller. Your view is blank currently. Please ,have a look at the viewcontroller's xml structure from source code option.

enter image description here

Storyboard is xml bounded by document type tag. Everything in the storyboard contains in scene sceneID= tag. scene tag holds every viewcontrollers. Thats the basic.

Now we added a UILabel and a UIButton on the view. Also set the autolayout of the elements. Now it's looks like :

enter image description here

Adding a level/button to viewcontroller added some new code inside the subview tag of the view. Same thing will go for further element addition or any UI changes. Carefully check the tag structure which is really important to fix any conflicts.

Now we add another viewcontroller in the storyboard name Homeviewcontroller. Adding a new viewcontroller means it adds a new scene under scenes tag. Look at this:

enter image description here

At this point, we will change the structure randomly and observe the issues/warnings. We change first viewcontroller label end tag and save the file. Now run it and look at the warning. Error says end tag is not correct which created from line 23. In line 23 , we see a label constrains is set with no end tag. That's the problem. Now we put the end tag and build the project. After setting end tag, we can view the storyboard successfully.

enter image description here

When face any warning of conflicts , please compare with your previous source and changes source. We remove the old/redundant code , keep the new code with proper tag start-end and get things fixed.

[N.B , i will update the answer with some more test cases when get times]

Not the answer you're looking for? Browse other questions tagged or ask your own question.