Wednesday, July 27, 2011

Branch and Merge vsTrunk: Latent code pattern

http://www.infoq.com/presentations/The-Kiev-Experiment

time: 58:54
[Source Control/ CI (Continuous Integration)] Latent code pattern:
Multiple teams work on the same Trunk (no branching, merging hassle). Some checked in code is simply unreachable (not executable): this is ensured by event driven architecture (event does not happen, code is not triggered); modularity/partitioning and Dependency Injection technique.
The (new) feature (bit) can be OFF or ON (configured). You can promote configuration into production weeks before the release and have some features off. And when you are ready, you just flip the switch on. It allows you to be agile. Business tells you want they want and when.

Wednesday, December 22, 2010

CVS

!TCL=62550
!TITLE=CVS Notes
!SORT=Y

!TEXT= Eclipse & CVS
http://www.eclipse.org/articles/Article-CVS-branching/eclipse_branch.html

(Main branch - Head/Trunk)
When branching off a development stream, it is often advisable to rebase before merging the branch back to the main branch. To rebase means to merge the contents of the main branch to the subbranch. If any conflicts are to be resolved, they are done on the subbranch rather than the main branch. If the merge goes well, the subbranch is merged to the main branch. After having previously resolved all merge conflicts, this last merge would be a trivial one. The advantage of taking the extra rebase step is that it avoids having conflicts on the main branch.

!
!TEXT= Installation (Wiki)

http://www.cvsnt.org/wiki/InstallationTip
http://www.cvsnt.org/wiki/InstallationTips#head-4a95e78b6a684a77ce4024901eabbbc6bfcb9daa

!
!TEXT= Creating repositories (first steps)

