Installing Mercurial -- Mac OS X

Be sure to select the correct installer, depending on the version of Mac OS that you are using. Packages could be found at http://mercurial.berkwood.com/

Installing Mercurial -- Solaris

Sun internal users can use /pkg/local/bin/hg. Solaris packages are at OpenCSW Mercurial package.

Installing Mercurial -- Linux -- Fedora

1.0.1 is not available for older Fedora's (as in selenic's download site or Fedora RPMs). For newer Fedoras use "yum install mercurial"
and for older ones build Mercurial from sources.

Installing Mercurial -- Linux -- Ubuntu

Ubuntu provides Mercurial packages. Ubuntu version 9.04 (Jaunty Jackalope) installs version 1.1.2 with the command 'sudo apt-get install mercurial'. Older versions of Ubuntu generally install versions of Mercurial that are too old. Do not use them. Build Mercurial from sources instead (it is very easy) or see Sofeng's Blog instructions.

Configuring Mercurial

If you are using Windows, you probably want to convert newlines to CRLF in your checkout.
Mercurial does not do this by default, but you can edit Mercurial.ini in your installation
and make sure it includes

Even if you are not working on Windows, you may sometimes have files which may have CRLF in them.
If you commit those files and then try to push them, your push command will fail due to the forbidcrlf hook
on our servers. If you had made more commits after the one that committed the file with CRLF then it is harder
to get rid of that problematic commit. So the best way is to prevent that situation in the first place. If you have Mercurial 1.0 or later
this is easy. Just add the following hook to your Mercurial.ini on Windows, ~/.hgrc on Unix, or .hg/hgrc inside a repo.

[hooks]
pretxncommit.crlf = python:hgext.win32text.forbidcrlf

Be sure to configure your "user name" in the configuration file.
(Mercurial.ini on Windows, ~/.hgrc on Unix, or .hg/hgrc inside a repo.)
It should be your netbeans.org email address (based on your login ID).
Example:

[ui]
username = jhacker@netbeans.org

You may also include a display name using the usual email syntax.
This is useful since people may not recognize you by your login ID alone:

[ui]
username = John Q. Hacker <jhacker@netbeans.org>

Mercurial uses default HTTP ports (80 and 443), so if you use firewall, make sure that firewall permits connection to http://hg.netbeans.org/main for hg on these ports.
If you have to use a proxy for HTTPS, try adding to your global config file e.g.

http_proxy
host = webcache.uk.sun.com:8080

Mercurial also reads the environment variable http_proxy. Make sure to set it properly.

If one uses KDiff3 as a merge program, it is useful to use hgmerge.py script in order to avoid possible incorrect merges. More information about merge programs for mercurial can be found here. Example:

There are various repositories that are special clones of the above,
especially main. These function somewhat like branches in CVS:

release67 (for example): branched sources for the 6.7 release

core-main (for example): an integration repository for use by the Core team.

main-silver: development sources guaranteed to pass at least a basic build.

main-golden: development sources passing a full production build (safest but oldest).

Getting a working copy: cloning the NetBeans repository

To start working with the main NetBeans Mercurial repository you need to create a clone of it.
Every Mercurial repository is complete, self-contained, and independent.
It contains its own private copy of a project’s files and history.
A cloned repository remembers the location of the repository it was cloned from,
but it does not communicate with that repository, or any other, unless you tell it to.

Using a keyring

You can also avoid storing your password on disk if you use the
Mercurial keyring extension.
Install the extension (and the Python keyring library it requires)
according to the instructions on that page. Then add to your ~/.hgrc:

You will be prompted for your password just once, and thereafter it should be taken from a secure keyring.

Self-signed SSL certificate

As of Mercurial 1.7, the HTTPS certificate is checked, and since hg.netbeans.org uses a self-signed certificate, this results in a (legitimate) warning. See http://mercurial.selenic.com/wiki/CACertificates for background. The easiest fix with 1.7.4 or later is to add to your .hgrc:

Understanding the structure of the NetBeans Mercurial repository

