Version Control

Diomidis Spinellis
Department of Management Science and Technology
Athens University of Economics and Business
Athens, Greece
dds@aueb.gr

Version Control

The Great Debate

Version Control Operations

Branching

Revision Tree Example

cat.c revision tree
cat.c revision tree

Life Under a VCS

The Goodies

Example of a Change Log

RCS file: /cvsroot/basesrc/bin/cat/cat.c,v
Working file: cat.c
head: 1.28
branch:
locks: strict
access list:
symbolic names:
    netbsd-1-5-PATCH002: 1.23
    [...]
    netbsd-1-5: 1.23.0.4
    [...]
    netbsd-1-2-BETA: 1.11
    netbsd-1-2-base: 1.11
    netbsd-1-2: 1.11.0.6
    [...]
keyword substitution: kv
total revisions: 33;    selected revisions: 33
description:
----------------------------
revision 1.28
date: 2001/09/16 12:12:13;  author: wiz;  state: Exp;  lines: +6 -4
Some KNF, via patch by Petri Koistinen in private mail.
----------------------------
revision 1.27
date: 2001/07/29 22:40:57;  author: wiz;  state: Exp;  lines: +6 -6
Some style improvements. [Nearly] #13592 by Petri Koistinen.
[...]
----------------------------
revision 1.15.2.1
date: 1998/02/08 21:45:36;  author: mellon;  state: Exp;  lines: +18 -9
Pull up 1.16 and 1.17 (kleink)

Example of a File Difference List

$ cvs diff -c -r1.12 -r1.13 basesrc/bin/cat/cat.c
Index: basesrc/bin/cat/cat.c
===================================================================
RCS file: /cvsroot/basesrc/bin/cat/cat.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -c -r1.12 -r1.13
[...]
***************
*** 136,141 ****
--- 136,142 ----
                                fp = stdin;
                        else if ((fp = fopen(*argv, "r")) == NULL) {
                                warn("%s", *argv);
+                               rval = 1;
                                ++argv;
                                continue;
                        }

Example of an Annotated Listing

