Web Development With Source Code Management A Basic Guide

9 minute read

This is a seriously old post. I’d probably not bother reading it, but I keep it here for nostalgia.

Web Development With SCM Basics

Pre-Amble

I remember when I first started development. Even more fun was doing the same but over a remote ftp connection through Transmit, or just directly on the server. I got used to pretty GUI’s doing things for me and visually feedback for whether I’d got it right. Oh, how things have changed. My work flow was:

  • Make changes to my code
  • Flip to my browser and refresh
  • See what I’ve done has changed
  • Go back to my code and make more changes
  • Go back to my browser and refresh
  • See I broke stuff
  • Go back and try fix it
  • etc.

I want to take you through how a basic version of what I do now, and the benefits of what I do. I have confidence in my changes and a general feeling of happiness that I’d like to pass on to you. Whether or not I work in a team, I use distributed version managed code to do so. Any changes I make locally are pushed to a remote computer, why? What if my hard drive failed or I’m working on another machine for the day, you never know. Either way, I have access to my code, including all the changes I’ve made.

Why was my initial plan inefficient? Well, it was brittle and to test everything meant looking at all the pages sequentially. Making changes in one place might affect another and I had to double check it manually. Also, the changes I made weren’t reversible. I worked around that by saving multiple copies of my files or folders, keeping old version of sites hanging around so I could always revert back if I wanted. This just doesn’t scale.

What’s the alternative? Source Code Management. There are many systems around and I’ve certainly used a myriad of them, but I’ve settled on git which makes me warm and fuzzy inside. Git was developed initially by Linus Torvalds to manage the complicated process of building a Linux kernel in a distributed manner (multiple people, multiple places editing one set of files). Quick list of benefits we’re interested in:

  • Revert changes without saving different versions manually
  • Develop multiple version of your site concurrently
  • Log changes you’ve made without a separately managed log file

Enough talk, let’s just run through what I do. I use Ruby on Rails and Sinatra for web development, but this will work with most languages too, if not all.

Getting Setup

Create a new project in your tool of choice, I’ll create one called ‘scm_project’ with Ruby on Rails:

1
2
3
4
5
$ rails scm_project
create
create app/controllers
...
create log/test.log

This is just a plain old Ruby on Rails project, but it could be anything for you, even just a folder with some php files. We need to initialise the folder with our source code manager ‘git’.

1
2
3
$ cd scm_project
scm_project $ git init
Initialized empty Git repository in /a/demos/scm_project/.git/

So git has set up our folder as a version managed folder. We can now, for example, ask git for the status of this folder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# README
# Rakefile
# app/
# config/
# doc/
# log/
# public/
# script/
# test/
nothing added to commit but untracked files present (use "git add" to track)</pre>

Don’t worry, this is nothing scary. It’s just telling me that this folder has some unmanaged (‘untracked’) files. Source code managers need to told which files they’re managing. In this case we just need to tell git what to add and what to ignore. Some things shouldn’t be added, for example a database credentials file. If you have multiple people on a project and you all have your own local database server, then there’s no guarantee that the access details are the same, so by leaving it out (telling git to ignore it) it will never be added and everyone can have their own version without it affecting others.

Let’s set up our file ignore list. Create a file in the root of that folder called .gitignore and put in contents like this:

1
2
3
4
5
6
7
8
log/*.log
tmp/
.DS_Store
doc/api
doc/app
doc/plugins
db/*.sqlite3
config/database.yml

This is my base .gitignore file, you can add to this later as you go. The idea is that anything you don’t want version managed, you add to this file.

Next up, we need to tell the version management to add all files.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git add .
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: .gitignore
# new file: README
...
# new file: test/performance/browsing_test.rb
# new file: test/test_helper.rb
#

So by running git add . we’re telling git to add everything within this directory. . means ‘this directory’ in linux talk. That’s easy enough. Adding files to git means you’re telling it what you want to store in the system, but you need to ‘commit’ them too. Committing the changes that you’ve racked up tells the version system to store them.

The pattern is generally to rack up related changes, and then commit them with a message that logs those changes. In the future you can look at those logs and see what changes were made, even over multiple files, because of the way you add them.

The changes I’ve added here are simply adding a bare project, so I’m going to commit them now with a relevant message.

1
2
3
4
5
6
7
8
$ git commit -m 'initial bare rails project'
[master (root-commit) a085392] initial bare rails project
 41 files changed, 8438 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 README
 ...
 create mode 100644 test/performance/browsing_test.rb
 create mode 100644 test/test_helper.rb

After running the command, notice that git has told me how many insertions and deletions it’s accomplished. These are line counts. Where are we now? We’ve added the files we want the version management system to track, we can add more later, and we’ve committed the first set of changes to those files. Let’s hope through a few more changes and see what happens.

Making Changes

I’m going to change my application’s README file.

1
2
3
4
5
6
7
8
9
10
$ echo 'My New README' > README
$ git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: README
#
no changes added to commit (use "git add" and/or "git commit -a")

Our status shows me that I’ve got changes in the README but I’ve not added them to a commit. So this highlights an important fact, adding files to git doesn’t mean ‘add the file’ it means ‘add the changes’. Let’s prove this fact by adding our changed README.

1
2
3
4
5
6
7
8
9
10
11
12
$ git add README
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: README
#
$ git commit -m 'showing what modifying files that are tracked does'
[master b9b57e5] showing what modifying files that are tracked does
 1 files changed, 1 insertions(+), 243 deletions(-)
 rewrite README (100%)

Our status changed from ‘Changed but not updated’ to ‘Changes to be committed’. Changes can be over multiple files and be added in groups, what’s important is that when you commit those changes they must be relevant to each other. Notice also that git has counted the new lines I’ve added as well as the ones I deleted.

1
1 files changed, 1 insertions(+), 243 deletions(-)

The pattern I generally follow is:

  • Make changes for a feature or bugfix
  • Ensure my tests are passing
  • Add the changes for that commit
  • Commit them as a group describing what I changed overall

Some people like to describe it on a per file basis, but for me it comes down to a feature or bugfix. ’ why did I change it’, not ’ what did I change’. This is an important fact to note because the version manager is already logging ‘what’ changed, so all that remains is ‘why’.

Looking at Changes

What is it logging? Let’s take a look:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git log
2009-08-30 21:15:10 fearoffish ttys001
commit b9b57e53fa0bdcd29b14fb0ded6ab4355ef3cb92
Author: Jamie van Dyke <fearoffish@fearofpro.local>
Date: Fri Aug 28 23:03:31 2009 +0100

 showing what modifying files that are tracked does

commit a08539202e8bf908106e1736dabf588c3b367151
Author: Jamie van Dyke <fearoffish@fearofpro.local>
Date: Fri Aug 28 21:58:47 2009 +0100

 initial bare rails project

What we see is who committed changes, when, and what they logged as the message. You also get a reference id to the commit, which is a 40 character SHA-1 value of the commit contents. When you reference a commit in the future you use this id, like others I mostly just use 6 characters as that’s more than likely the amount of characters you need to uniquely identify it. The beauty of the git log is that if you keep good logs of the changes you’ve made and you group your commits correctly, then you can revert blocks of changes as required.

Reverting Changes

Let’s revert the last commit and see how easy it is to go back to previous version of your app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ git revert b9b57e
2009-08-30 21:20:59 fearoffish ttys001
Finished one revert.
[master 47d2c28] Revert "showing what modifying files that are tracked does"
 1 files changed, 243 insertions(+), 1 deletions(-)
 rewrite README (100%)
$ git log
2009-08-30 21:33:04 fearoffish ttys001
commit 47d2c28a1c90ed95a32c5e76fa6e669b89ca5f09
Author: Jamie van Dyke <fearoffish@fearofpro.local>
Date: Sun Aug 30 21:33:03 2009 +0100

 Revert "showing what modifying files that are tracked does"

 This reverts commit b9b57e53fa0bdcd29b14fb0ded6ab4355ef3cb92.

commit b9b57e53fa0bdcd29b14fb0ded6ab4355ef3cb92
Author: Jamie van Dyke <fearoffish@fearofpro.local>
Date: Fri Aug 28 23:03:31 2009 +0100

 showing what modifying files that are tracked does

commit a08539202e8bf908106e1736dabf588c3b367151
Author: Jamie van Dyke <fearoffish@fearofpro.local>
Date: Fri Aug 28 21:58:47 2009 +0100

 initial bare rails project

When you run the git revert command, you give it the SHA-1 reference – or six characters, like I did – and git will remove any changes you made for that commit. Cool, huh? So you are keeping multiple versions of your application without keeping multiple files.

Okay, that’s enough for this episode. I’ll be creating more episodes on subjects like local and remote repositories, hosting your Rails applications and more, soon.