hg clone http://hg.netbeans.org/main/ will create a main directory under your current directory.
(If you pass another argument, it will be used as an alternate directory name to create.)
The main directory then contains a full copy of the http://hg.netbeans.org/main/ repository with checked out sources.
The main/.hg directory contains all the Mercurial control files.

Most other directories under main are NetBeans modules, named according to an abbreviation of the module's code name base:
java.j2seproject,
api.progress,
openide.loaders,
etc.
If you are looking for a module that used to be in CVS, check nbbuild/translations.
The basic build infrastructure is in main/nbbuild.

Doing your first build

Building NetBeans uses Ant.
There is a top-level build.xml
which delegates to nbbuild/build.xml for convenience.
You need JDK 7 and Ant 1.8.4 to build the current development version.

$ cd main
$ ant

Note: you need to be connected to the network for the first build,
because it will fetch external binaries (JARs and ZIPs) from a server.
You will also need to be online when doing the first build after some update to external binaries.

Some users will need to set ANT_OPTS in ~/.antrc, e.g.

ANT_OPTS="-Xmx512m -XX:MaxPermSize=256m"

Committing changes

Mercurial's commit operation will change only your local copy of the NetBeans repository.
Example:

$ cd main
$ # edit some files...
$ hg pull -u# optional
$ hg ci

and enter a log message when prompted.
(Note: you should make the first line of the log a complete sentence as a summary.
Any additional lines can supply details.)

In case you want to integrate a fix and immediatelly share it with others (see hg push below), it is desirable to do hg pull -u first. This way you first make your sources up-to-date with the most recent changes done by others and you can hg push your changes without any need for merging.

If you only want to check in some files or directory, just specify them:

Adding new files

More info about operations on files could be found in the
Mercurial book.

Making changes visible to others

First check what changes will be propagated to the server:

$ cd main
$ hg out -pv

Then if you are ready to really push your changes, run:

$ cd main
$ hg push

(If you checked out just http://hg.netbeans.org/main/,
and did not configure an HTTPS URL for the default-push path as suggested above,
you will need to specify this full URL as a command argument.)

If someone else has pushed changes in the meantime (since you last pulled),
you need to pull their changes first and merge;
see the next section.

Note: the server checks some basic conditions about your push before accepting it.
In particular, if you tried to commit carriage returns (CRLF) in a text file,
this will be rejected.
You need to enable CRLF translation in your Hg settings.

Tip: if you are using Windows and you get a weird error message about SSL,
check if your Internet Explorer settings say to use a proxy.

Updating your sources from the server

To update your sources, you can use:

$ cd main
$ hg pull -u

This will pull other people's changes from the server into your repository.
It will also update your working copy to the latest version.

If you have made your own changes in this repository
(even in a completely unrelated directory),
you will need to merge your changes with other people's changes.
This requires running hg merge.

A convenient way to pull and merge at the same time
is to use the Fetch extension. Enable it:

Getting all repositories

If you want to retrieve other repositories like contrib,
just clone them in the right place:

cd main
hg clone http://hg.netbeans.org/main/contrib/

(It is also possible to use the
Forest extension
but this is not really necessary.)

You can open and build experimental modules normally, e.g.

ant -f contrib/quickfilechooser/build.xml nbm

Backing out bad changes

In most cases, if you make a mistake and want to fix it,
you should just edit sources to fix it and commit a new revision.
This preserves history of the mistake and its correction
and is suitable for routine programming errors.

If a whole big commit was wrong (e.g. someone else broke the build),
it is too much work to revert it manually.
For this case you can use hg backout to revert its effects.
(If the bad commit was not the last, you will need to merge
since the subsequent commits should still be in effect.)

If you commit something that you really cannot tolerate being in history
(e.g. legally forbidden files, passwords, ...)
it is possible to discard the commit only if you have not yet pushed it.
(Once it is on the server, it is permanent.)

If you have just committed the change and nothing else,
just run hg rollback.
Your working copy will still be modified;
you can hg revert if you need to.

Sometimes hg rollback cannot be used,
but it is still possible to kill off bad changesets.
The simplest way of doing this is to use the hg strip command,
added by the MQ extension:

[extensions]
mq =

