A good conceptual model is the key to using any tool effectively. In order to use a version control system, or even understand how it can be useful, you will need to develop a conceptual model. For programmers, coding something yourself is a very effective way to develop a conceptual model of how it works – a model that you can feel. This fun activity will help you develop a conceptual model that will make learning a complex tool much simpler.
Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later.
From the git book section 1.1.
A Version Control System allows you to keep track of your code, view different versions of your code, switch between versions, maintain different versions of your code, and share your work with other programmers.
Before we start building one, we need to have some basic concepts:
In this activity, we will keep things simple by adding another directory,
.vcs – this is where we will keep the code of our vcs so that we can easily reference the scripts we create. Ordinarily your VCS is a software packaged installed on your operating system, so you just run it as you would any other linux command. But we don’t have time to mess with the $PATH variable and such, so this is simpler.
If you crave a top down understanding, here’s a basic outline:
A version control system will allow us to save snapshots of our code, creating a history that we can navigate back and forth through. We can tag snapshots so they are easier to find. We can also create parallel branches of code, so that we can try things and discard them later (or so that multiple people can work in parallel). Branching necessitates merging, and we will keep our project simple by stopping the train before we start trying to merge code. But having done all the other things will give you enough of an idea of how everything else works that you will be able to appreciate the complexity of the merge process. And the magic necessary to make it smooth.
We will start our version control system with the basics – saving code. In order to do that, we’ll have to detour through setting up a repository. From there we will figure out how to jump around in the history. Once we can jump around, tagging will be a simple extension. Then we will come to figuring out how to do branching… which is deceptively complex in its own right. :) And once you’ve finished branching, you’ll be ready for Git.
Download the initial project files, and follow the instructions in the README. The project includes some test scripts that you can use to verify that your scripts do exactly what they are supposed to. A (mostly blank) file has already been created for each of the scripts you will need to write, and the test script will also make sure they are all executable.
The main instruction you will need is: run the tests with
The first thing you would want to do with a VCS is save your code regularly. (Not just save your files, but save the entire set of your project’s files). But we need a place for saving code, and a system for saving code.
init script is the beginning of any VCS project.
The goal is to type
vcs-init.sh <directory>, and have your repository set up.
vcs/vcs-init.sh script that will do the following:
.repo, exit with an error.
.repoinside the target directory. This is where the code will be saved, and where we will also keep other vcs files that help us manage the saved code.
.repodirectory, create a directory called
refs. This will come in handy later.
.repo/refsdirectory, create a directory called
tags. This will come in handy later.
.repodirectory, create a directory called
snapshots. This will store the code.
The first thing you want to be able to do with a VCS is to save code. We’re going to call these “snapshots”, and we’re going to save them to our
The goal is to be able to run
vcs-commit.sh in your working directory and save a “snapshot” to our
vcs/vcs-commit.sh script to do the following:
.repo/snapshotsnamed with a number, indicating which snapshot we are creating. For your first snapshot, the directory name should be
1, the next
2, and so on.
--excludeoption, as well as other options that will make this task incredibly simple. ;)
.commitin the snapshot directory that contains metadata about the snapshot:
vcs-commit.sh "I don't know why but this works so I'm committing it before it breaks again".
##Finding code It’s somewhat useful to be able to save snapshots easily, because I can explore the snapshots directory if I want to find an old version of a file after I’ve broken something. But it’s a little tedious to try to find which snapshot has what I’m looking for. So let’s create a script that will let us scroll through all the commit messages.
Start by creating a “history viewer”. We’ll call it
This script is really simple:
Here’s some sample output (from commits made by the test script, hence they’re all the same time…)
snapshot: 1 user: ryan time: Sat Oct 14 15:18:22 EDT 2017 message: snapshot: 2 user: ryan time: Sat Oct 14 15:18:22 EDT 2017 message: snapshot: 3 user: ryan time: Sat Oct 14 15:18:22 EDT 2017 message: snapshot: 4 user: ryan time: Sat Oct 14 15:18:22 EDT 2017 message: this is a test message!
We sometimes want to “bookmark” certain commits. This is really simple – we create a script that creates file in the
.repo/refs/tags folder that references our current checked out snapshot.
Objective: I can create an alias for snapshot 4 by running
.vcs/tag.sh 4 test, it will create a file in the refs directory named
test that links to
Write a script called
refs/tagsdirectory that named for the first parameter and linking to the snapshot whos id is given in the second parameter.
vcs-log.sh to list tags as well as snapshots in the output. (Note this output will be somewhat redundant as a snapshot that is tagged will be listed twice, but it would be quite complicated to make the tags list next to their respective snapshots).
.vcsignorefile, the commit script will not include files referenced by the
.vcsignorefile in the snapshot.
.vcsignorefile that contains two lines, one with
buildand another with
.blob, then, when I create my snapshot, if there is a directory named
build, I won’t copy that directory into the snapshot. Likewise, I will ignore a file named
This activity is much more limited in scope than I’d hoped it to be (much to the relief of all students assigned the task). To get a sense for where this would go, read the article that inspired the activity: “The Git Parable” by Tom Preston-Werner.
We haven’t implemented some of the more complex features that would make this tool powerful, but we don’t need to. There is already a professional tool that we can learn that has all the complex features. However, you could use this system to back up your projects. Explore the
.testing_temp directory after you run a test to see how the system looks on your hard drive. Also feel free to play around with it on other projects. Although once you’ve learned git, you won’t want to.