+++++++++++++++++++++++++++++++++++++++++++++++
*** Creating a repository (on the CVS server):
(On Linux server you will need to configure [x]inetd (Network services to support cvs service) - config file;
update /home//.bash_profile for
CVSROOT=/...../.../
export CVSROOT

cvs -d init

*** import a project (a set of files) as is (keeps folder structure).
*** (uploads files from your local directory into server's repository)

cvs -d import vendor_tag release_tag
(see example below)
After this you may delete the source (client) directory (from which files were
imported into server repository) and get it by checkout module (normally into a different folder)
--- now you get the code under CVS control (simple import does not get it under CVS control -
only copies folder(s)/files to the server).

mkdir temp/example
cd temp/example
1. $ cvs -d /var/was/cvsroot import example example_project ver_0-1

2. C:\tmp\unix>cvs -d c:/cvs/my_repository/ import test_project test_project_vendor rel-1

The files are stored as a collection of RCS files (file,v)
---------------------------
# server repository on same as client machine

cd
C:\CVS\cvs_client_repository\
mkdir new_proj_2 <== that will be new project to be imported
............
cd new_proj_2

cvs -d /CVS/cvs_server_repository import -m "Creating a new project" new_proj_2_module avendor arelease

the repository will receive the whole folder structure with files from C:\CVS\cvs_client_repository\new_proj_2
the module will be "new_proj_2_module".


!
!TEXT= Creating a module

*** creaging a module (a mapping (alias) between a [module] name and top folder

checkout CVSROOT module in a folder (you will get all the CVS system files),
update modules file: add the line

module_1 fresh_one

where fresh_one is the top folder of a folder structure

your are done.

In CVS clients you need to check out module_1 to get the fresh_one/...... files.

in Eclipse, you will see under the HEAD both fresh_one folder and module_1 which are its alias.

!
!TEXT= Authenticating (pserver, problems with CVSNT on local)

------------------------------------------------------------------
What worked for me:
Windows 2000 Workstation; CVSNT (2.0.51d)
Created update the %CVSROOT%/CVSROOT/passwd file (as it was not there)
and added a line:

cvsuser::

where
:: means nill password and cvsuser when using on the cvs consoles will be mapped into System user.

The command to connect to the local repository using the newly created cvs user:
cvs -d :pserver:cvsuser@localhost:2401:/tmp/CVS_LOCAL_REPO login
------------------------------------------------------------------
*** Authentication (pserver)
If you want to play around with your local host hosting both the server repository & client workspace,
you may want to disable autherntication by taking the following steps:

1. Update C:\CVS\cvs_server_repository\CVSROOT\config as follows:
# Set this to `no' if pserver shouldn't check system users/passwords
##SystemAuth=yes
>>>> SystemAuth=no
??? does not seem to work

2. On CVSNT (2.5 March-hare.com[2005])) add an anonymous user (Server Settings >> Anonymous user textbox) e.g. cvsuser
to C:\CVS\cvs_server_repository\CVSROOT\passwd file:
just one line
cvsuser:

(and providing no password after :). You must be IN !!!

WinCVS keeps the passwords under
HKEY_CURRENT_USER\Software\cvsnt\cvspass
as
:pserver:cvsuser@localhost:/CVS/cvs_server_repository

Note:
Normally it should be in the format (CVS help)
This file is $CVSROOT/CVSROOT/passwd /
Its format is similar to /etc/passwd,
except that it only has two or three fields, username, password, and optional username for the server to use.
For example:

bach:ULtgRLXo7NRxs
cwang:1sOp854gDF3DY

I: Passwords are 13 bytes long and generated by C's crypt command to hash password from single DES with Salt "Rs" - similar to
one used in Unix's when hashing passwords.

Right now, the only way to put a password in the CVS passwd file is to generate it using some soft and then paste it in password file.

@ SEE Wanna create bona-fide passwd file on CVS server with users/pasword below.

Someday, there may be a cvs passwd command (???? CVSNT does it!!!)

Exlipse (CVS) -
add location:
Host: localhost
Respository path: /CVS/cvs_server_repository
user: cvsuser
password: [nothing]
Connection type: pserver
user default port
save password (check)

>>>>> FINISH.

You shoudl be in.

If you want to impersonate some system user with an alias cvs user (say cvsBosh) with blank password, you can do the following:
update the CVSROOT/passwd file with the following line:

cvsBosh::Bosh :: means nill password and cvsBosh when using on the cvs consoles will be mapped into System Bosh user.

It is possible to "map" cvs-specific usernames onto system usernames (i.e., onto system login names) in the $CVSROOT/CVSROOT/passwd file by appending a colon and the system username after the password. For example:

cvs:ULtgRLXo7NRxs:kfogel
generic:1sOp854gDF3DY:spwang
anyone:1sOp854gDF3DY:spwang

Thus, someone remotely accessing the repository on chainsaw.yard.com with the following command:

cvs -d :pserver:cvs@chainsaw.yard.com:/usr/local/cvsroot checkout foo

would end up running the server under the system identity kfogel, assuming successful authentication.
However, the remote user would not necessarily need to know kfogel's system password,
as the $CVSROOT/CVSROOT/passwd file might contain a different password, used only for CVS.
And as the example above indicates, it is permissible to map multiple cvs usernames onto a single system username.

This feature is designed to allow people repository access without full system access
(in particular, see Read-only access); however, also see Password authentication security. Any sort of repository access very likely implies a degree of general system access as well.

????? Right now, the only way to put a password in the CVS passwd file is to paste it there from somewhere else.


*** If stuck with pserver, try sspi protocol - much easier for Widnows NT, it will udpate your $%^&*( passwd file)
without the need to use openSSL and cut/paste:

1. C:\CVS\cvs_server_repository>set cvsroot=:sspi:box2:/CVS/cvs_server_repository

Add a user cvsmv78 that maps to the actual windows mv78 user
2. C:\CVS\cvs_server_repository>cvs passwd -r mv78 -a cvsmv78
Adding user cvsmv78@box2
New Password: blah
Verify Password: blah

>>> in the CVSROOT/passwd file you will see:
cvsmv78:CeX5pImmjhKKk:mv78

Note: the actual window's account's password stays unchanged !!!!
!
!TEXT= Connect to Apache CVS respository

host: cvs.apache.org
repository: /home/cvspublic
user: anoncvs
password: anoncvs
connection type: pserver

:pserver:anoncvs@cvs.apache.org:2401:/home/cvspublic


!
!TEXT= Wanna create bona-fide passwd file on CVS server with users/pasword

QUOTE: "Right now, the only way to put a password in the CVS passwd file is to paste it there from somewhere else.
Someday, there may be a cvs passwd command"

Want to update the CVSROOT/passwd file with real passowrds? Use openSSL (which mimicks)
Unix's crypto function to generate the password (and hashit) and copy/paste it into CVSROOT/passwd file.

Created here passwd.src file with only entry: letmein (7 bytes, no more - no end of file, etc...)

C:\utils\OpenSSL\cvs>
RUN >>> openssl passwd -in passwd.src
>> STDOUTPUT:
RsK4d.aEmWtVU

Pasted
RsK4d.aEmWtVU
into /CVSROOT/passwd as follows:
me:RsK4d.aEmWtVU
now from CVS client can get in via pserver by providing password: letmein.

Sweet.

2. I tried: Use perl's crypt function as follows:
my $pass = "letmein";
my $salt = "Rs";
print crypt ($pass, $salt);
same output!!!

!
!TEXT= Changing repositories
*** Changing repositories:

* (Hack) Manually Edit CVS/Root in all directories in the sandbox

!
!TEXT= Viewing past revisons of a file

cvs log: Viewing past revisions of a file:
===============================================
. . . .
----------------------------
revision 1.12
date: 2004/08/08 15:28:30; author: Tosh; state: Exp; lines: +1 -1; kopt: kv; commitid: 2644116469d0000; filename:
PBE.java;
"from #2"
----------------------------
revision 1.11
date: 2004/08/08 15:24:36; author: Tosh; state: Exp; lines: +4 -0; kopt: kv; commitid: 27c411645b30000; filename:
PBE.java;
no message
----------------------------
. . . .

!
!TEXT= Revision stamping
You put $Revision$ line in your source text file, CVS will keep it updated
with the current revision number:
e.g. $Revision: 1.5 $

every time you commit / update new .
!
!TEXT= Status

*** cvs status
===================================
* -l local non-recursive (current dir only)
* -R default (recursive)
* -v verbose

cvs status -v PBE.java

.....
File: PBE.java Status: Up-to-date
Other statuses could be: Needs Checkout (does not exist in the sandbox, only in repository)
Needs Patch ( get update)


If you expect to use one repository, set the $CVSROOT environment variable to the repository's

DOS:
> SET CVSROOT=c:\CVS\cvs_server_repository
or
set CVSROOT=:pserver:charlie@MyServer:/usr/local/cvsrep
set CVSROOT=:pserver:mv78@192.168.09.100:/apps/cvs/cvs1/cvsroot

full path, in the format :protocol:user@host:path.
It should look something like :ext:jenn@cvs.example.com.au:/home/cvs.

ext - ssh access
kserver - Run in Kerberos server mode.
pserver - Run in password server mode.

There are several ways to tell CVS where to find the repository.
1. You can name the repository on the command line explicitly, with the -d (for "directory") option:

$ cvs -d /usr/local/cvsroot checkout module_name

2, sh and bash users should instead have these lines in their .profile or .bashrc:

CVSROOT=/usr/local/cvsroot
export CVSROOT

!
!TEXT= CVS general switches
CVS operations are not atomic, so if someone commits while your are tagging, for example, you may
end up with not what you expect.

*** cvs command
cvs switches:
* -Q (very quiet) / -q (quiet)
* -n - no changes (just query)
* -d - repository path
H /h - help

!
!TEXT= I want to see or list modules in my repository

*** cvs ls : listing modules in your repository:
================================================
Run on server ???
cvs ls
Listing modules on server

CVSROOT
ImportSettings_Module_Repository_Path
.....
!
!TEXT= Checkout
*** cvs checkout: Getting the Tree:
=========================================

CVS stores the files in a central repository, but users work from a working copy of a file.
Project on your client machine is sitting in what is called a "sandbox".

CVS will create te sandbox as a subdirectory of your current working directory.
Make a directory to do your work in.
cd into that directory.

(If you don't have a $CVSROOT environment variable, or want to use a different repository,
use

cvs -d repos_dir checkout project_name

to checkout the module instead).

The checkout will put a copy of that module's files and subdirectories into your cvs directory.

e.g.
cd C:\cvs_client_side
C:\cvs_client_side>cvs -d c:/cvs/my_repository/ checkout test_project
cvs checkout: Updating test_project
U test_project/PBE.java
U test_project/SimpleExample.java

Folder CVS is created:
Directory of C:\cvs_client_side\test_project\CVS

08/04/2004 10:42p 101 Entries
. . .
08/04/2004 09:14p 14 Repository
08/04/2004 09:14p 23 Root

Repository contains project name
Root - the repository location:

C:\cvs_client_side\test_project>more CVS\repository
test_project # the name of the module (project)

C:\cvs_client_side\test_project>more CVS\root
c:/cvs/my_repository/ # server side location


Switches:
* -P prune empty directories
* -D date or -r revision
* -f force CVS to check out the latest (used with -D or -r)

!
!TEXT= Merge
You have created YOUR_BRANCH; want to merge it into HEAD.
1. Get HEAD into your local sandbox; cd there
2. cvs update -j YOUR_BRANCH (merging HEAD (current working folder) with BRANCH code via update)
-j == join
CVS will make an honest attempt to merge......

!
!TEXT= Update (receive changes)
*** cvs update: Receiving Changes
====================================
Every day before you start work, and any time someone else may have made and committed
#regular
> cd /folder
> cvs update -P -d -C

# getting by revision (revision 1.2) :
> cvs update -p -r 1.2 yourfile.dat
changes, cd into your working directory and run cvs update.
This checks your working copies against the repository files and imports any changed
files for you.


*** update switches
* -C (clean) overwrite files in the sandbox with copies from the repository (cvs update -C file2.dat)
* -l local update (no recursive)
* -R recursive udpate
* -d "download" files & directories (without -d, only files )
* -D or -r update by date / revision number
* -P avoid pulling down empty directories (exclusive with -d)
* -A reset any sticky tags, dates or keywords, replace the existing files in the sandbox with the

revision at the head of the trunk (head sometimes is referred to as trunk).

also gives you any new directories.

Update reports on the status of each file as it checks it:

*U file
updated successfully

*A file
added but not yet committed (need to run a cvs commit)

*R file
removed but not yet committed (need to run a cvs commit)

*M file
modified in your working directory: The file in the sandbox is more recent than the repository version
or the sandox and the repository both had changes that the system could safely merge into your sandbox
copy (need to run a cvs commit)

*C file

there was a conflict between the repository copy and your copy which requires human intervention

*? file
the file is in your working directory but not the repository and CVS doesn't know what to do with it

If CVS can't merge a modified file successfully with the copy in the repository, it announces the conflict in the output of cvs update. The original file is stored in .#file.version in the file's working directory, and the results of the merge are stored as the original filename.

Apply the updates to the repository with

!
!TEXT= Commit

*** cvs commit
====================

* -l local non-recursive (current dir only)
* -R default (recursive)
* -m "message"
* -F for single file
* -r revision


This command needs to be run from higher in the hierarchy than all the files you have changed -- you can run it from the base of your working copy.

You can also
cvs commit filename
, which will commit a single file or recursively commit a directory.

CVS then opens whichever editor is the default in your environment -- based on the $CVSEDITOR or $EDITOR environment variables.


Use cvs add filename to mark a new file for inclusion. CVS doesn't put the file in the repository until you do a cvs commit.

Directories are added with the same command. Files within a directory can't be added until the directory is added.

!
!TEXT= Add file

*** cvs add: Adding file
========================
Windows: first
cvs add file
then
need to commit:
cvs add file (in directory C:\cvs_client_side\test_project\)
cvs add: scheduling file `file' for addition
cvs add: use 'cvs commit' to add this file permanently
cvs commit -m "Added line, commited" file

!
!TEXT= Remove file

*** cvs remove Removing Files:
=============================
To mark a file for removal from the working copies, use cvs remove filename. Before CVS will remove a file from the repository, you have to actually delete it from the filesystem. CVS doesn't actually remove the file entirely, it puts it in a special subdirectory in the repository called Attic.

Directories Don't Remove
CVS does not remove directories -- it would break the change tracking. Directories can be removed by changing the repository -- this is discussed in "CVS Administration."

!
!TEXT= Branching

-b - branch
D2006-03-06T1102-DB2Decomm - branch name
(use script for the date:
$ echo D`date +%FT%H%M-DETAILS`
D2006-03-06T1115-DETAILS)

Abicas-biz - module (folder on server)

$ cvs rtag -b D2006-03-06T1102-DB2Decomm Abicas-biz
....
cvs rtag: Tagging Abicas-biz
cvs rtag: Tagging Abicas-biz/bizMktStatic
......
Or simpler, cd to the directory from which you are branching:
cvs tag -b NOV_2006_PROD_FIXES

!
!TEXT= Tagging
*** cvs tag : Tagging
==========================
Tagging is for creating a snapshot in time of a project.

> cvs tag LABEL_1 (the files in sandbox that have been synchronized with repository)

You can use option -f (force) with -r and -D (date)

Unless time is specified, -D 12 Feb 2004, e.g. will instruct cvs to tag the file revisions
as they were at 12:00 am on Feb 12, 2004.

You can use -l (local)

To retrieve a tagged file / files use
> cvs checkout -r LABEL_1 test_project # to create a new sandbox
> cvs update .... # to update the existing sandbox

e.g.
cvs -d c:/cvs/my_repository/ update -r LABEL_1 # will get you the LABEL_1 into sandbox
# repository will keep the files committed after LABEL_1, but will move current version to
the one tagged by LABEL_1

!
!TEXT= Annotate dir or file
*** cvs annotate /dir/file
==================================
shows the content of a file with insertions of changes as per revisions:
1.1 (Tosh 05-Aug-04): import sun.misc.*;
1.15 (Tosh 13-Aug-04): // LINE 2
1.1 (Tosh 05-Aug-04): //
1.1 (Tosh 05-Aug-04): // http://www.cs.ucf.edu/~jlee/cop5937/Homework/HW3/PBE.htm
1.1 (Tosh 05-Aug-04): //
1.1 (Tosh 05-Aug-04): public class PBE
1.1 (Tosh 05-Aug-04): {
1.14 (Tosh 08-Aug-04): // File updated locally....
1.14 (Tosh 08-Aug-04): private static int ITERATIONS = 1000;


!
!TEXT= History
*** cvs log: File /s history
==================================

++++++++++++++++++++++++++++++++++++++++++++++
*** cvs release: Releasing a sandbox
=====================================
cvs release command should be used before you delete a sandbox.
if prompted, run cvs commit or cvs update -A (to remove stickness)
cvs release -d

!
!TEXT= Setup command line client on Windows
- set path to CVS.exe:
> path = C:\Program Files\GNU\WinCvs 1.3\CVSNT;%PATH%

- set CVS root
> set CVSROOT=/cvs/cvs1/cvsroot
(extract it from "@server_name:/cvs/cvs1/cvsroot)

- navigate to the folder where you have your module checked out and run commands:
- run your commands:
e.g.
# difference of revisions:
cvs diff -r 1.10 -r 1.11

# Grep the history of the file , apply grepping:
cvs log | grep -n3 'jndi'

# update revision:
cvs update -r 1.22

# Label the directory
cd your_dir
cvs tag LABEL_1
(the files in sandbox that have been synchronized with repository)

# Create a branch
cvs rtag -b D2006-03-06T1102-DB2Decomm Abicas-biz


# Add a new file:
cd your_dir
cvs add
cvs commit -m "New better file"

# Getting by revision (revision 1.2) :
cvs update -r 1.2

# Update folder:
cd /folder
cvs update -P -d -C (-A -reset sticky flag)
# List folders (modules) in server repository (module is an alias to a folder that can be set)
# Windows command line:
set CVSROOT=:pserver:user@192.168.0.100:/CVS/cvs_server_repository
# set path to cvs.exe
cvs login
>password: ....
cvs ls
> listing modules on server
....
> virtual modules on server (CVSROOT/modules file)
module_1 fresh_one
(mod name/alias) (folder name)

#Check out a module:
cd C:\cvs_client_side
cvs [-d $CVSROOT] checkout YOUR_MODULE
!
!TEXT= More on basic stuff
http://homepages.borland.com/ccalvert/linux/utils/cvsDocs.html
!
!TEXT= Suggested TAG names
Setting branch name: D2005-10-04T2000-R51b

Tag naming convention:
D`date +%FT%H%M-CR_NUMBER-prod` (e.g. D2006-01-12T1111-CR1909248-prod for Jan 12 11:11)
One can use the command above (Bash / Kornshell) to generate the timestamp

Note:
If code needs to be relabeled (retagged), the time portion of the label will change.
So possibly, there may be more than one tag / label for same CR, e.g.

D2006-01-12T1111-CR1909248-prod
may be followed by a new tag (for same CR number) at say 15:12 January 14:
D2006-01-14T1512-CR1909248-prod

Tagging from command line:
> Admin > Command Line | Ctl-L
cvs rtag -r

e.g.
tag module module_name:
cvs rtag -r D2005-10-04T2000-R51b D2006-01-12T1111-CR1909248-prod module_name

!
=========================
Basics of WinCVS:
=========================
Make sure you have cvs.exe installed, so

If you don't see CVSNT installer after wincvs_setup.exe completion, run cvsnt_setup.exe separately.

Both executables are included in the WinCVS 2.

Start WinCVS
> Admin > Login >

Put in CVSROOT
:pserver;username=youridonserver;hostname=cvsserver;port=2401:/cvs/BPortalRemediation
(note, no closing '/')
Enter.

If you want to change the CVSROOT, you will need to
Admin > Logout >

Select your local repository folder as you like it.
> Remote > Check0ut module >

Redub the CVSROOT from login,
if you have a path to the module,e.g. Path_to_module/ (module (folder) is not at the same level as the CVSROOT Folder on the CVS server), put the absolute path:

[Path_to_module/]Module_Name

(no starting '/' on the path or module)
OK.

=============

Tuesday, October 26, 2010

Subversion

Check-out (get) from command line:
c:\tmp> svn co svn://srv-svn/server/trunk/Documents --username mike
password?
Will have a SVN repository created in the current folder (c:\tmp)

From:
http://hgbook.red-bean.com/read/how-did-we-get-here.html

Has ability to let a user lock a file.

Prior to version 1.5, Subversion had no useful support for merges. At the time of writing, its merge tracking capability is new, and known to be complicated and buggy.

Because many Subversion commands must talk to the server and Subversion does not have useful replication facilities, server capacity and network bandwidth become bottlenecks for modestly large projects

Subversion doesn't store revision history on the client,
it is well suited to managing projects that deal with lots of large binary files. If you check in fifty revisions to an incompressible 10MB file, Subversion's client-side space usage stays constant The space used by any distributed SCM will grow rapidly in proportion to the number of revisions, because the differences between each revision are large.

Mercurial can import revision history from a Subversion repository. It can also export revision history to a Subversion repository. This makes it easy to “test the waters” and use Mercurial and Subversion in parallel before deciding to switch.


Setting up SVN Server
--------------------------
I used VisualSVNServer for Windows (runs as VisualSVN Server service)
which ?? is a wrapper around Apache http web server + Win GUI console:

httpd.conf:
-----------------
ServerRoot "C:/SVN"
ServerName "myserver.com:80"
PidFile "C:/SVN/Repositories/server.pid"
Listen "80

Provides nice Browser view and Basic Windows GUI.
Start / Stop VisualSVNServer will start / stop Apache Http server
-------------------------------------------
SVN comes with the server for svn protocol:
$ svnserve -d -r C:\SVN\Repositories
-d --deamon
-r --root (directory to serve)
(default port is 3690)

if dir structure is:
C:\SVN\Repositories
|
| - R2

you can do:
$ svn list svn://localhost/R2
$ svn list svn://localhost:3690/R2
branches/
tags/
trunk/
(if have the recommended folder structure)

And that's what you would put in as URL in GUI (e.g. Subclipse plug in)

============================================
Tools:
3-way comparison:
1. http://www.perforce.com/perforce/downloads/windowslist.html#ntx86
2. kdiff3

Client: Eclipse:
downloaded Subclipse plugin site package from C:\downloads\SVN-site-1.0.6 and installed from local site.
============================================
To play with the SVN config on Windows:

C:\Documents and Settings\\Application Data\Subversion
|
-- config


SVN_HOME=....
path \bin


# Create a repository:
$ svnadmin create c:\repo


Prepare a initial project for importing.
Create a folder structure for project (Suggested repository structure):

My_Project
|
|-branches
|-tags
|-trunk

Import the above skeleton to repository:
$ svn import My_Project file:///C:/SVN/Repositories/R2 -m "Init import"
or
$ svn import My_Project http://servername/svn/R2 -m "Init Import"

To start using (checkout / co):
$ svn checkout file:///C:/SVN/Repositories/R2/trunk my_project
Or
$ svn co http://localhost/svn/R2/trunk my_project

to create my_project folder with any subfolders in the current dir (where you execute svn command)

List the folders in a repository:
$ svn -v list file:///C:/SVN/Repositories/R1 (e.g /trunk)

You can lock and steal this lock. Nice.

Mercurial distributed SCM

Joel's
http://hginit.com/


10/25/2010 12:04PM
=========================================================
Open book (covers 1.2 -- 2008):
Mercurial: The Definitive Guideby Bryan O'Sullivan:
http://hgbook.red-bean.com/read/

distributed revision control system

-----------------------------
Mercurial maintains a complete copy of history in each clone, everyone uses Mercurial to collaborate on a project can potentially act as a source of backups in the event of a catastrophe. If a central repository becomes unavailable, you can construct a replacement simply by cloning a copy of the repository from one contributor, and pulling any changes they may not have seen from others.

There's a one-to-one relationship between branches you're working in and directories on your system. Hard file links are used if necessary to save on the disk space.

There always exists a branch named "default".
So
$ hg push will push changes from your local to the default

-----------------------------
Mercurial is Not so good for:
[Binary] files that are very large and incompressible

Frequently changed files with merging conflicts

Good for "patch management" (A patchwork quilt) problem.
You have an "upstream" source tree that you can't change; you need to make some local changes on top of the upstream tree; and you'd like to be able to keep those changes separate as a single "unit of work" (should be isolated/orthogonal). E.g. Linux kernel patches (thousands). Quilt manages a stack of patches on top of a directory tree.
Mercurial includes a powerful extension (marriage of distributed revision control with patches): Mercurial Queues (MQ) (changeset push/pop stack). This feature contributes to the agility dimension.
-------------------------------------------------------------------------------
Starting UP:

Create
~/Mercurial.ini (.hgrc)
--------------------------------------------
[ui]
username = Mike Vladi
# this guy will take base, local, other and merged copies of the file in conflict
# and will allow for manual resolve
HGMERGE=C:\uts\Kdiff3.exe

[paths]
# repository aliases
default=C:\mercurial_SCM\REPO
mylocal=c:\tmp\local

[hooks]
# will be invoked on commit
commit = C:\tmp\tmp\ECLIPSE_BKUP\BASE\src\dump.bat

[extensions]
extdiff =
# DID NOT yet figured out
# How-to use on command line: $ hg extdiff -p %bc2%
# where c:> set bc2="path/to/beyond_compare.exe"

# NO good: extdiff ="C:\Program Files\Beyond Compare 3\BCompare.exe"


--------------------------------------------
Put hg[.exe] on your PATH
--------------------------------------------

Getting help:
$ hg -v help
$ hg command -hv

global options:
-R --repository REPO repository root directory or name of overlay bundle file
--cwd DIR change working directory
-y --noninteractive do not prompt, assume 'yes' for any required answers
-q --quiet suppress output
-v --verbose enable additional output
--config CONFIG [+] set/override config option (use 'section.name=value')
--debug enable debugging output
--debugger start debugger
--encoding ENCODE set the charset encoding (default: cp1252)
--encodingmode MODE set the charset encoding mode (default: strict)
--traceback always print a traceback on exception
--time time how long the command takes
--profile print command execution profile
--version output version information and exit
-h --help display help and exit


Task: Clone from the default repo to another (just an empty folder)

$ hg clone [-r 74b852bb154b] default C:\tmp\REPO
revision/tag/cset source --> target

the hash after -r (evision) can be changeset (unique across all repos) (can use the prefix number (local revision number) as well)
"default: repo is specified in the mercurial.ini
--------------------------------------------
Normal work:
working on a repo:
$ hg add (all files)
$ hg commit -m "Label text"

Note: not happy about commit:
$ hg rollback
to the point just before commit

Which you can combine with a commit's convenient flag:
$ hg commit -A -m "Label text"

-A adds/removes the new files

Another repo:
$ hg pull -u source_repo
(pull and update)

Variations:
$ cd ../local
$ hg pull stable_repo
$ hg merge
$ hg commit -m "Bring in bugfix from stable branch"

# At this point your changes in local are not seen on the stable_repo
# but you have brought in the fixes from the stable over to local and merged

-----------------------------------

A nice feature of clone is -U flag:
-U --noupdate the clone will include an empty working copy
(only a repository)

It is useful when you want to cd in thatfolder and start doing update by tag / revision:
$ hg clone -U main main-old_tag
$ cd main-old_tag
$ hg update


--------------------------------------------
Start HTTP server for GUI:
$ hg serve
access: http://localhost:8000/
--------------------------------------------
$hg log:
RevisionNumber:Changesetid

change set id is unique across all repos
revision number is a short cut which is not unique across repos

Samples: hg log -vpr3 as a short cut for
$ hg log -v -p -r 3 (3 is the prefix as in 3:0272e0d5a56 )

Compact output:
$ hg log --style compact

very compact:
$ hg log -q
8:fd537033bce7
7:c74f
......
0:37c27d0ebb97

You can make this style persistent via config:
[ui]
style = compact

------------------------
$ hg status
will place M in front of the Modified file, ! if the file was physically removed
if you deleted file by accident its hg status will show with !, you
can get it back by
$hg revert del_file_name

----------
$ hg diff
will show the changes in the local repo
----------
$ hg commit
will create a new changeset

Note: commit is a logical operation, see push command for change distribution (which is symmetrical to pull)

$ hg commit -u some_other_user
will override the [ui] value in the mercurial.ini (.hgrc)

commit works on the entire repo (working directory)
(in CVS & Subversion you have better granularity)

---------------

Unit of work A:
You do some changes to local repo, then
$ hg status
to get the M for modified files and A for file you have added (hg add), ? if not known (not added)

You can use patterns to fine-tune to status:
$ hg status "glob:**.dat"
Note: no spaces in the string above.
will output on all files ending with .dat and in all subdirectories
(see patterns below)


Let's see the current tip (latest changeset id for the repo):
$ hg tip
changeset: 9:b37fe065e35e
tag: tip

Now commit your changes, it will create a new changeset:
$ hg tip
changeset: 10:e04b50c57c69
tag: tip

If you use the -p (path) flag on hg tip, you will get the repo - wide diff for commit between the newest and the previous tip:

$ hg tip -vp

diff -r b37fe065e35e -r e04b50c57c69
previous cset newest cset
-------------
Mercurial separates pulling changes in from updating the working directory.

Workflow:
.................
$hg incoming and
$hg pull (due to latency, you can now pull more than incomming above was showing)

If you want precision, use a -r flag to pull by a cset
$ hg pull -rxxxxxx


the pull command will update the "REPOSITORY" but not the files in the "WORKING DIRECTORY"

This separation between pull and update helps to update to any revision in the repository's history.

But the pull-and-update flow is so frequent, so
$ hg pull -u
--------------
$ hg update
update to the tip (latest) revision

updating to a previous local revision e.g. to version 5
$ hg update 5
5 is local rev # (prefix: before change set cset)
you will get a diagnostics message like:
1 files updated, 0 files merged, 2 files removed,..

----------------
Work flow: push
.................
$ hg outgoing
what can be pushed to that REPO
$ hg push -f
-f force update

You will still need to do hg update in the to get the changes in the working directory.

Unlike hg pull, hg push does not provide a -u option that updates the other repository's working directory.
-----------------
How to undo if I issued a commit?
$ hg rollback
it is only 1 level and works on the following transactional commands:
- commit
- import
- pull
- push (with this repository as the destination)
- unbundle

Notes:
- Rolling back is useless once you've pushed
- You can only roll back once (one prev txn)

If you have not yet committed, use:
$ hg revert file
(it is kinda undo all your changes since last commit)
file.orig is created that contains the (discarded edit) updated file.
revert will restore the file you removed bypassing Mercurial (OS) or after using wrong add / remove Mercurial commands.

-----------------
$ hg rename f1 f2
$ hg diff
-f1
+f2
-------------
Tagging:
You can add / remove! tags.

A tag is nothing more than a "symbolic name" for a revision.
The tip tag is a special "floating" tag, which always identifies the newest revision in the repository.

$ hg tag "'Autumn release 2010'" (better just one word hg tag tv1.0)

'' will help isolate the text that Mercurial automatically creates on creation (see below)

$ hg tip
changeset: .....
tag: tip
...
summary: Added tag 'Autumn release 2010' for changeset 47b49fb43421

# the summary is autogenerated (standard text) !

$ hg tags
tip ....
'Autumn release 2010' 24:47b49fb43421

Now folks can get the repo by the tag:
$ hg update

Note: You can use "A sentence for tag" and use it
$hg update "A sentence for tag"
of simple v_1.0 to avoid "" quotes

Removing a tag you no longer need:
$ hg tag --remove v1.0

Overriding a tag (you did not like the name) also exist ??



A usual thing is to clone the tagged version to a "stable" branch:
$ hg clone -r "Some text" local_branch stable_branch
---------------------
Project sub-branching by feature (and assigning to respective developers):

Master branch
|
|
------------------------------
| | |
fron-end middle-tier deployment-scripts

All branches are cloned from the master and teams work in isolation.

Flow of changes:
"Big picture" branches (release/milestones); people give them names, and talk about them in conversation.

"Little picture" branches are artefacts of the day-to-day activity of developing and merging changes. They expose the narrative of how the code was developed.

The easiest way to isolate a "big picture" branch in Mercurial is in a dedicated repository.
If you have an existing shared repository—let's call it myproject—that reaches a "1.0" milestone, you can start to prepare for future maintenance releases on top of version 1.0 by tagging the revision from which you prepared the 1.0 release.

$ cd myproject
$ hg tag v1.0

You can then clone a new shared myproject-1.0.1 repository as of that tag.


$ hg clone myproject
...
$ hg push myproject
--------------------------------------
Naming branches within one repository

Naming branches gives you a permanent record of which branch a changeset originated on. This gives you more context when you're trying to follow the history of a long-lived branchy project.

There is one default branch which is omitted as in: $ hg push

See the branches:
$ hg branches
default [cset]

to see the current branch:
$ hg branch
default

$ hg branch foo
marked working directory as branch foo

You need to makes changes (update a file) in the working dir and commit to see it appear:

$ hg branch
foo

$hg branches
default
foo

You can now update working dir with branch's content as if by revision:
$ hg update -r foo


For details see:
http://hgbook.red-bean.com/read/managing-releases-and-branchy-development.html



---------------
Patterns (can be used in say hg status
'glob:**.?' .c across all subdirectories
'glob:*.py'

-I (nclude) does the same:
hg status -I "*.dat"

-X (exclude) (grep -v )
$ hg status -X "**.jar" []

$ hg status 'glob:*.{in,py}'
? MANIFEST.in
? setup.py

$ hg status 'glob:**[nr-t]'
? MANIFEST.in
? src/xyzzy.txt
---------------------
typical-looking .hgignore file:

syntax: glob
# This line is a comment, and will be skipped.
# Empty lines are skipped too.

# Backup files left behind by the Emacs editor.
*~

# Lock files used by the Emacs editor.
# Notice that the "#" character is quoted with a backslash.
# This prevents it from being interpreted as starting a comment.
.\#*

# Temporary files used by the vim editor.
.*.swp

# A hidden file created by the Mac OS X Finder.
.DS_Store

----------------------

Hooks
http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html

Hook can be a script / Python function. Python hook is in-process and much faster an external script and there is no forking.
The keyword argument for a Python hook will also be named foo, while the environment variable for an external hook will be named HG_FOO

Script / function returns 1 is true, 0 is false. For return value, false (0) is OK, 1 is BAD/deny.
.hgrc / ini file:
Python script declaration:

[hooks]
commit.example = python:mymodule.submodule.myhook

When Mercurial runs the commit.example hook, it imports mymodule.submodule, looks for the callable object named myhook, and calls it.



3 Step process:
1. You create a batch
$ cat check_bug_id
#!/bin/sh
# check that a commit comment mentions a numeric bug id
hg log -r $1 --template {desc} | grep -q "bug *[0-9]"
I understand that the command is about grepping bug \d text in
the newest log entry output (referenced as {desc})created on e.g. commit

2. You update a the config file:
format of the command:
pretxncommit.
$ echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc

3. test it
$ echo a >> a
$ hg commit -m 'i am not mentioning a bug id'
The message does not contain the bug \d pattern, so when your pre commit txn hook is called and message is parsed, error code is returned:

transaction abort!
rollback completed
abort: pretxncommit.bug_id_required hook exited with status 1

4. So, to satisfy this requirement, you must go ahead and add:
$ hg commit -m 'i refer you to bug 10'

Should be OK.

Hooks calls can be traced with running hg with the -v (verbose) flag:
$ hg -v ....

-------------
Templating
http://hgbook.red-bean.com/read/customizing-the-output-of-mercurial.html

as in:
$ hg log --template 'i saw a changeset: {desc}\n'

{} parameters:
desc: String. The text of the changeset description.
files: List of strings. All files modified, added, or removed by this changeset.
file_adds: List of strings. Files added by this changeset.
file_dels: List of strings. Files removed by this changeset.
node: String. The changeset identification hash, as a 40-character hexadecimal string.
parents: List of strings. The parents of the changeset.
rev: Integer. The repository-local changeset revision number.
tags: List of strings. Any tags associated with the changeset.

Escape sequences: \n \r \t \ \{ \} \v (vertical tab)