If you strip out a changeset from your local repository,
it will be removed along with all descendant changesets.
Be careful. (The command will make a backup of the removed changesets just in case.)

You can also make a version of the repository that does not include the latest changes.
Use hg clone -r and pass in the "last known good" changeset ID.

Server hooks (abort: pretxnchangegroup.something hook failed)

hg.netbeans.org has a number of server hooks in place
to prevent common accidents from being committed permanently into the repository. The hooks are checking your changesets
one by one.

If you try to push some changesets and they are rejected for one of these reasons,
you will need to redo them before you can push. You can also use hg out command which could help you identify
which changeset is wrong.
If you have only made one commit, you can probably use hg rollback,
fix the problem, commit again, and push again.
If you have made several commits, the whole batch will be rejected, and you should

Use hg export -g to record the changes you made.

Use hg strip to pop off all the commits (unless the earliest ones are all OK).

Use hg import to reapply the changes, perhaps after fixing problems.

and then try to push again.

pretxnchangegroup.forbid_2heads - you need to merge before pushing. hg heads can print the heads for you local repository. If you don't have more than one head then you are pushing your changes with hg push -f command which could create new heads on server, you need to run hg fetch first.

Working with release branches

All the release branches are hosted in the repository releases. Typical workflow for these branches is to do all the fixes on the trunk and backport after QE verification.
This involves the question how the fixes/changes/changesets could be easily moved from one to repository to another.

graft

Assuming you are using Mercurial 2.0 or higher, the preferred way is the standard graft command. Assuming you have a clone of the repository releases, which should contain the original fix (since the default branch from main-silver is routinely copied to it), just make sure you are updated to the right release branch (e.g. release71_fixes) and run:

hg graft MYCHANGESETID

transplant

For older Mercurial releases, use the Transplant extension. First, you need to enable the transplant extension in releases/.hg/hgrc or ~/.hgrc:

[extensions]
transplant=
[defaults]
transplant = --log

If you have your changeset already reviewed then its import to release-branch repository would be as simple as running (substitute the right release branch name as needed):

cd releases
hg pull
hg up release71_fixes
hg transplant REV1 REV2

It will update your working directory to release branch and then apply the changes in revisions REV1 and REV2 to the release-branch. (You can specify only one changeset or as many as you need.) The new changesets are created in release-branch repository releases.
They will have the same date and username as the original;
the log message will additionally mention the original changeset.
Note that transplanting a changeset involves a merge operation
(the branch might be missing some context that was in the trunk)
so you may on occasion be asked to resolve conflicts
(see hg help transplant for more).

manual transplant

A more CVS-like method is to create a patch first and then apply it to the release-branch.
So the sequence of the commands would be following:

It should basically do the same job as using transplant extension.
(The graft and transplant commands adds some invisible metadata to the new changeset
saying that it is a transplant, so that is preferable to doing a manual diff import.)
This method has the advantage that you could edit the patch a bit
before applying it to the branch, if some pieces are only applicable to trunk,
but be very careful about applying a patch that QE has not tested.

Don't forget to push your changes when done.

Note:
There is known issue while using transplant and/or import/export for moving patches between clones on Windows. It is related to the CRLF conversion, see http://www.selenic.com/mercurial/bts/issue1077 for more details, or read below.
The more modern graft is probably unaffected since it uses merge rather than patch machinery.

Getting ready for work with clones

If you know when making the fix that it may be eligible for the release branch
then you do not need to backport/transplant at all.
Just make sure that the parent of the fix is present in the release branch.
Then you can simply pull your fix into the release.
For example, to make a fix for 6.7 Beta:

plus a lot of careful sanity checking
to make sure you are doing what you think you are doing.

If you want the module to live under a different relative path in the new repo,
you should use

(echo include mod; echo rename mod newmod) | ....

