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.
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:
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:
The download will hold all of the history up to the pause point but nothing beyond it.
The download will hold only the events that are needed to recreate what is on the screen at the pause point and nothing more. For example, any code that was added and then deleted before the pause point will not be a part of the downloaded repository because it is not on the screen at that time.
The download will hold all of the history regardless of the pause point but will also include events to 'undo' the code to get it back to the state of the pause point.
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 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.
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.
.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.
Here is an example that has branching and merging in it. These are the steps that happened in this example: