Warning: Do not attempt to use RCS for Project 1 if it is one day before the project is due and you are just starting.
In this topic, we will look at the concept of revision control: that is, tracking changes you've made to your code.
How often have you made a change to your code which caused you to think: "What did I do which broke my code???" or "My code was working...". If you're lucky, you made a back up (e.g., cp SingleList.h SingleList.h.bak), but more often than not, you made some changes since the back up which you meant to make, or, you backed up after you made the offending change.
Revision control solves this problem for you: it allows you to keep track of changes you've made and also allows you to see the differences.
Perforce
A more modern tool for revision control is created by perforce. This is an excellent tool for maintaining revision control, and, as a bonus, they allow you to use it indefinitely and for free for up to two users. You can down load this onto your home computer. I will try to put together some documentation on this.
RCS (Revision Control System)
The Unix server ecelinux has RCS (Revision Control System) installed on it, and you will be able to use this not only for ECE 250, but also, possibly for ECE 251, ECE 354, etc. This tutorial will cover some of the basics of RCS.
In your project file, create a directory RCS:
{ecelinux:1} cd ece250/p1 {ecelinux:2} mkdir RCS {ecelinux:3}
Next, for each file you want to add to revision control, use ci (for check in). Just follow the instructions, for example:
{ecelinux:3} ci SingleList.h RCS/SingleList.h,v <-- SingleList.h enter description, terminated with single '.' or end of file: NOTE: This is NOT the log message! >> Project 1 source code for SingleList. >> . initial revision: 1.1 done {ecelinux:4}
Warning: depending on your terminal settings, you may not be able to use the backspace character when writing your comment. Simply use Ctrl-Backspace instead.
If you do an ls of the RCS directory, you will find a new file created, SingleList.h,v. You will also note that the file no longer exists in the current directory:
{ecelinux:4} ls RCS {ecelinux:5} ls RCS SingleList.h,v {ecelinux:6}
To edit the file, use co -l (check out and lock). This allows you to edit the file.
If you now edit the file, you can look at the changes by using the command rcsdiff.
{ecelinux:6} gvim SingleList.h {ecelinux:7} rcsdiff SingleList.h =================================================================== RCS file: RCS/SingleList.h,v retrieving revision 1.1 diff -r1.1 SingleList.h 6,7c6,7 < * Author: uwuserid --- > * Author: dwharder 9c9 < * Semester of Submission: (Winter|Spring|Fall) 20NN --- > * Semester of Submission: Fall 2006 74,75c74 < // enter your implementation here < return 0; --- > return count; 80,81c79 < // enter your implementation here < return true; --- > return count == 0; {ecelinux:8}
If you examin this, you will note that it indicates the differences made. For example, I filled in my name, Updated some info, and implemented two functions. The lines on which the changes were made is indicated, for example, the last change was to change lines 80 and 81 in the old file to line 79 in the new file.
Thus, you know what changes you've made, and once you're ready you can check your code in:
{ecelinux:8} ls RCS/ SingleList.h {ecelinux:9} ... do some testing ... {ecelinux:19} ci SingleList.h RCS/SingleList.h,v <-- SingleList.h new revision: 1.2; previous revision: 1.1 enter log message, terminated with single '.' or end of file: >> Implemented and tested the size() and empty() functions. >> . done {ecelinux:20} ls RCS/ {ecelinux:21}
You can check the file out, again, or you can also continue using the file by using the lock option to check in: ci -l. This checks in the differences but allows you to keep editing the file.
Revision History
You can look at the history log file by using the rlog command together with the file name, for example, for the changes we made above, I would get the log file
{ecelinux:21} rlog SingleList.h RCS file: RCS/SingleList.h,v Working file: SingleList.h head: 1.2 branch: locks: strict access list: symbolic names: keyword substitution: kv total revisions: 2; selected revisions: 2 description: Project 1 source code for SingleList. ---------------------------- revision 1.2 date: 2006/08/10 15:02:53; author: ece250; state: Exp; lines: +5 -7 Implemented and tested the size() and empty() functions. ---------------------------- revision 1.1 date: 2006/08/10 15:02:18; author: ece250; state: Exp; Initial revision ============================================================================= {ecelinux:22}
The most useful information is highlighted in blue. Note that the earliest change appears last and the most recent change is first in the list.
Dealing with Mistakes
At some point, you will check in incorrect code, either because you didn't know the original code was correct, or you hadn't properly tested a feature. Fortunately, RCS will allow you to check out older versions of your code. You can test them, find out which change caused the error, and then find out what changes you made which may have caused the error.
Suppose I check out the file again, change the function int size() to use != instead of ==, checked this in, and then made further changes:
{ecelinux:22} co -l SingleList.h RCS/SingleList.h,v --> SingleList.h revision 1.2 (locked) done {ecelinux:23} gvim SingleList.h {ecelinux:24} ci -l SingleList.h RCS/SingleList.h,v <-- SingleList.h new revision: 1.3; previous revision: 1.2 enter log message, terminated with single '.' or end of file: >> Updating the size() function to use != >> . done {ecelinux:25} ci -l SingleList.h RCS/SingleList.h,v <-- SingleList.h new revision: 1.4; previous revision: 1.3 enter log message, terminated with single '.' or end of file: >> Implementing the SingleNode >> . done {ecelinux:26}
We can examine the revision log:
{ecelinux:26} rlog SingleList.h RCS file: RCS/SingleList.h,v Working file: SingleList.h head: 1.4 branch: locks: strict access list: symbolic names: keyword substitution: kv total revisions: 4; selected revisions: 4 description: Project 1 source code for SingleList. ---------------------------- revision 1.4 date: 2006/08/10 15:09:58; author: ece250; state: Exp; lines: +1 -2 Implementing the SingleNode
At this point, because we used ci -l, we are still editing the file, however, with further testing, we determine that something is wrong with int size(). We were sure that it worked correctly at some point in the past, and now, the question is, what change broke it? For this simple case, we could easily re-examine the code, determine what went wrong, and fix it, however, for more complex changes, this may be too frustrating. Also, if you make too many changes per check in, you will not be able to use this feature. First, I've made some changes which I'm not interested in, and therefore we check out a locked version of the file (this discards any changes I've made):
{ecelinux:30} co -u SingleList.h RCS/SingleList.h,v --> SingleList.h revision 1.4 (unlocked) writable SingleList.h exists; remove it? [ny](n): y done {ecelinux:31}
We now have the last checked-in version of the file available, and, after some testing, we note the error still exists.
Next, we can check check out older versions:
{ecelinux:40} co -r1.3 SingleList.h RCS/SingleList.h,v --> SingleList.h revision 1.3 done {ecelinux:41}
Testing shows that the error still exists in version 1.3, thus we continue going back:
{ecelinux:50} co -r1.2 SingleList.h RCS/SingleList.h,v --> SingleList.h revision 1.2 done {ecelinux:51}
At this point, we recognize that the error no longer occurs and therefore we can compare the two versions to determine what went wrong by using the rcsdiff command and giving it the two revisions (1.2 and 1.3) which we want to compare:
{ecelinux:60} co -l SingleList.h RCS/SingleList.h,v --> SingleList.h revision 1.5 (locked) done {ecelinux:61} rcsdiff -r1.2 -r1.3 SingleList.h =================================================================== RCS file: RCS/SingleList.h,v retrieving revision 1.2 retrieving revision 1.3 diff -r1.2 -r1.3 79c79 < return count == 0; --- > return count != 0; {ecelinux:62}
At this point, we have two options: we can either check out the newest version again, make the correction, test it, and check it in. Alternatively, if we want to undo all of the changes from Revesion 1.3, we can do the following:
{ecelinux:62} rcsmerge -r1.3 -r1.2 SingleList.h RCS file: RCS/SingleList.h,v retrieving revision 1.3 retrieving revision 1.2 Merging differences between 1.3 and 1.2 into SingleList.h {ecelinux:63} rcsdiff SingleList.h =================================================================== RCS file: RCS/SingleList.h,v retrieving revision 1.4 diff -r1.4 SingleList.h 79c79 < return count != 0; --- > return count == 0; {ecelinux:64} ci -l SingleList.h RCS/SingleList.h,v <-- SingleList.h new revision: 1.5; previous revision: 1.4 enter log message, terminated with single '.' or end of file: >> Discarding changes made in Revision 1.3. >> . done {ecelinux:65}
Conflicts
Suppose you perform a merge, however, you have since edited the code. Fortunately, when you do the rcsmerge, it will not silently discard future changes. Instead, it will issue the warning
rcsmerge: warning: conflicts during merge
If you now edit the file, you will notice that there is a block of code which looks like:
<<<<<<< SingleList.h // newer code. ======= // older (hopefully correct) code. >>>>>>> 1.6
You can now look at the current state (the newer code) and the original state (the older code) and pick and choose those changes which you actually want.
Warning
All the benefits of RCS are lost if you don't check in your files often and include useful descriptions. Check in often with small and incremental changes.
Help
You can always get your last checked-in version of the file by issuing the co -u command.
Copyright ©2005-2012 by Douglas Wilhelm Harder. All rights reserved.