to move it during the conversion.
Otherwise you could use regular hg -R repo2 ren mod newmod at the end,
but this will consume additional disk space
(Hg bug #883).

Applying patches from another Hg branch on Windows

The command 'hg export' generates a patch in Unix encoding (LF) independently on hgext.win32text setup.
If you use patch.eol=crlf (as above) this should not be a problem for you.

Develop API review patches using MQ

For routine development you will simply make some changes, test, and commit.
However in special circumstances you may prefer to polish a patch for review by others.
In particular, API changes normally go through a
prereview process.
This is different from normal development because:

Changes must be reviewed in advance. In fact, the change could be rejected. If you are doing several reviews in parallel, it is quite possible you will commit them in a different order than you started.

Reviewers generally want to see the entire change as one patch. It is confusing to see you make a mistake in one patch and then fix it later.

The quality of the patch is especially important. You want it as small and clear as possible. If you find that some change was unnecessary, you want to delete it. If a new method was implemented in a confusing way, you want to rewrite it. This all ensures that reviewers see the smallest, clearest possible change.

For this style of development, MQ (Mercurial Queues) is ideal.
This is a powerful tool bundled with Mercurial for managing patches.
To get started, enable the MQ extension:

[extensions]
mq =

You must be sure to not pull (or fetch) with patches applied.
If you are a Unix user you can just

[hooks]
prechangegroup.mq-no-pull = ! hg qtop > /dev/null 2>&1

You will probably also want to use Git-format diffs.
This enhanced diff format captures file renames, among other things.
You can either turn this on for all Mercurial commands:

[diff]
git = 1

or just for MQ:

[defaults]
qdiff = --git
qnew = --git
qrefresh = --git

In your NetBeans source repository, set up a patch queue:

hg qinit

(Use -c if you also want to version it as a separate Hg repo.)

Now let's say you are working on fixing bug #123456
when you realize that it requires an API change.
Just make the API change as a local modification and try to use it - verify that it helps.
Do not commit anything.
Feel free to add, delete, or rename files as well as editing them
(using hg add, rm, ren as usual).

Now you can initialize a patch for this change.
Since you already have local modifications, use -f;
add -e to give an initial log message:

hg qnew -e -f 123456.diff

Now hg stat and hg di will show nothing -
because you have no modifications beyond what is saved in the patch.
hg tip will list a special temporary changeset for your working patch,
because your patch is applied, as you can see with hg qapp.

When you have submitted the issue for review
(keywords API API_REVIEW_FAST, assigned to apireviews),
attach the patch directly from .hg/patches/123456.diff,
or you can run hg qdi to produce a patch that also shows the base revision.
Add a reminder to your calendar to commit the patch in a week if there are no objections.

hg qpop -a to go back to unpatched sources and go about your normal work.
(Do not pull or push while you have patches applied!)

If reviewers request some changes in the following days,
hg qgo 123456 to reapply patch;
make whatever changes you want.
hg di will show changes from the last saved patch.
To update the saved patch, use hg qref,
at which point you can sanity-check it using hg qdi.
Then just attach the new version as before so reviewers can see the revised patch.

If you'd rather not attach every revision, you can also mail the patch easily:
hg email qtip will send it out to interested parties.
(Use -n to preview what would be mailed before you really do it!)
You need a little configuration, for example:

If some changes are made to the repository which causes your patch to not apply cleanly
after you last worked on it,
hg qpush or hg qgo will show some warnings and leave behind *.rej files
containing "hunks" of the patch which did not apply.
You need to look at these and figure out how to apply the equivalent to the new code.
(It is possible but quite tricky to run a standard 3-way merge tool to resolve conflicts;
a future version of MQ may make this more friendly.)
hg qref when you have everything the way you want it again.

If your review is accepted, you can easily commit the patch as a permanent change
(and remove it from the queue):

hg qfinish -a

and you can then push as usual.

If you have multiple active patches, bear in mind that in MQ patches are applied in series.
This means that if hg qser prints

123321.diff
123456.diff

and the two patches touch related files,
then 123456.diff may depend on 123321.diff and build on top of it.
If you want to ensure the patches are independent, just hg qpop -a,
edit .hg/patches/series to reorder your patches,
and run hg qgo 123456.diff to make sure it applies on its own.

Want to know more about MQ?
Try chapters 12
and 13
of the Mercurial book.

Using a named branch

Rather than using MQ, you may prefer to use a named branch in your team repository. This makes it easier to collaborate with team members; Hudson builds will ignore your branch until you merge it to trunk.

To start, pick a branch name. Avoid hyphens (-) since they can be confused with set subtraction in revset expressions, requiring a more cumbersome quoting syntax:

$ hg branch my_feature_123456
# ...edit...
$ hg ci -m 'normal work'

(When pushing changes, you may be prompted to use --new-branch to confirm that you want to add a new branch to the repository. Just be sure that you have reviewed the output of hg out -pv.)

To go back to the trunk:

$ hg up default

To go back to the branch:

$ hg up my_feature_123456

To synch with trunk, it is recommended that you make trunk the first merge parent, as this makes hg out -pv work intuitively, and generally makes merge conflicts easier to understand:

If you forget to "close" the branch, it will remain in the output of hg heads when --topo is not used, under the expectation that you are going to return to the branch later. To close the branch retroactively, just update to it and close it. You can also do so in bulk if you need to:

Setting up Mercurial for resolving merge conflicts

Before using Mercurial on production sources you should make sure you understand not only what merging does,
but also that your merge tool is correctly set up in the unusual case of a line-by-line merge conflict.
Let's make some dummy repositories to test a merge conflict.

We will use hg clone -r REV to simulate another person cloning a repository before some further changes were made.
You could equivalently switch back and forth between the repositories, but clone -r will be helpful in retrying the merge.

Now the second user, in the dupe repository clone, has committed changes against revision 58d574e6ba6e, effectively creating a new branch.
In this case we have intentionally committed conflicting changes to the same file.
When the second user tries to merge in changes from the first, Mercurial will look for a graphical merge tool and try to launch it.
If your Hg installation is configured correctly, this tool will be found, and you will be able to resolve the merge and save:

Here the merge tool has shown us that two parties changed one to both two and three
and we have resolved this by saying it should really be two and a half.

You can use hg glog to see the result graphically.
Note that while changeset IDs (the long hex hashes) stay the same,
sequence numbers are different from the original repository: 1 was pulled to this clone as 2
though it is still identified as de9c1703a8d3.

Unix users who prefer not to use graphical merge tools at all can choose to just get CVS-style conflict markers.
In this case you will need to edit the conflicted files, manually resolve the conflicts, and commit the merge when done.
You will need the command merge in your path (many systems put this in a package called rcs).
And in your ~/.profile or similar, add export HGMERGE=merge to use this simple tool.
Here is an example of the result:

Hg equivalents of common CVS commands

CVS checkout

Mercurial has no direct equivalent to the CVS checkout command;
you always have the entire repository with history on your computer.

$ hg clone http://hg.netbeans.org/main/ nb_all

The Mercurial command checkout is simply an alias for the update command.
This does no network operations but might be used to switch your working directory to an older revision.

CVS update

hg pull -u (possibly followed by hg merge and hg ci),
or hg fetch,
is the closest equivalent to cvs up.

CVS commit

hg ci followed by hg push together act similarly to cvs ci.

CVS "what-if" update

You can use the -p (patch) option to either incoming or outgoing.
This provides something similar to cvs -n up or cvs -n ci
to preview what will be pulled or pushed.
Example:

cd /path/to/repo1
hg in -p http://hg.netbeans.org/repo2/

CVS log -D...

To find changes between two builds, it does not in general suffice to use a date range, since the builds might have been made from slightly different branches. Better is to use the full history graph. Look up the newer and older changeset IDs in nb/build_info, then run:

hg log -r "::$newer & ! ::$older" -M -v

.cvsignore

CVS has a .cvsignore file in each directory
which can match files or subdirectories directly in that directory
using a simple glob syntax.

Hg uses a single .hgignore file at top level
which lists ignored files or subdirectories in the whole repository
using a choice of syntax, by default regular expression.

The initially created NB repositories will have .hgignore files
created by inspecting the old .cvsignore files (which are not copied over).
Some general patterns cover a lot of cases,
e.g. /nbproject/private$ ignores any such dir generically.
If you need to add new special-case ignore patterns,
just edit and commit this file.