1.166        (jhb      16-Oct-02):      fdp = p->p_fd;
1.114        (alfred   13-Jan-02):      FILEDESC_LOCK(fdp);
1.157        (iedowse  02-Sep-02):      if ((unsigned)fd >= fdp->fd_nfiles ||
1.157        (iedowse  02-Sep-02):          (fp = fdp->fd_ofiles[fd]) == NULL) {
1.114        (alfred   13-Jan-02):              FILEDESC_UNLOCK(fdp);
1.106        (dillon   01-Sep-01):              error = EBADF;
1.106        (dillon   01-Sep-01):              goto done2;
1.106        (dillon   01-Sep-01):      }
1.157        (iedowse  02-Sep-02):      pop = &fdp->fd_ofileflags[fd];
1.94         (dillon   18-Nov-00):
1.157        (iedowse  02-Sep-02):      switch (cmd) {
1.1          (rgrimes  24-May-94):      case F_DUPFD:
1.241        (rwatson  07-Aug-04):              /* mtx_assert(&Giant, MA_NOTOWNED); */
1.158        (jhb      03-Sep-02):              FILEDESC_UNLOCK(fdp);

Extracting Metrics

Tracking Example

Maintainability index over time in the FreeBSD kernel.
Maintainability index over time in the FreeBSD kernel.

Best Practices

Subversion Cheat Sheet

(Results appear after the # sign.)

Create Repository

pwd
# /home/dds
svnadmin create repo
chmod -R go+rwX repo/

Create Project Structure

mkdir template
cd template
mkdir myproject
cd myproject/
mkdir trunk tags branches
cd ..
pwd
# /home/dds/template
ls
# myproject

Initial Addition of a Project to the Repository

pwd
# /home/dds/template
svn import . file:///home/dds/repo/ --message 'Initial repository layout'
# Adding         myproject
# Adding         myproject/trunk
# Adding         myproject/branches
# Adding         myproject/tags

# Committed revision 1.
cd ..

Initial Checkout from the Repository

pwd
# /home/dds/
mkdir work
cd work
svn co file:///home/dds/repo/myproject
# A    myproject/trunk
# A    myproject/branches
# A    myproject/tags
# Checked out revision 1.
ls
# myproject

Add a File to the Project

pwd
# /home/dds/work
cd myproject/trunk
echo hi >file.txt
svn add file.txt
# A         file.txt
svn commit --message 'Added file.txt'
# Adding         trunk/file.txt
# Transmitting file data .
# Committed revision 2.

Tag a Release and Create a Branch

svn copy file:///home/dds/repo/myproject/trunk  file:///home/dds/repo/myproject/tags/version-1.0 --message 'Tag version 1.0'
# Committed revision 3.
svn copy file:///home/dds/repo/myproject/trunk  file:///home/dds/repo/myproject/branches/bug-fix-r1.0 --message 'Branch version 1.0 for bug fixes'
# Committed revision 4.

Update with Changes

cd ..
pwd
# /home/dds/work/myproject
svn up
#A    branches/bug-fix-r1.0
#A    tags/version-1.0
#Updated to revision 4.

Commit a Change

echo hello >file.txt
svn up
# At revision 5.
svn commit -m 'Made greeting more formal'
#Sending        trunk/file.txt
#Transmitting file data .
#Committed revision 5.

Git Cheat Sheet

(Results appear after the # sign.)

Create Repository

pwd
# /home/dds
git init repo
chmod -R go+rwX repo/

Create Project

cd repo
mkdir myproject
cd myproject
pwd
# /home/dds/repo/myproject

Add a File to the Project

pwd
# /home/dds/repo
cd myproject
echo "My project repo." >README
git add README (or git add . to include every file present.)
git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
# new file:   README
#
git commit -m 'README file for repo.'
#[master (root-commit) 138f654] README file for repo.
#1 files changed, 1 insertions(+), 0 deletions(-)
#create mode 100644 README
echo "TODO: configure the repo in $GIT_DIR/config." >>README
git status
# On branch master
# Changes not staged for commit:
#   (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")
git commit -a -m 'Updated README file.'
#[master 1376204] Updated README file.
#1 files changed, 1 insertions(+), 0 deletions(-)

Create a Branch

git branch
#* master
git branch bug-fixing
git branch -a
#  bug-fixing
#* master

Initial Checkout from the Repository

pwd
# /home/dds/
mkdir work
cd work
git clone file:///home/dds/repo
#Cloning into repo...
#remote: Counting objects: 306, done.
#remote: Compressing objects: 100% (92/92), done.
#remote: Total 306 (delta 214), reused 306 (delta 214)
#Receiving objects: 100% (306/306), 213.91 KiB, done.
#Resolving deltas: 100% (214/214), done.
ls
# repo

Update with Changes

pwd
#/home/dds/work/repo/myproject
git pull
#Already up-to-date.

Work with Branches

pwd
#/home/dds/work/repo/myproject
git checkout bug-fixing
#Branch bug-fixing set up to track remote branch bug-fixing from origin.
#Switched to a new branch 'bug-fixing'.

Commit a Change

pwd
#/home/dds/work/repo/myproject
git branch
#* bug-fixing
echo "TODO: Improve layout in README." >>README
git commit -a -m 'New TODO in README.'
#[bug-fixing d758c7f] New TODO in README.
# 1 files changed, 1 insertions(+), 0 deletions(-)
git push
#Counting objects: 5, done.
#Delta compression using up to 2 threads.
#Compressing objects: 100% (2/2), done.
#Writing objects: 100% (3/3), 324 bytes, done.
#Total 3 (delta 0), reused 0 (delta 0)
#Unpacking objects: 100% (3/3), done.
#To file:///home/dds/repo/
#c6439c5..d758c7f  bug-fixing -> bug-fixing

Tag a Release

pwd
#/home/dds/work/repo/myproject
git tag "v1.1"
git push --tags
#Total 0 (delta 0), reused 0 (delta 0)
#To file:///home/dds/repo/
# * [new tag]         v1.1 -> v1.1

More Resources

Further Reading