Easy version control for single files: RCS

Version control is a wonderful invention: it allows you to keep track of what has changed in a file (or directory hierarchy) between each revision.  When you have made some changes you “check in” (or “commit”) and leave a quick log message.  You can then later view the entire history of that file, or look at the differences between any two versions, or check out any of the previous versions.

Sometimes people do not want to use version control because they feel that setting up a Mercurial or Git repository is a chore and it’s not worth the effort for a single file.  This concern is mostly valid, though I would say that the problem is not really that it’s a single file but rather that a directory might have many files that you do not want to control together.  We will use RCS to show lightweight version control on single files.  RCS is in all the GNU/Linux distributions ("sudo apt install rcs" on debian, "sudo yum install rcs" on redhat-based systems).

Example: on GNU/Linux and UNIX systems (and others) people who use the shell bash put various commands to be run at startup in a file called .bashrc – these are for the most part commands to set environment variables.

Here is how you could start controlling your .bashrc with a single command. I just did this in my home directory (try it!):
$ cd ~
$ ci -l .bashrc
.bashrc,v
>> initialization file for bash
>> .
initial revision: 1.1
done
$

Now you can see what that ci -l .bashrc has done:

$ ls -l .bashrc*
-rw-r--r-- 1 markgalassi markgalassi 5789 Feb 8 2016 .bashrc
-r--r--r-- 1 markgalassi markgalassi 6038 Jun 28 10:31 .bashrc,v
$

There is a new file with a ,v extension: .bashrc,v, and the original .bashrc file is still there.  You will never do anything with the .bashrc,v file, but remember that it keeps the historical information.  Let us make a change to .bashrc, for example: I like to keep my aliases and shell functions in a separate file called .bash_aliases, so I will use a text editor to add this line toward the top of my .bashrc:

. $HOME/.bash_aliases

(note that you will want to make yourself a .bash_aliases file, either empty or with a few aliases or shell functions — I’ll give you my favorite one here:

function lst()
{
ls -lashtg ${1:-.} | head -13
}

which I use virtually every time time I change into a directory)

Now I want to check in the new version of .bashrc:
$ ci -l .bashrc
.bashrc,v

>> Added a line to source my .bash_aliases file
>> .
done
$

So this is the workflow: use "ci -l filename" every time you make some changes to that file. Nothing else!

So what’s the point? Let’s say that I want to look at what changed between versions. First I will look at a log of all changes:
$ rcs log .bashrc
[...]
revision 1.2 locked by: markgalassi;
date: 2017/06/28 16:52:59; author: markgalassi; state: Exp; lines: +2 -0
Added a line to source my .bash_aliases file
----------------------------
revision 1.1
date: 2017/06/28 16:47:46; author: markgalassi; state: Exp;
Initial revision
[...]
$

This tells me that I have versions 1.1 and 1.2. To look at the differences between them I can type:
$ rcs diff -u -r1.1 -r1.2 .bashrc
===================================================================
RCS file: .bashrc,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- .bashrc 2017/06/28 16:47:46 1.1
+++ .bashrc 2017/06/28 16:52:59 1.2
@@ -1,5 +1,7 @@
# Mark Galassi's .bashrc


+. $HOME/.bash_aliases
+
DIO_LOCAL=$HOME/DLOCAL
export PATH=$DIO_LOCAL/bin:$PATH
export LIBRARY_PATH=$DIO_LOCAL/lib:$DIO_LOCAL/lib64:$LIBRARY_PATH
$

This is a context diff which shows a bit of the context around the change in the file, and marks with a + (plus sign) the lines that were added (and it would have shown with a - minus sign any lines that were removed).

Some notes about the example I just gave and when to use RCS:

  • If you have not yet used version control, start right now!  You should always use version control on files you change.
  • This was a single file in a cluttered directory: your home directory will have so many files and subdirectories that are not tightly related, so using Mercurial or Git would be awkward: they try to own the whole directory.  That’s why RCS works well here.
  • People have tried to create systems that use Mercurial or Git to control the various “dot” files in your home directory (.bashrc is not the only one – many programs have configuration files in your home directory that start with a dot). These schemes sometimes involve having a separate directory under version control and then using symbolic links to make those files appear in your home directory.  I found it a bit too cumbersome, so I have taken the approach of using RCS for many of the single “dot” files in my home directory, and using Mercurial for those programs which use a whole subdirectory for configuration, such as emacs which uses a .emacs.d directory.

There is much more that can be discussed and demonstrated, but I will point to existing tutorials for that. My purpose here was to get you going with version control on a single file.

Advertisements

About markgalassi

Mark Galassi is a research scientist in Los Alamos National Laboratory, working on astrophysics and nuclear non-proliferation.
This entry was posted in programmingforresearch, sysadmin, try this, unix, version-control. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s