Version Control

A version control system allows multiple developers to work on the same set of files at the same time without interfering with each other. Each developer downloads a copy of a 'repository' (a directory with files that are tracked) so that they can work in isolation from everyone else on the team. The version control system keeps track of different versions of a team's code in its different states (for example, it is important to store the code right after Alice completes and tests a new feature).

With most version control systems the developer must choose a time to commit their code to it. This is like taking a snapshot of the code at a particular point in time. It records all of these snapshots at the commit points. It can also be used to merge two or more developer's code together and revert to a previous snapshot, for example to fix a bug, with relative ease.

Version control systems are an important tool for working on a team. Version control systems like Git have a reputation for being hard to understand and use. Storyteller was created, at least in part, to make it easier to do simple version control.

Storyteller does not require a developer to choose a point in time to 'commit' their code. Since it is always recording the state of the files, the entire history is stored. If Git stores snapshots then Storyteller stores moving pictures.


Branching

The fundamental operations in a version control system are branching and merging. Branching is the act of making a copy of a repository that can be edited by a developer that won't affect any other developer's copy. When someone downloads a playback in Storyteller they are creating a branch. There are different options to perform a download:

Download types

Each one of these options makes a copy of a Storyteller repository but each does it differently. The downloaded zip file includes a directory called .storyteller that holds the data necessary to playback the history of the system. There are different options to store different amounts of history from the playback:

After the playback has been downloaded and unzipped a developer can use Storyteller in their editor to make changes to the code. These changes will become part of a new branch. This provides a way to build off of a playback that will not interfere with anyone else's branch.


Merging

Merging is the act of bringing two branches together into a new, combined repository. Sometimes there is a 'main' branch which holds the latest and greatest version of a team's code. A typical flow for a developer is to create a branch from the 'main' branch, make changes to add a feature or fix a bug, and then merge those changes back in to the 'main' branch. This process is then repeated by all of the developers, often concurrently.

The only problem with this approach is that if there are two or more developers working on branches at the same time they might each be making changes to the same parts of the same files. When two branches include changes to the same line in a file this is called a conflict. For example, Bob might rename a variable on line 20 of main.cpp in his branch and Alice may set a different initial value for that variable on the same line in her branch. If this is the case then there is a conflict that needs to be resolved by the two developers who created it. There is no way that the version control system can figure out what the combined code should look like automatically.

Version control systems can identify which changes are in conflict and which are not. For the changes that are not in conflict with each other (like when Bob changes line 100 and Alice changes line 200) the version control system will simply add both of them to the new branch. If there is a conflict, most version control systems add the changes from both branches and identify which branches they came from. The developers then have to work together to resolve which code should stay and which should go. In Bob and Alice's case this may be an easy discussion. Other times it is not so easy but this is where having good communication on a team helps.

It turns out that this is a relatively rare occurrence. Most of the time when two developers are working concurrently there are no conflicts. However, since it occassionally happens a version control system needs to be able to help the developers resolve their conflicts.


Merging in Storyteller

Merge

After a branch is made from downloading a playback a developer can use their Storyteller enabled editor to open the project. Next, they can make changes to the code. Afterwards, if they want to merge in another branch (perhaps the latest and greatest version of the 'main' branch with Bob and Alice's most recent changes in it) all the developer has to do is create a playback in the browser with their version and then hit the 'merge' button (which is next to the download button) and choose a playbackData.json file from another Storyteller repsotiory to merge into the playback.

The directory .storyteller that is in every downloaded playback contains a file called playbackData.json. This file holds all of the historical events and comments in the playback. The events in this file are merged into the events in the playback.

All of the non-conflicting events are added to a new playback. The conflicting events from both branches are added to the playback and are surrounded with code that identifies which branch they came from. The playback can be replayed to see how they merged together. If the developer likes the merge they can download the playback and then work from it. If there were conflicts the developers will need to resolve them in this new Storyteller repository.


Branch and Merge Example

Here is an example that has branching and merging in it. These are the steps that happened in this example:

  1. A developer, Alan T., created a Storyteller repository, added a file, and put some well known quotes in the file. Here is a playback of Alan's work.
  2. Another developer, Mark Mahoney, watched a playback of Alan's code and downloaded it. He then unzipped the downloaded file and opened up the Storyteller repository in his editor to fix some of Alan's misspellings. Here is a playback of Mark Mahoney's work.
  3. Another developer, Mark M. (there are a lot of Marks around here), watched a playback of Alan's code and downloaded it. He then unzipped the downloaded file opened up the Storyteller repository in his editor to add some embellishments to Alan's quotes. Here is a playback of Mark M.'s work.
  4. Mark M. then decided to merge his changes with Mark Mahoney's. Mark M. hit the merge button and then selected Mark Mahoney's playbackData.json file. Storyteller then merged the two Marks' changes together. The merge produced one conflict in the file that has to be resolved by a human. There were some other changes that were not in conflict and they were added to the playback.
  5. Mark M. downloaded the merged playback with both Marks' changes and sent it to Alan.
  6. Alan then unzipped the downloaded playback and opened up the Storyteller repository in his editor. Alan worked with the two Marks to come up with a final version that involved all three developers' changes.
  7. Finally, Alan built off of the merged text and added another quote. His version now has the latest and greatest changes from the team. Here is a playback with all of the work together. Anyone can download this playback and get the history of the system.


Questions? Comments? Corrections? Contact the BDFL