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)