Skip to content

Entries from April 2011.

Tracking merges with Perforce

Perforce is a commercial version control system that seems to share some CVS and SVN features. Besides his shortcomings and weaknesses it has very useful feature: automatic merge tracking.

But sometimes you want to know what commits were already merged and what not. The simplest method to obtain such information is to try merge commits separately (so called cherry-picks) and then check merge results reported by "p4 resolve". It's very slow and boring method. Can it be automated?

Script below uses method described above but automatically. You can easily check merge status:

cd dest-branch
p4-merge-status //path/to/branch

Also you can narrow commits to be checked using weird P4 syntax (to save time):

p4-merge-status //path/to/branch @CL1,@CL2

Here's the script:

#!/bin/sh

BRANCH=$1
RANGE=$2

p4 changes $BRANCH/...$RANGE | sort -n | awk -v BRANCH=$BRANCH '
BEGIN {
        system("p4 revert ... >/dev/null 2>&1")
}
{
        cl=$2;
        pcl=cl-1;
        line=$0;

        cmd = "p4 integrate -Dt " BRANCH "/...@" pcl ",@" cl " ... 2>&1";
        while(cmd | getline > 0) {
                if(/already integrated/) {
                        print " + " line;
                        next;
                }
        }
        close(cmd)

        both = 0
        theirs = 0
        conflict = 0

        cmd = "p4 resolve -af 2>&1";
        while(cmd | getline > 0) {
                if (/^Diff/) {
                        both += ($9 + 0)
                        theirs += ($6 + 0)
                        conflict += ($12 + 0)
                }
        }
        close(cmd)

        if (both >= theirs) {
                print " + " line " both=" both ", theirs=" theirs ", conflict=" conflict;
                next;
        }
        # system("p4 revert ... >/dev/null 2>&1")
        print " - " line " both=" both ", theirs=" theirs ", conflict=" conflict;
}
END {
        system("p4 revert ... >/dev/null 2>&1")
}
'

And sample results:

$ p4-merge-status ../dev @165853,@166120
 + Change 165853 on 2011/04/19 by abc@def 'artf69528 fixed (assigned actio'
 - Change 165863 on 2011/04/20 by abc@def 'Artf69596: After this change Re' both=0, theirs=2, conflict=0
 - Change 165865 on 2011/04/20 by abc@def 'E2E>NMC>PVR> PVR node is displa' both=0, theirs=21, conflict=0
 + Change 165881 on 2011/04/20 by dariusz.cieslak@dc 'Merging changes' both=9, theirs=0, conflict=0
 - Change 165884 on 2011/04/20 by abc@def 'artf68460 : additional popup im' both=0, theirs=16, conflict=0

Legend:

  • "+": change was already merged
  • "-" change was not merged yet
  • both: number of chunks that are the same on both source and destination branch
  • theirs: number of chunks only on source branch
  • conflict: number of chunks with conflicts

Above data allows you to estimate merge effort (and risk) before starting real merge.

The script is not fast because it's using P4 commands to merge changes. Perforce uses network heavily and that's why it's so slow for operations that other systems (SVN, GIT) do locally.

However: it's better than nothing, I hope you will find above script useful.

Port tunnelling using SSH

A typical problem: some work must be done outside the office, but remote services needed are restricted only to office IP address (or some of them are behing VPN). If the service is available under single static port it will be pretty easy to tunnel the connection using SSH.

Tunnel: means you can access the service port as it's available locally. It's not a proxy (however ssh can act as HTTP proxy if configured).

I'll show practical example: Perforce server begind VPN must be accessed outside office. First, configure it using ~/.ssh/config (more elegant solution):

Host dccf
     User user1
     HostName 123.123.123.123
     Port 10222
     LocalForward 1333 124.124.124.124:1666

123.123.123.123 is a public office IP, 124.124.124.124 is IP of the service (that operates on 1666 port). Then you can connect new alias:

$ ssh dccf -N &

After this operation you can connect the service using local address (localhost) with local port (1333 in this example):

$ export P4PORT=127.0.0.1:1333
$ p4 sync ...

Option "-N" is useful when you want to only forward some ports. Of course you can setup the tunnel from command line as well in one step:

$ ssh dccf -N -L 1333:124.124.124.124:1666 123.123.123.123

Enjoy!

Simple shell lock implementation on Linux

Sometimes you want to avoid running second instance of some shell script. Locking implementation is not very hard:

LOCK_FILE=$0.lock
test -f $LOCK_FILE && {
        PID=`cat $LOCK_FILE`
        echo "$LOCK_FILE exists, PID=$PID, exiting"
        exit 1
}
echo $$ > $LOCK_FILE
trap "rm $LOCK_FILE" 0 2 3 15