Monotone Documentation
Monotone is a distributed version control tool. It can help automate many tedious and error-prone tasks in group software development.
Please be aware that monotone is a slightly unorthodox version control tool, and many of its concepts are similar — but subtly or significantly different — from concepts with similar names in other version control tools.
Complete table of contents
This chapter should familiarize you with the concepts, terminology, and behavior described in the remainder of the user manual. Please take a moment to read it, as later sections will assume familiarity with these terms.
Suppose you wish to modify a file file.txt on your computer. You begin with one version of the file, load it into an editor, make some changes, and save the file again. Doing so produces a new version of the file. We will say that the older version of the file was a parent, and the new version is a child, and that you have performed an edit between the parent and the child. We may draw the relationship between parent and child using a graph, where the arrow in the graph indicates the direction of the edit, from parent to child.

We may want to identify the parent and the child precisely, for sake of reference. To do so, we will compute a cryptographic hash function, called sha1, of each version. The details of this function are beyond the scope of this document; in summary, the sha1 function takes a version of a file and produces a short string of 20 bytes, which we will use to uniquely identify the version1. Now our graph does not refer to some “abstract” parent and child, but rather to the exact edit we performed between a specific parent and a specific child.

When dealing with versions of files, we will dispense with writing out “file names”, and identify versions purely by their sha1 value, which we will also refer to as their file ID. Using IDs alone will often help us accommodate the fact that people often wish to call files by different names. So now our graph of parent and child is just a relationship between two versions, only identified by ID.

Version control systems, such as monotone, are principally concerned
with the storage and management of multiple versions of some files.
One way to store multiple versions of a file is, literally, to save a
separate complete copy of the file, every time you make a
change. When necessary, monotone will save complete copies of your
files, compressed with the zlib compression format.

Often we find that successive versions of a file are very similar to one another, so storing multiple complete copies is a waste of space. In these cases, rather than store complete copies of each version of a file, we store a compact description of only the changes which are made between versions. Such a description of changes is called a delta.
Storing deltas between files is, practically speaking, as good as
storing complete versions of files. It lets you undo changes from a
new version, by applying the delta backwards, and lets your friends
change their old version of the file into the new version, by applying
the delta forwards. Deltas are usually smaller than full files, so
when possible monotone stores deltas, using a modified xdelta
format. The details of this format are beyond the scope of this
document.

After you have made many different files, you may wish to capture a “snapshot” of the versions of all the files in a particular collection. Since files are typically collected into trees in a file system, we say that you want to capture a version of your tree. Doing so will permit you to undo changes to multiple files at once, or send your friend a set of changes to many files at once.
To make a snapshot of a tree, we begin by writing a special file called a manifest. In fact, monotone will write this file for us, but we could write it ourselves too. It is just a plain text file, in a structured but human-readable format used by several parts of monotone. Each file entry of a manifest binds a specific name, as a full path from the root of the workspace, to a specific file ID, as the hash of its content. In this way, the manifest collects together the snapshot of the file names and contents you have at this point in time; other snapshots with other manifests can use different names for the same file, or different contents for the same name.
Other entries in the manifest format name directories or store file attrs, which we will cover later.

Now we note that a manifest is itself a file. Therefore a manifest can serve as input to the sha1 function, and thus every manifest has an ID of its own. By calculating the sha1 value of a manifest, we capture the state of our tree in a single manifest ID. In other words, the ID of the manifest essentially captures all the IDs and file names of every file in our tree, combined. So we may treat manifests and their IDs as snapshots of a tree of files, though lacking the actual contents of the files themselves.

As with versions of files, we may decide to store manifests in their entirety, or else we may store only a compact description of changes which occur between different versions of manifests. As with files, when possible monotone stores compact descriptions of changes between manifests; when necessary it stores complete versions of manifests.
Suppose you sit down to edit some files. Before you start working, you may record a manifest of the files, for reference sake. When you finish working, you may record another manifest. These “before and after” snapshots of the tree of files you worked on can serve as historical records of the set of changes, or changeset, that you made. In order to capture a “complete” view of history – both the changes made and the state of your file tree on either side of those changes – monotone builds a special composite file called a revision each time you make changes. Like manifests, revisions are ordinary text files which can be passed through the sha1 function and thus assigned a revision ID.

The content of a revision includes one or more changesets. These changesets make reference to file IDs, to describe how the tree changed. The revision also contains manifest IDs, as another way of describing the tree “before and after” the changeset — storing this information in two forms allows monotone to detect any bugs or corrupted data before they can enter your history. Finally and crucially, revisions also make reference to other revision IDs. This fact – that revisions include the IDs of other revisions – causes the set of revisions to join together into a historical chain of events, somewhat like a “linked list”. Each revision in the chain has a unique ID, which includes by reference all the revisions preceding it. Even if you undo a changeset, and return to a previously-visited manifest ID during the course of your edits, each revision will incorporate the ID of its predecessor, thus forming a new unique ID for each point in history.

Often, you will wish to make a statement about a revision, such as stating the reason that you made some changes, or stating the time at which you made the changes, or stating that the revision passes a test suite. Statements such as these can be thought of, generally, as a bundle of information with three parts:
For example, if you want to say that a particular revision was composed on April 4, 2003, you might make a statement like this:

In an ideal world, these are all the parts of a statement we would need in order to go about our work. In the real world, however, there are sometimes malicious people who would make false or misleading statements; so we need a way to verify that a particular person made a particular statement about a revision. We therefore will add two more pieces of information to our bundle:
When these 2 items accompany a statement, we call the total bundle of 5 items a certificate, or cert. A cert makes a statement in a secure fashion. The security of the signature in a cert is derived from the rsa cryptography system, the details of which are beyond the scope of this document.

Monotone uses certs extensively. Any “extra” information which needs to be stored, transmitted or retrieved — above and beyond files, manifests, and revisions — is kept in the form of certs. This includes change logs, time and date records, branch membership, authorship, test results, and more. When monotone makes a decision about storing, transmitting, or extracting files, manifests, or revisions, the decision is often based on certs it has seen, and the trustworthiness you assign to those certs.
The rsa cryptography system — and therefore monotone itself — requires that you exchange special “public” numbers with your friends, before they will trust certificates signed by you. These numbers are called public keys. Giving someone your public key does not give them the power to impersonate you, only to verify signatures made by you. Exchanging public keys should be done over a trusted medium, in person, or via a trusted third party. Advanced secure key exchange techniques are beyond the scope of this document.
Monotone moves information in and out of four different types of storage:
The keystore is a directory .monotone/keys in your home directory which contains copies of all your private keys. Each key is stored in a file whose name is the key identifier with some characters converted to underscores. When you use a key to sign a cert, the public half of that key is copied into your local database along with the cert.
All information passes through your local database, en route to some other destination. For example, when changes are made in a workspace, you may save those changes to your database, and later you may synchronize your database with someone else's. Monotone will not move information directly between a workspace and a remote database, or between workspaces. Your local database is always the “switching point” for communication.

A workspace is a tree of files in your file system, arranged according to the list of file paths and IDs in a particular manifest. A special directory called _MTN exists in the root of any workspace. Monotone keeps some special files in the _MTN directory, in order to track changes you make to your workspace. If you ever want to know if a directory is a monotone workspace, just look for this _MTN directory.
Aside from the special _MTN directory, a workspace is just a normal tree of files. You can directly edit the files in a workspace using a plain text editor or other program; monotone will automatically notice when you make any changes. If you wish to add files, remove files, or move files within your workspace, you must tell monotone explicitly what you are doing, as these actions cannot be deduced.
If you do not yet have a workspace, you can check out a workspace from a database, or construct one from scratch and add it into a database. As you work, you will occasionally commit changes you have made in a workspace to a database, and update a workspace to receive changes that have arrived in a database. Committing and updating take place purely between a database and a workspace; the network is not involved.

A database is a single, regular file. You can copy or back it up using standard methods. Typically you keep a database in your home directory. Databases are portable between different machine types. You can have multiple databases and divide your work between them, or keep everything in a single database if you prefer. You can dump portions of your database out as text, and read them back into other databases, or send them to your friends. Underneath, databases are accessed using a standard, robust data manager, which makes using even very large databases efficient. In dire emergencies, you can directly examine and manipulate a database using a simple SQL interface.
A database contains many files, manifests, revisions, and certificates, some of which are not immediately of interest, some of which may be unwanted or even false. It is a collection of information received from network servers, workspaces, and other databases. You can inspect and modify your databases without affecting your workspaces, and vice-versa.
Monotone knows how to exchange information in your database with other remote databases, using an interactive protocol called netsync. It supports three modes of exchange: pushing, pulling, and synchronizing. A pull operation copies data from a remote database to your local database. A push operation copies data from your local database to a remote database. A sync operation copies data both directions. In each case, only the data missing from the destination is copied. The netsync protocol calculates the data to send “on the fly” by exchanging partial hash values of each database.

In general, work flow with monotone involves 3 distinct stages:
The last stage of workflow is worth clarifying: monotone does not blindly apply all changes it receives from a remote database to your workspace. Doing so would be very dangerous, because remote databases are not always trustworthy systems. Rather, monotone evaluates the certificates it has received along with the changes, and decides which particular changes are safe and desirable to apply to your workspace.
You can always adjust the criteria monotone uses to judge the trustworthiness and desirability of changes in your database. But keep in mind that it always uses some criteria; receiving changes from a remote server is a different activity than applying changes to a workspace. Sometimes you may receive changes which monotone judges to be untrusted or bad; such changes may stay in your database but will not be applied to your workspace.
Remote databases, in other words, are just untrusted “buckets” of data, which you can trade with promiscuously. There is no trust implied in communication.
So far we have been talking about revisions as though each logically follows exactly one revision before it, in a simple sequence of revisions.

This is a rosy picture, but sometimes it does not work out this way. Sometimes when you make new revisions, other people are simultaneously making new revisions as well, and their revisions might be derived from the same parent as yours, or contain different changesets. Without loss of generality, we will assume simultaneous edits only happen two-at-a-time; in fact many more edits may happen at once but our reasoning will be the same.
We call this situation of simultaneous edits a fork, and will refer to the two children of a fork as the left child and right child. In a large collection of revisions with many people editing files, especially on many different computers spread all around the world, forks are a common occurrence.

If we analyze the changes in each child revision, we will often find that the changeset between the parent and the left child are unrelated to the changeset between the parent and the right child. When this happens, we can usually merge the fork, producing a common grandchild revision which contains both changesets.

Sometimes, people intentionally produce forks which are not supposed to be merged; perhaps they have agreed to work independently for a time, or wish to change their files in ways which are not logically compatible with each other. When someone produces a fork which is supposed to last for a while (or perhaps permanently) we say that the fork has produced a new branch. Branches tell monotone which revisions you would like to merge, and which you would like to keep separate.
You can see all the available branches using mtn list branches.
Branches are indicated with certs. The cert name branch is
reserved for use by monotone, for the purpose of identifying the
revisions which are members of a branch. A branch cert has a
symbolic “branch name” as its value. When we refer to “a branch”,
we mean all revisions with a common branch name in their branch
certs.
For example, suppose you are working on a program called “wobbler”.
You might develop many revisions of wobbler and then decide to split
your revisions into a “stable branch” and an “unstable branch”, to
help organize your work. In this case, you might call the new branches
“wobbler-stable” and “wobbler-unstable”. From then on, all
revisions in the stable branch would get a cert with name branch
and value wobbler-stable; all revisions in the unstable branch
would get a cert with name branch and value
wobbler-unstable. When a wobbler-stable revision forks,
the children of the fork will be merged. When a
wobbler-unstable revision forks, the children of the fork will
be merged. However, the wobbler-stable and
wobbler-unstable branches will not be merged together, despite
having a common ancestor.

For each branch, the set of revisions with no children is called the heads of the branch. Monotone can automatically locate, and attempt to merge, the heads of a branch. If it fails to automatically merge the heads, it may ask you for assistance or else fail cleanly, leaving the branch alone.
For example, if a fork's left child has a child of its own (a “left grandchild”), monotone will merge the fork's right child with the left grandchild, since those revisions are the heads of the branch. It will not merge the left child with the right child, because the left child is not a member of the heads.

When there is only one revision in the heads of a branch, we say that the heads are merged, or more generally that the branch is merged, since the heads is the logical set of candidates for any merging activity. If there are two or more revisions in the heads of a branch, and you ask to merge the branch, monotone will merge them two-at-a-time until there is only one.
The branch names used in the above section are fine for an example, but they would be bad to use in a real project. The reason is, monotone branch names must be globally unique, over all branches in the world. Otherwise, bad things can happen. Fortunately, we have a handy source of globally unique names — the DNS system.
When naming a branch, always prepend the reversed name of a host that
you control or are otherwise authorized to use. For example, monotone
development happens on the branch net.venge.monotone, because
venge.net belongs to monotone's primary author. The idea is that
this way, you can coordinate with other people using a host to make sure
there are no conflicts — in the example, monotone's primary author can
be certain that no-one else using venge.net will start up a
different program named monotone. If you work for Yoyodyne,
Inc. (owners of yoyodyne.com), then all your branch names should look
like com.yoyodyne.something.
What the something part looks like is up to you, but
usually the first part is the project name (the monotone in
net.venge.monotone), and then possibly more stuff after that to
describe a particular branch. For example, monotone's win32 support
was initially developed on the branch net.venge.monotone.win32.
(For more information, see Naming Conventions.)
This chapter illustrates the basic uses of monotone by means of an example, fictional software project.
Before we walk through the tutorial, there are two minor issues to address: standard options and revision selectors.
Before operating monotone, two important command-line options should be explained.
Monotone will cache the settings for these options in your workspace, so ordinarily once you have checked out a project, you will not need to specify them again. We will therefore only mention these arguments in the first example.
Many commands require you to supply 40-character sha1 values as arguments, which identify revisions. These “revision IDs” are tedious to type, so monotone permits you to supply “revision selectors” rather than complete revision IDs. Selectors are a more “human friendly” way of specifying revisions by combining certificate values into unique identifiers. This “selector” mechanism can be used anywhere a revision ID would normally be used. For details on selector syntax, see Selectors.
We are now ready to explore our fictional project.
Our fictional project involves 3 programmers cooperating to write firmware for a robot, the JuiceBot 7, which dispenses fruit juice. The programmers are named Jim, Abe and Beth.
In our example the programmers work privately on laptops, and are usually disconnected from the network. They share no storage system. Thus when each programmer enters a command, it affects only his or her own computer, unless otherwise stated.
In the following, our fictional project team will work through several version control tasks. Some tasks must be done by each member of our example team; other tasks involve only one member.
The first step Jim, Abe and Beth each need to perform is to create a new database. This is done with the mtn db init command, providing a --db option to specify the location of the new database. Each programmer creates their own database, which will reside in their home directory and store all the revisions, files and manifests they work on. Monotone requires this step as an explicit command, to prevent spurious creation of databases when an invalid --db option is given.
In real life, most people prefer to keep one database for each project
they work on. If we followed that convention here in the tutorial,
though, then all the databases would be called juicebot.mtn, and
that would make things more confusing to read. So instead, we'll have
them each name their database after themselves.
Thus Jim issues the command:
$ mtn db init --db=~/jim.mtn
Abe issues the command:
$ mtn db init --db=~/abe.mtn
And Beth issues the command:
$ mtn db init --db=~/beth.mtn
Now Jim, Abe and Beth must each generate an rsa key pair for themselves. This step requires choosing a key identifier. Typical key identifiers are similar to email addresses, possibly modified with some prefix or suffix to distinguish multiple keys held by the same owner. Our example programmers will use their email addresses at the fictional “juicebot.co.jp” domain name. When we ask for a key to be generated, monotone will ask us for a passphrase. This phrase is used to encrypt the key when storing it on disk, as a security measure.
Jim does the following:
$ mtn genkey jim@juicebot.co.jp
mtn: generating key-pair 'jim@juicebot.co.jp'
enter passphrase for key ID [jim@juicebot.co.jp] : <Jim enters his passphrase>
confirm passphrase for key ID [jim@juicebot.co.jp]: <Jim confirms his passphrase>
mtn: storing key-pair 'jim@juicebot.co.jp' in /home/jim/.monotone/keys
Abe does something similar:
$ mtn genkey abe@juicebot.co.jp
mtn: generating key-pair 'abe@juicebot.co.jp'
enter passphrase for key ID [abe@juicebot.co.jp] : <Abe enters his passphrase>
confirm passphrase for key ID [abe@juicebot.co.jp]: <Abe confirms his passphrase>
mtn: storing key-pair 'abe@juicebot.co.jp' in /home/abe/.monotone/keys
as does Beth:
$ mtn genkey beth@juicebot.co.jp
mtn: generating key-pair 'beth@juicebot.co.jp'
enter passphrase for key ID [beth@juicebot.co.jp] : <Beth enters her passphrase>
confirm passphrase for key ID [beth@juicebot.co.jp]: <Beth confirms her passphrase>
mtn: storing key-pair 'beth@juicebot.co.jp' in /home/beth/.monotone/keys
Each programmer has now generated a key pair and placed it in their keystore. Each can list the keys in their keystore, to ensure the correct key was generated. For example, Jim might see this:
$ mtn list keys
[public keys]
9e9e9ef1d515ad58bfaa5cf282b4a872d8fda00c jim@juicebot.co.jp (*)
(*) - only in /home/jim/.monotone/keys/
[private keys]
771ace046c27770a99e5fddfa99c9247260b5401 jim@juicebot.co.jp
The hexadecimal string printed out before each key name is a fingerprint of the key, and can be used to verify that the key you have stored under a given name is the one you intended to store. Monotone will never permit one keystore to store two keys with the same name or the same fingerprint.
This output shows one private and one public key stored under the name
jim@juicebot.co.jp, so it indicates that Jim's key-pair has been
successfully generated and stored. On subsequent commands, Jim will need
to re-enter his passphrase in order to perform security-sensitive
tasks. Jim isn't very worried about security (and, more importantly, it
simplifies the tutorial text to skip the passphrase prompts) so he
decides to store his passphrase in his monotonerc file. He does
this by writing a hook function which returns the passphrase:
$ mkdir ~/.monotone
$ cat >>~/.monotone/monotonerc
function get_passphrase(keypair_id)
return "jimsekret"
end
^D
Now whenever monotone needs his passphrase, it will call this function
instead of prompting him to type it. Note that we are appending the new
hook to the (possibly existing) file. We do this to avoid losing other
changes by mistake; therefore, be sure to check that no other
get_passphrase function appears in the configuration file.
Abe and Beth do the same, with their secret passphrases.
Before he can begin work on the project, Jim needs to create a workspace — a directory whose contents monotone will keep track of. Often, one works on projects that someone else has started, and creates workspaces with the checkout command, which you'll learn about later. Jim is starting a new project, though, so he does something a little bit different. He uses the mtn setup command to create a new workspace.
This command creates the named directory (if it doesn't already exist), and creates the _MTN directory within it. The _MTN directory is how monotone recognizes that a directory is a workspace, and monotone stores some bookkeeping files within it. For instance, command line values for the --db, --branch or --key options to the setup command will be cached in a file called _MTN/options, so you don't have to keep passing them to monotone all the time.
He chooses jp.co.juicebot.jb7 as a branch name. (See
Naming Conventions for more information about appropriate branch
names.) Jim then creates his workspace:
/home/jim$ mtn --db=jim.mtn --branch=jp.co.juicebot.jb7 setup juice
/home/jim$ cd juice
/home/jim/juice$
Notice that Jim has changed his current directory to his newly created workspace. For the rest of this example we will assume that everyone issues all further monotone commands from their workspace directories.
Next Jim decides to add some files to the project. He writes up a file containing the prototypes for the JuiceBot 7:
$ mkdir include
$ cat >include/jb.h
/* Standard JuiceBot hw interface */
#define FLOW_JUICE 0x1
#define POLL_JUICE 0x2
int spoutctl(int port, int cmd, void *x);
/* JuiceBot 7 API */
#define APPLE_SPOUT 0x7e
#define BANANA_SPOUT 0x7f
void dispense_apple_juice ();
void dispense_banana_juice ();
^D
Then adds a couple skeleton source files which he wants Abe and Beth to fill in:
$ mkdir src
$ cat >src/apple.c
#include "jb.h"
void
dispense_apple_juice()
{
/* Fill this in please, Abe. */
}
^D
$ cat >src/banana.c
#include "jb.h"
void
dispense_banana_juice()
{
/* Fill this in please, Beth. */
}
^D
Now Jim tells monotone to add these files to its record of his workspace. He specifies one filename and one directory; monotone recursively scans the directory and adds all its files.
$ mtn add include/jb.h src
mtn: adding include/jb.h to workspace manifest
mtn: adding src/apple.c to workspace manifest
mtn: adding src/banana.c to workspace manifest
This command produces a record of Jim's intentions in a special file called _MTN/revision, stored in the workspace. The file is plain text:
$ cat _MTN/revision
format_version "1"
new_manifest [2098eddbe833046174de28172a813150a6cbda7b]
old_revision []
add_file "include/jb.h"
content [3b12b2d0b31439bd50976633db1895cff8b19da0]
add_file "src/apple.c"
content [2650ffc660dd00a08b659b883b65a060cac7e560]
add_file "src/banana.c"
content [e8f147e5b4d5667f3228b7bba1c5c1e639f5db9f]
You will never have to look at this file, but it is nice to know that it is there.
Jim then gets up from his machine to get a coffee. When he returns he has forgotten what he was doing. He asks monotone:
$ mtn status
Current branch: jp.co.juicebot.jb7
Changes against parent :
added include/jb.h
added src/apple.c
added src/banana.c
The output of this command tells Jim that his edits, so far, constitute only the addition of some files.
Jim wants to see the actual details of the files he added, however, so he runs a command which prints out the status and a GNU “unified diff” of the patches involved in the changeset:
$ mtn diff
#
# old_revision []
#
# add_file "include/jb.h"
# content [3b12b2d0b31439bd50976633db1895cff8b19da0]
#
# add_file "src/apple.c"
# content [2650ffc660dd00a08b659b883b65a060cac7e560]
#
# add_file "src/banana.c"
# content [e8f147e5b4d5667f3228b7bba1c5c1e639f5db9f]
#
============================================================================
--- include/jb.h
+++ include/jb.h 3b12b2d0b31439bd50976633db1895cff8b19da0
@ -0,0 +1,13 @
+/* Standard JuiceBot hw interface */
+
+#define FLOW_JUICE 0x1
+#define POLL_JUICE 0x2
+#define SET_INTR 0x3
+int spoutctl(int port, int cmd, void *x);
+
+/* JuiceBot 7 API */
+
+#define APPLE_SPOUT 0x7e
+#define BANANA_SPOUT 0x7f
+void dispense_apple_juice ();
+void dispense_banana_juice ();
============================================================================
--- src/apple.c
+++ src/apple.c 2650ffc660dd00a08b659b883b65a060cac7e560
@ -0,0 +1,7 @
+#include "jb.h"
+
+void
+dispense_apple_juice()
+{
+ /* Fill this in please, Abe. */
+}
============================================================================
--- src/banana.c
+++ src/banana.c e8f147e5b4d5667f3228b7bba1c5c1e639f5db9f
@ -0,0 +1,7 @
+#include "jb.h"
+
+void
+dispense_banana_juice()
+{
+ /* Fill this in please, Beth. */
+}
Satisfied with the work he's done, Jim wants to save his changes. He then commits his workspace, which causes monotone to process the _MTN/revision file and record the file contents, manifest, and revision into the database. Since he provided a branch name when he ran setup, monotone will use this as the default branch name when he commits.
$ mtn commit --message="initial checkin of project"
mtn: beginning commit on branch 'jp.co.juicebot.jb7'
mtn: committed revision 2e24d49a48adf9acf3a1b6391a080008cbef9c21
When monotone committed Jim's revision, it updated _MTN/revision to record the workspace's new base revision ID. Jim can use this revision ID in the future, as an argument to the checkout command, if he wishes to return to this revision:
$ mtn automate get_base_revision_id
2e24d49a48adf9acf3a1b6391a080008cbef9c21
Monotone also generated a number of certificates attached to the new revision, and made sure that the database contained a copy of Jim's public key. These certs store metadata about the commit. Jim can ask monotone for a list of certs on this revision.
$ mtn ls certs 2e24d49a48adf9acf3a1b6391a080008cbef9c21
-----------------------------------------------------------------
Key : jim@juicebot.co.jp
Sig : ok
Name : branch
Value : jp.co.juicebot.jb7
-----------------------------------------------------------------
Key : jim@juicebot.co.jp
Sig : ok
Name : date
Value : 2004-10-26T02:53:08
-----------------------------------------------------------------
Key : jim@juicebot.co.jp
Sig : ok
Name : author
Value : jim@juicebot.co.jp
-----------------------------------------------------------------
Key : jim@juicebot.co.jp
Sig : ok
Name : changelog
Value : initial checkin of project
The output of this command has a block for each cert found. Each block
has 4 significant pieces of information. The first indicates the
signer of the cert, in this case jim@juicebot.co.jp. The
second indicates whether this cert is “ok”, meaning whether the
rsa signature provided is correct for the cert data. The third is
the cert name, and the fourth is the cert value. This list shows us
that monotone has confirmed that, according to
jim@juicebot.co.jp, the revision
2e24d49a48adf9acf3a1b6391a080008cbef9c21 is a member of the
branch jp.co.juicebot.jb7, written by
jim@juicebot.co.jp, with the given date and changelog.
It is important to keep in mind that revisions are not “in” or “out” of a branch in any global sense, nor are any of these cert values true or false in any global sense. Each cert indicates that some person – in this case Jim – would like to associate a revision with some value; it is up to you to decide if you want to accept that association.
Jim can now check the status of his branch using the “heads” command, which lists all the head revisions in the branch:
$ mtn heads
branch 'jp.co.juicebot.jb7' is currently merged:
2e24d49a48adf9acf3a1b6391a080008cbef9c21 jim@juicebot.co.jp 2004-10-26T02:53:08
The output of this command tells us that there is only one current
“head” revision in the branch jp.co.juicebot.jb7, and it is
the revision Jim just committed. A head revision is one without any
descendents. Since Jim has not committed any changes to this revision
yet, it has no descendents.
Jim now decides he will make his base revision available to his employees. To do this, he arranges for Abe and Beth to synchronise their databases with his, over the network. There are two pre-requisites for this: first, he has to get a copy of each of their public keys; then, he has to tell monotone that the holders of those keys are permitted to access his database. Finally, with these pre-requisites in place, he needs to tell monotone to provide network access to his database.
First, Abe exports his public key:
$ mtn --db=~/abe.mtn pubkey abe@juicebot.co.jp >~/abe.pubkey
His public key is just a plain block of ASCII text:
$ cat ~/abe.pubkey
[pubkey abe@juicebot.co.jp]
MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCbaVff9SF78FiB/1nUdmjbU/TtPyQqe/fW
CDg7hSg1yY/hWgClXE9FI0bHtjPMIx1kBOig09AkCT7tBXM9z6iGWxTBhSR7D/qsJQGPorOD
DO7xovIHthMbZZ9FnvyB/BCyiibdWgGT0Gtq94OKdvCRNuT59e5v9L4pBkvajb+IzQIBEQ==
[end]
Beth also exports her public key:
$ mtn --db=~/beth.mtn pubkey beth@juicebot.co.jp >~/beth.pubkey
Then Abe and Beth both send their keys to Jim. The keys are not secret, but the team members must be relatively certain that they are exchanging keys with the person they intend to trust, and not some malicious person pretending to be a team member. Key exchange may involve sending keys over an encrypted medium, or meeting in person to exchange physical copies, or any number of techniques. All that matters, ultimately, is that Jim receives both Abe's and Beth's key in a way that he can be sure of.
So eventually, after key exchange, Jim has the public key files in his home directory. He tells monotone to read the associated key packets into his database:
$ cat ~/abe.pubkey ~/beth.pubkey | mtn --db=~/jim.mtn read
mtn: read 2 packets
Now Jim's monotone is able to identify Beth and Abe, and he is ready to give them permission to access his database. He does this by editing a pair of small files in his ~/.monotone directory:
$ cat >>~/.monotone/read-permissions
pattern "*"
allow "abe@juicebot.co.jp"
allow "beth@juicebot.co.jp"
^D
$ cat >>~/.monotone/write-permissions
abe@juicebot.co.jp
beth@juicebot.co.jp
^D
These files are read by the default monotone hooks that will decide whether remote monotone users will be allowed access to Jim's database, identified by the named keys.
Jim then makes sure that his TCP port 4691 is open to incoming connections, adjusting his firewall settings as necessary, and runs the monotone serve command:
$ mtn --db=jim.mtn serve "jp.co.juicebot.jb7*"
This command starts monotone listening on all network interfaces of
his laptop on the default port 4691, serving any branch matching
jp.co.juicebot.jb7*. This will naturally include the
jp.co.juicebot.jb7 branch, and any sub-branches. The quotes
around "jp.co.juicebot.jb7*" are there to protect the *
from expansion by the shell; they have no meaning to monotone.
With Jim's server preparations done, now Abe is ready to fetch Jim's code. To do this he issues the monotone sync command:
$ mtn --db=abe.mtn sync jim-laptop.juicebot.co.jp "jp.co.juicebot.jb7*"
mtn: setting default server to jim-laptop.juicebot.co.jp
mtn: setting default branch include pattern to 'jp.co.juicebot.jb7*'
mtn: setting default branch exclude pattern to ''
mtn: connecting to jim-laptop.juicebot.co.jp
mtn: first time connecting to server jim-laptop.juicebot.co.jp:4691
mtn: I'll assume it's really them, but you might want to double-check
mtn: their key's fingerprint: 9e9e9ef1d515ad58bfaa5cf282b4a872d8fda00c
mtn: warning: saving public key for jim@juicebot.co.jp to database
mtn: finding items to synchronize:
mtn: bytes in | bytes out | revs in | revs out | revs written
mtn: 2587 | 1025 | 1 | 0 | 1
mtn: successful exchange with jim-laptop.juicebot.co.jp
Abe now has, in his database, a copy of everything Jim put in the branch. Therefore Abe can disconnect from the expensive network connection he's on and work locally for a while. Remember that, in monotone, work is done between workspaces in the filesystem and the local database; network connectivity is necessary only when that work is to be shared with others.
As we follow the juicebot team through the next several steps, we'll see them run the sync command again with Jim, and work will flow both ways. The first time you sync a new database, monotone remembers the server and branch patterns you use, and makes them the default for future operations.
At the end of each exchange, information about all changes in the branch known to each database have been sent to the other party - including the work of the third team member that had previously been exchanged. As well as allowing each team member to learn about the others' work, this also means that each party's laptop contains a backup of the others' work too.
Jim, Abe and Beth will continue working like this while they're getting started, and we'll revisit the issue of network service with them a little later as the project grows.
Abe decides to do some work on his part of the code. He has a copy of
Jim's database contents, but cannot edit any of that data yet. He
begins his editing by checking out the head of the
jp.co.juicebot.jb7 branch into a workspace, so he can edit
it:
$ mtn --db=abe.mtn --branch=jp.co.juicebot.jb7 checkout .
Monotone unpacks the set of files in the head revision's manifest directly into Abe's current directory. (If he had specified something other than . at the end, monotone would have created that directory and unpacked the files into it.) Abe then opens up one of the files, src/apple.c, and edits it:
$ vi src/apple.c
<Abe writes some apple-juice dispensing code>
The file src/apple.c has now been changed. Abe gets up to answer a phone call, and when he returns to his work he has forgotten what he changed. He can ask monotone for details:
$ mtn diff
#
# old_revision [2e24d49a48adf9acf3a1b6391a080008cbef9c21]
#
# patch "src/apple.c"
# from [2650ffc660dd00a08b659b883b65a060cac7e560]
# to [e2c418703c863eabe70f9bde988765406f885fd0]
#
============================================================================
--- src/apple.c 2650ffc660dd00a08b659b883b65a060cac7e560
+++ src/apple.c e2c418703c863eabe70f9bde988765406f885fd0
@ -1,7 +1,10 @
#include "jb.h"
void
dispense_apple_juice()
{
- /* Fill this in please, Abe. */
+ spoutctl(APPLE_SPOUT, FLOW_JUICE, 1);
+ while (spoutctl(APPLE_SPOUT, POLL_JUICE, 1) == 0)
+ usleep (1000);
+ spoutctl(APPLE_SPOUT, FLOW_JUICE, 0);
}
Satisfied with his day's work, Abe decides to commit.
$ mtn commit
mtn: beginning commit on branch 'jp.co.juicebot.jb7'
Abe neglected to provide a --message option specifying the change log on the command line and the file _MTN/log is empty because he did not document his changes there. Monotone therefore invokes an external “log message editor” — typically an editor like vi — with an explanation of the changes being committed and the opportunity to enter a log message.
polling implementation of src/apple.c
MTN:
MTN: ----------------------------------------------------------------------
MTN: Enter Log. Lines beginning with `MTN:' are removed automatically
MTN:
MTN: format_version "1"
MTN:
MTN: new_manifest [b33cb337dccf21d6673f462d677a6010b60699d1]
MTN:
MTN: old_revision [2e24d49a48adf9acf3a1b6391a080008cbef9c21]
MTN:
MTN: patch "src/apple.c"
MTN: from [2650ffc660dd00a08b659b883b65a060cac7e560]
MTN: to [e2c418703c863eabe70f9bde988765406f885fd0]
MTN:
MTN: ----------------------------------------------------------------------
MTN:
Abe enters a single line above the explanatory message, saying “polling implementation of src/apple.c”. He then saves the file and quits the editor. Monotone deletes all the lines beginning with “MTN:” and leaves only Abe's short message. Returning to the shell, Abe's commit completes:
mtn: committed revision 70decb4b31a8227a629c0e364495286c5c75f979
Abe then sends his new revision back to Jim:
$ mtn sync
mtn: connecting to jim-laptop.juicebot.co.jp
mtn: finding items to synchronize:
mtn: certs | keys | revisions
mtn: 8 | 2 | 2
mtn: bytes in | bytes out | revs in | revs out | revs written
mtn: 615 | 2822 | 0 | 1 | 0
mtn: successful exchange with jim-laptop.juicebot.co.jp
Beth does a similar sequence. First she syncs her database with Jim's:
$ mtn --db=beth.mtn sync jim-laptop.juicebot.co.jp "jp.co.juicebot.jb7*"
mtn: setting default server to jim-laptop.juicebot.co.jp
mtn: setting default branch include pattern to 'jp.co.juicebot.jb7*'
mtn: setting default branch exclude pattern to ''
mtn: connecting to jim-laptop.juicebot.co.jp
mtn: first time connecting to server jim-laptop.juicebot.co.jp:4691
mtn: I'll assume it's really them, but you might want to double-check
mtn: their key's fingerprint: 9e9e9ef1d515ad58bfaa5cf282b4a872d8fda00c
mtn: warning: saving public key for jim@juicebot.co.jp to database
mtn: finding items to synchronize:
mtn: bytes in | bytes out | revs in | revs out | revs written
mtn: 4601 | 1239 | 2 | 0 | 1
mtn: verifying new revisions (this may take a while)
mtn: bytes in | bytes out | revs in | revs out | revs written
mtn: 4601 | 1285 | 2 | 0 | 2
mtn: successful exchange with jim-laptop.juicebot.co.jp
She checks out a copy of the tree from her database:
$ mtn --db=beth.mtn --branch=jp.co.juicebot.jb7 checkout .
She edits the file src/banana.c:
$ vi src/banana.c
<Beth writes some banana-juice dispensing code>
and logs her changes in _MTN/log right away so she does not forget what she has done like Abe.
$ vi _MTN/log
* src/banana.c: Added polling implementation
Later, she commits her work. Monotone again invokes an external editor for her to edit her log message, but this time it fills in the messages she's written so far, and she simply checks them over one last time before finishing her commit:
$ mtn commit
mtn: beginning commit on branch 'jp.co.juicebot.jb7'
mtn: committed revision 80ef9c9d251d39074d37e72abf4897e0bbae1cfb
And she syncs with Jim again:
$ mtn sync
mtn: connecting to jim-laptop.juicebot.co.jp
mtn: finding items to synchronize:
mtn: certs | keys | revisions
mtn: 12 | 3 | 3
mtn: bytes in | bytes out | revs in | revs out | revs written
mtn: 709 | 2879 | 0 | 1 | 0
mtn: successful exchange with jim-laptop.juicebot.co.jp
Careful readers will note that, in the previous section, the JuiceBot company's work was perfectly serialized:
The result of this ordering is that Jim's work entirely preceded Abe's work, which entirely preceded Beth's work. Moreover, each worker was fully informed of the “up-stream” worker's actions, and produced purely derivative, “down-stream” work:
This is a simple, but sadly unrealistic, ordering of events. In real companies or work groups, people often work in parallel, diverging from commonly known revisions and merging their work together, sometime after each unit of work is complete.
Monotone supports this diverge/merge style of operation naturally; any time two revisions diverge from a common parent revision, we say that the revision graph has a fork in it. Forks can happen at any time, and require no coordination between workers. In fact any interleaving of the previous events would work equally well; with one exception: if forks were produced, someone would eventually have to run the merge command, and possibly resolve any conflicts in the fork.
To illustrate this, we return to our workers Beth and Abe. Suppose Jim sends out an email saying that the current polling juice dispensers use too much CPU time, and must be rewritten to use the JuiceBot's interrupt system. Beth wakes up first and begins working immediately, basing her work off the revision 80ef9... which is currently in her workspace:
$ vi src/banana.c
<Beth changes her banana-juice dispenser to use interrupts>
Beth finishes and examines her changes:
$ mtn diff
#
# old_revision [80ef9c9d251d39074d37e72abf4897e0bbae1cfb]
#
# patch "src/banana.c"
# from [7381d6b3adfddaf16dc0fdb05e0f2d1873e3132a]
# to [5e6622cf5c8805bcbd50921ce7db86dad40f2ec6]
#
============================================================================
--- src/banana.c 7381d6b3adfddaf16dc0fdb05e0f2d1873e3132a
+++ src/banana.c 5e6622cf5c8805bcbd50921ce7db86dad40f2ec6
@ -1,10 +1,15 @
#include "jb.h"
+static void
+shut_off_banana()
+{
+ spoutctl(BANANA_SPOUT, SET_INTR, 0);
+ spoutctl(BANANA_SPOUT, FLOW_JUICE, 0);
+}
+
void
-dispense_banana_juice()
+dispense_banana_juice()
{
+ spoutctl(BANANA_SPOUT, SET_INTR, &shut_off_banana);
spoutctl(BANANA_SPOUT, FLOW_JUICE, 1);
- while (spoutctl(BANANA_SPOUT, POLL_JUICE, 1) == 0)
- usleep (1000);
- spoutctl(BANANA_SPOUT, FLOW_JUICE, 0);
}
She commits her work:
$ mtn commit --message="interrupt implementation of src/banana.c"
mtn: beginning commit on branch 'jp.co.juicebot.jb7'
mtn: committed revision 8b41b5399a564494993063287a737d26ede3dee4
And she syncs with Jim:
$ mtn sync
Unfortunately, before Beth managed to sync with Jim, Abe had woken up and implemented a similar interrupt-based apple juice dispenser, but his workspace is 70dec..., which is still “upstream” of Beth's.
$ vi apple.c
<Abe changes his apple-juice dispenser to use interrupts>
Thus when Abe commits, he unknowingly creates a fork:
$ mtn commit --message="interrupt implementation of src/apple.c"
Abe does not see the fork yet; Abe has not actually seen any of Beth's work yet, because he has not synchronized with Jim. Since he has new work to contribute, however, he now syncs:
$ mtn sync
Now Jim and Abe will be aware of the fork. Jim sees it when he sits down at his desk and asks monotone for the current set of heads of the branch:
$ mtn heads
mtn: branch 'jp.co.juicebot.jb7' is currently unmerged:
39969614e5a14316c7ffefc588771f491c709152 abe@juicebot.co.jp 2004-10-26T02:53:16
8b41b5399a564494993063287a737d26ede3dee4 beth@juicebot.co.jp 2004-10-26T02:53:15
Clearly there are two heads to the branch: it contains an un-merged fork. Beth will not yet know about the fork, but in this case it doesn't matter: anyone can merge the fork, and since there are no conflicts Jim does so himself:
$ mtn merge
mtn: starting with revision 1 / 2
mtn: merging with revision 2 / 2
mtn: [source] 39969614e5a14316c7ffefc588771f491c709152
mtn: [source] 8b41b5399a564494993063287a737d26ede3dee4
mtn: common ancestor 70decb4b31a8227a629c0e364495286c5c75f979 abe@juicebot.co.jp 2004-10-26T:02:50:01 found
mtn: trying 3-way merge
mtn: [merged] da499b9d9465a0e003a4c6b2909102ef98bf4e6d
mtn: your workspaces have not been updated
The output of this command shows Jim that two heads were found, combined via a 3-way merge with their ancestor, and saved to a new revision. This happened automatically, because the changes between the common ancestor and heads did not conflict. If there had been a conflict, monotone would have invoked an external merging tool to help resolve it.
After merging, the branch has a single head again, and Jim updates his workspace.
$ mtn update
mtn: selected update target da499b9d9465a0e003a4c6b2909102ef98bf4e6d
mtn: updating src/apple.c to f088e24beb43ab1468d7243e36ce214a559bdc96
mtn: updating src/banana.c to 5e6622cf5c8805bcbd50921ce7db86dad40f2ec6
mtn: updated to base revision da499b9d9465a0e003a4c6b2909102ef98bf4e6d
The update command selected an update target — in this case the newly merged head — and performed an in-memory merge between Jim's workspace and the chosen target. The result was then written to Jim's workspace. If Jim's workspace had any uncommitted changes in it, they would have been merged with the update in exactly the same manner as the merge of multiple committed heads.
Monotone makes very little distinction between a “pre-commit” merge (an update) and a “post-commit” merge. Both sorts of merge use the exact same algorithm. The major difference concerns the recoverability of the pre-merge state: if you commit your work first, and merge after committing, then even if the merge somehow fails (due to difficulty in a manual merge step, for instance), your committed state is still safe. If you update, on the other hand, you are requesting that monotone directly modify your workspace, and while monotone will try hard not to break anything, this process is inherently more open to error. It is therefore recommended that you commit your work first, before merging.
If you have previously used another version control system, this may at first seem surprising; there are some systems where you are required to update, and risk the above problems, before you can commit. Monotone, however, was designed with this problem in mind, and thus always allows you to commit before merging. A good rule of thumb is to only use update in workspaces with no local modifications, or when you actually want to work against a different base revision (perhaps because finishing your change turns out to require some fixes made in another revision, or because you discover that you have accidentally started working against a revision that contains unrelated bugs, and need to back out to a working revision for testing).
So by now you're familiar with making changes, sharing them with other people, and integrating your changes with their changes. Sometimes, though, you may want to make some changes, and not integrate them with other people's — or at least not right away. One way to do this would be to simply never run mtn merge; but it would quickly become confusing to try and keep track of which changes were in which revisions. This is where branches are useful.
Continuing our example, suppose that Jim is so impressed by Beth's work on banana juice support that he assigns her to work on the JuiceBot 7's surprise new feature: muffins. In the mean time, Abe will continue working on the JuiceBot's basic juice-related functions.
The changes required to support muffins are somewhat complicated, and Beth is worried that her work might destabilize the program, and interfere with Abe's work. In fact, she isn't even sure her first attempt will turn out to be the right approach; she might work on it for a while and then decide it was a bad idea, and should be discarded. For all these reasons, she decides that she will work on a branch, and then once she is satisfied with the new code, she will merge back onto the mainline.
She decides that since main development is in branch
jp.co.juicebot.jb7, she will use branch
jp.co.juicebot.jb7.muffins. So, she makes the first few edits to
the new muffins code, and commits it on a new branch by simply passing
--branch to commit:
$ mtn commit --branch=jp.co.juicebot.jb7.muffins --message='autobake framework'
mtn: beginning commit on branch 'jp.co.juicebot.jb7.muffins'
mtn: committed revision d33caefd61823ecbb605c39ffb84705dec449857
That's all there is to it — there is now a
jp.co.juicebot.jb7.muffins branch, with her initial checkin on
it. She can make further checkins from the same workspace, and they
will automatically go to the muffins branch; if anyone else wants to
help her work on muffins, they can check out that branch as usual.
Of course, while Beth is working on the new muffins code, Abe is still making fixes to the main line. Occasionally, Beth wants to integrate his latest work into the muffins branch, so that her version doesn't fall too far behind. She does this by using the propagate command:
$ mtn propagate jp.co.juicebot.jb7 jp.co.juicebot.jb7.muffins
mtn: propagating jp.co.juicebot.jb7 -> jp.co.juicebot.jb7.muffins
mtn: [source] da003f115752ac6e4750b89aaca9dbba178ac80c
mtn: [target] d0e5c93bb61e5fd25a0dadf41426f209b73f40af
mtn: common ancestor 853b8c7ac5689181d4b958504adfb5d07fd959ab jim@juicebot.co.jp 2004-10-26T:12:44:23 found
mtn: trying 3-way merge
mtn: [merged] 89585b3c5e51a5a75f5d1a05dda859c5b7dde52f
The propagate merges all of the new changes on one branch onto another.
When the muffins code is eventually stable and ready to be integrated into the main line of development, she simply propagates the other way:
$ mtn propagate jp.co.juicebot.jb7.muffins jp.co.juicebot.jb7
mtn: propagating jp.co.juicebot.jb7.muffins -> jp.co.juicebot.jb7
mtn: [source] 4e48e2c9a3d2ca8a708cb0cc545700544efb5021
mtn: [target] bd29b2bfd07644ab370f50e0d68f26dcfd3bb4af
mtn: common ancestor 652b1035343281a0d2a5de79919f9a31a30c9028 jim@juicebot.co.jp 2004-10-26T:15:25:05 found
mtn: [merged] 03f7495b51cc70b76872ed019d19dee1b73e89b6
Monotone always records the full history of all merges, and is designed to handle an arbitrarily complicated graph of changes. You can make a branch, then branch off from that branch, propagate changes between arbitrary branches, and so on; monotone will track all of it, and do something sensible for each merge. Of course, it is still probably a good idea to come up with some organization of branches and a plan for which should be merged to which other ones. Monotone may keep track of graphs of arbitrary complexity — but you will have more trouble. Whatever arrangement of branches you come up with, though, monotone should be able to handle it.
Up until now, Jim has been using his laptop and database as a sort of “central server” for the company; Abe and Beth have been syncing with Jim, and learning of each other's work via Jim's database. This has worked fine while the product has been in early development; Jim has good network connectivity in Japan, and has been staying home concentrating on programming. He has been able to leave his laptop connected and running all the time, while his employees in different time-zones work and sync their databases. This is now starting to change, and two problems are starting to cause occasional difficulties.
This doesn't prevent them doing any work, but it does have some uncomfortable consequences: they're more likely to have to manually merge conflicting changes when they finally sync up and discover they've both come up with slightly different fixes for the same bug in the meantime, and they're more exposed to loss of work if one of them suffers a disk failure before they've had a chance to sync that work with another database.
The level of project activity is picking up, and there are more and more changes to be synced in the narrower window of time while Jim is connected. He finds he sometimes needs to take down the server process to do this local work, further exacerbating the first problem.
The juicebot team are resourceful, and by now quite used to working independently. While Jim has been away travelling, Abe and Beth have come up with their own solution to the first problem: they'll run servers from their databases, setting them up just like Jim did previously. That way, if Jim's database is offline, either Beth or Abe can run the serve command and provide access for the other to sync with. Beth also has the idea to create a second database for the serve process, and to sync her development database with that server locally, avoiding locking contention between multiple monotone processes on the one database file.
When Jim reappears, the next person to sync with him will often pass him information about both employees' work that they've sync'ed with eachother in the meantime, just as he used to do. In fact, Jim now finds it more convenient to initiate the sync with one of the other servers when he has a spare moment and dynamic connectivity from a hotel room or airport. Changes will flow between servers automatically as clients access them and trade with one another.
This gets them by for a while, but there are still occasional inconveniences. Abe and Beth live in very different time-zones, and don't always have reliable network connectivity, so sometimes Jim finds that neither of them is online to sync with when he has the chance. Jim now also has several customers interested in beta-testing the new code, and following changes as the bugs and issues they report are addressed.
Jim decides it's time for a permanent server they can all sync with; this way, everyone always knows where to go to get the latest changes, and people can push their changes out without first calling their friends and making sure that they have their servers running.
Jim has rented some web server space on a service provider's shared
system for the JuiceBot Inc. public website, www.juicebot.co.jp;
he thinks this server will be a good place to host the central monotone
server too. He sets up a new monotone database on the server,
generates a new key specially for the server (so he doesn't have to
expose his own development private key on the shared system), and loads
in the team-members' keys:
$ mtn --db=server.mtn db init
$ mtn genkey monotone-server@www.juicebot.co.jp
mtn: generating key-pair 'monotone-server@www.juicebot.co.jp'
enter passphrase for key ID [monotone-server@www.juicebot.co.jp] : <Jim enters a new passphrase>
confirm passphrase for key ID [monotone-server@www.juicebot.co.jp]: <Jim confirms the passphrase>
mtn: storing key-pair 'monotone-server@www.juicebot.co.jp' in /home/jim/.monotone/keys
$ cat abe.pubkey beth.pubkey jim.pubkey | mtn --db=server.mtn read
mtn: read 3 packets
For the team members, he sets up the permissions files on the server
much like before — except that of course he needs to also grant his
jim@juicebot.co.jp key permission to access the new server. For
the beta-testers, Jim wants to allow them read-only access just to the
main JuiceBot 7 development line, but not to any of the sub-branches
where other experimental development is going on. He adds some lines at
the top of the ~/.monotone/read-permissions on the server, above
the broader permissions given to team-members. See the Hook Reference for get_netsync_read_permitted for more details; the
resulting file looks like this:
comment "Provide beta-testers with specific read-only access"
pattern "jp.co.juicebot.jb7"
allow "beta1@juicebot.co.jp"
allow "beta2@juicebot.co.jp"
continue "true"
comment "Fall-through, and allow staff access to all branches"
pattern "*"
allow "abe@juicebot.co.jp"
allow "beth@juicebot.co.jp"
allow "jim@juicebot.co.jp"
Jim could log in and start the monotone process manually from his shell
account on the server, perhaps under a program like screen to let it
stay running while he's away. This would be one way of giving it the
server-key's passphrase each startup, but he wants to make sure that the
server is up all the time; if the host reboots while he's travelling and
the monotone server is down until he next logs in, things aren't much
better than before. For the server to start automatically each time,
he'll need to use the get_passphrase hook in the server's
.monotonerc file again.
Because he's running on a shared server, Jim needs to be a little more restrictive about which interfaces and addresses his new server process will listen on. He should only accept connections at the address used for his website, because some of the provider's other customers might also want to publish their own monotone projects on this host. Jim uses the --bind=address:port argument like so:
$ mtn --db=server.mtn --bind=www.juicebot.co.jp serve "jp.co.juicebot.jb7*"
This will start monotone listening on the default port (4691), but only
on the IP address associated with www.juicebot.co.jp. Jim can do
this because his hosting provider has given him a dedicated IP address
for his website. If the hosting provider offered only a single shared
IP address belonging to the server, each customer could bind a different
port number on that address.
While he's first testing the setup, Jim uses --bind=localhost:1234. This causes the monotone process to listen only to port 1234 on the loopback interface 127.0.0.1, which is not accessible from the network, so Jim doesn't expose an open port to the rest of the world until he's satisfied with the permissions configuration. You can cause monotone to listen on all interfaces on port 1234 by leaving out the address part like --bind=:1234.
When he's satisfied the server is set up correctly, Jim does an initial sync with the new database, filling it with all the revision history currently on his laptop. While Jim has been busy setting up the server, Abe and Beth have kept working; the server will catch up with their latest changes when they next sync, too.
All of the team members now want to sync with the new monotone server by default. Previously, they had been syncing with Jim's laptop by default, even if they occasionally specified another team-member's server on the command line when Jim was away, because monotone had remembered the first server and branch patterns used in database Vars. These vars can be seen as follows:
$ mtn list vars
database: default-exclude-pattern
database: default-include-pattern jp.co.juicebot.jb7*
database: default-server jim-laptop.juicebot.co.jp
known-servers: jim-laptop.juicebot.co.jp 9e9e9ef1d515ad58bfaa5cf282b4a872d8fda00c
known-servers: abe-laptop.juicebot.co.jp a2bb16a183247af4133621f7f5aefb21a9d13855
known-servers: www.juicebot.co.jp 120a99ch93b4f174432c13d3e3e9f2234aa92612
The team members can reset their local database vars accordingly:
$ mtn set database default-server www.juicebot.co.jp
With their new server, the juicebot team have gained the convenience of a readily available common point of reference for syncs. However, they also know that this is there only as a convenience, and doesn't prevent them working as they did before:
Hopefully, their new server won't ever be down, but sometimes they might be working together while away from ready network access — fixing up the last few issues and finalising presentation materials while travelling to a sales conference, for example. The server will learn of these changes on the next sync.
They now develop a new habit out of courtesy, though — they try not to leave multiple heads and unmerged changes on the server, at least not for long. This saves them from repeating work, and also helps prevent confusion for the beta-testers. When each team member is ready to sync, they develop the habit of doing a pull from the server first. If new revisions were received from the server, they first merge their new revisions with the head(s) from the server, and finally sync to publish their merged changes as one. If the last sync happens to pull in new revisions again from the server, it means someone else has deposited new work at the same time, and another merge and sync would probably be polite.
He does, however, take a copy of the server's private key, so he can restore that if necessary.
jp.co.juicebot.www, and keep a backup of that content too.
Now he can use monotone to work on the website offline, and let other team members add and edit the content; he can also preview changes locally before updating the production content. He keeps a workspace checkout of this content in the webroot on the server, and runs a monotone update in there when he wants to bring the public web site up to date. Later, he'll think about using monotone's Quality Assurance mechanisms and Event Notification Hooks, so that the web server can update itself automatically when appropriate new revisions are received.
In monotone, the important trust consideration is on the signed content, rather than on the replication path by which that content arrived in your database.
This chapter covers slightly less common aspects of using monotone. Some users of monotone will find these helpful, though possibly not all. We assume that you have read through the taxonomy and tutorial, and possibly spent some time playing with the program to familiarize yourself with its operation.
Monotone's database synchronization system is based on a protocol
called netsync. By default, monotone transports this protocol over a
plain TCP connection, but this is not the only transport monotone can
use. It can also transport netsync through SSH, or any program which
can provide a full-duplex connection over stdio.
When a monotone client initiates a push, pull, or sync operation, it parses the first command-line argument as a URI and calls a lua hook to convert that URI into a connection command. If the lua hook returns a connection command, monotone spawns the command locally and speaks netsync over a pipe connected to the command's standard I/O handles.
If the lua hook does not return a connection command, monotone attempts to parse the command-line argument as a TCP address – a hostname with an optional port number – connects a TCP socket the host and port, and speaks netsync over the socket.
By default, monotone understands two URI schemes:
ssh://[user@]hostname[:port]/path/to/db.mtn,
to synchronize between private databases on hosts accessible only
through SSH. (These paths are absolute; to refer to a path relative
to a home directory, use
ssh://host-part/~/relative/path.mtn or
ssh://host-part/~user/relative/path.mtn.)
file:/path/to/db.mtn, to synchronize between local databases.
In the case of SSH URIs, the ssh program must be in your command execution path, either $PATH on Unix-like systems or %PATH% on Windows systems. Monotone will execute ssh as a subprocess, running mtn serve on the other end of the SSH connection. You will need mtn to be in the command execution path of the remote shell environment.
In the case of File URIs, mtn is run locally, so must be in your command execution path.
In both cases, the database specified in the URI needs to exist already, and will be locked for the duration of the synchronization operation. Also note that monotone's default transport authentication is disabled over these transports, to reduce the complexity of configuration and eliminate redundant protocol cost.
Additional URI schemes can be supported by customization of the lua
hooks get_netsync_connect_command and
use_transport_auth. For details on these hooks, see
Netsync Transport Hooks.
Revisions can be specified on the monotone command line, precisely, by entering the entire 40-character hexadecimal sha1 code. This can be cumbersome, so monotone also allows a more general syntax called “selectors” which is less precise but more “human friendly”. Any command which expects a precise revision ID can also accept a selector in its place; in fact a revision ID is just a special type of selector which is very precise.
Some selector examples are helpful in clarifying the idea:
a432a432
graydon@pobox.com/2004-04graydon@pobox.com in April 2004.
"jrh@example.org/2 weeks ago"jrh@example.org 2 weeks ago.
graydon/net.venge.monotone.win32/yesterdaynet.venge.monotone.win32 branch, written by
graydon, yesterday.
A moment's examination reveals that these specifications are “fuzzy” and indeed may return multiple values, or may be ambiguous. When ambiguity arises, monotone will inform you that more detail is required, and list various possibilities. The precise specification of selectors follows.
A selector is a combination of a selector type, which is a single
ASCII character, followed by a : character and a selector
string. All selectors strings except for selector type c
are just values. The value is matched against identifiers or certs,
depending on its type, in an attempt to match a single revision.
Selectors are matched as prefixes. The current set of selection
types are:
c. The selector string has the syntax
name or name=value. The former syntax will
select any revision that has a cert with that name, regardless of
value; the latter will match any revision that has a cert with that
name and value. Values to match for can have shell wildcards. For
example, c:tag matches all revisions that have a tag, and
c:tag=monotone-0.25 will match the revision tagged
monotone-0.25. (See also the t selector below.)
a. For example, a:graydon matches
author certs where the cert value contains graydon.
b. For example, b:net.venge.monotone matches
branch certs where the cert value is net.venge.monotone.
Values to match for can have shell wildcards. If you give a bare b:
monotone will require you to be in a workspace, and will use the branch
value recorded in your _MTN/options file.
h. For example, h:net.venge.monotone matches
branch certs where the cert value is net.venge.monotone and
the associated revision is a head revision on that branch. Values to match
for can have shell wildcards like the branch selector. If you give a bare
h: monotone will require you to be in a workspace, and use the branch
recorded in your _MTN/options file.
d. For example, d:2004-04 matches
date certs where the cert value begins with
2004-04. This selector also accepts expanded date syntax (see below).
e. For example, e:2004-04-25 matches
date certs where the cert value is less or equal than
2004-04-25T00:00:00. If the time component is unspecified,
monotone will assume 00:00:00. This selector also accepts expanded date
syntax (see below)
l. For example, l:2004-04-25 matches
date certs where the cert value is strictly greater than
2004-04-25T00:00:00. If the time component is unspecified,
monotone will assume 00:00:00. This selector also accepts expanded date
syntax (see below)
i. For example, i:0f3a matches
revision IDs which begin with 0f3a.
t. For example, t:monotone-0.11 matches
tag certs where the cert value begins with monotone-0.11.
Values to match for can have shell wildcards.
Further selector types may be added in the future.
Selectors may be combined with the / character. The combination
acts as database intersection (or logical and). For example,
the selector a:graydon/d:2004-04 can be used to select a
revision which has an author cert beginning with graydon
as well as a date cert beginning with 2004-04. The
/ character can be escaped using the \ character if necessary.
Before selectors are passed to the database, they are expanded using a
lua hook: expand_selector. The default definition of this hook
attempts to guess a number of common forms for selection, allowing you
to omit selector types in many cases. For example, the hook guesses
that the typeless selector jrh@example.org is an author
selector, due to its syntactic form, so modifies it to read
a:jrh@example.org. This hook will generally assign a selector
type to values which “look like” partial hex strings, email
addresses, branch names, or date specifications. For the complete
source code of the hook, see Hook Reference.
All date-related selectors (d, e, l) support an
english-like syntax similar to CVS. This syntax is expanded to the
numeric format by a lua hook: expand_date.
The allowed date formats are:
e and l selectors assume time 00:00:00
e and l selectors assume
time 00:00:00
number of
minutes|hours.
number of
days|weeks|months|years. e and l selectors assume time
00:00:00
e and l selectors assume the first
day of month and time 00:00:00.
The time component, if supplied, must be complete to the second.
For the complete source code of the hook, see Hook Reference.
If, after expansion, a selector still has no type, it is matched as a
special “unknown” selector type, which will match either a tag, an
author, or a branch. This costs slightly more database access, but
often permits simple selection using an author's login name and a
date. For example, the selector
graydon/net.venge.monotone.win32/yesterday would pass through
the selector graydon as an unknown selector; so long as there
are no branches or tags beginning with the string graydon this
is just as effective as specifying a:graydon.
Several monotone commands accept optional pathname... arguments in order to establish a “restriction”. Restrictions are used to limit the files and directories these commands examine for changes when comparing the workspace to the revision it is based on. Restricting a command to a specified set of files or directories simply ignores changes to files or directories not included by the restriction.
The following commands all support restrictions using optional pathname... arguments:
Including either the old or new name of a renamed file or directory will cause both names to be included in a restriction. If in doubt, the status command can be used to “test” a set of pathnames to ensure that the expected files are included or excluded by a restriction.
Commands which support restrictions also support the --depth=n option, where n specifies the maximum number of directories to descend. For example, n=0 disables recursion, n=1 means descend at most one directory, and so on.
The update command does not allow for updates to a restricted set of files, which may be slightly different than other version control systems. Partial updates don't really make sense in monotone, as they would leave the workspace based on a revision that doesn't exist in the database, starting an entirely new line of development.
The restrictions facility also allows commands to operate from within a subdirectory of the workspace. By default, the entire workspace is always examined for changes. However, specifying an explicit "." pathname to a command will restrict it to the current subdirectory. Note that this is quite different from other version control systems and may seem somewhat surprising.
The expectation is that requiring a single "." to restrict to the current subdirectory should be simple to use. While the alternative, defaulting to restricting to the current subdirectory, would require a somewhat complicated ../../.. sequence to remove the restriction and operate on the whole tree.
This default was chosen because monotone versions whole project trees and generally expects to commit all changes in the workspace as a single atomic unit. Other version control systems often version individual files or directories and may not support atomic commits at all.
When working from within a subdirectory of the workspace all paths specified to monotone commands must be relative to the current subdirectory.
Monotone only stores a single _MTN directory at the root of a workspace. Because of this, a search is done to find the _MTN directory in case a command is executed from within a subdirectory of a workspace. Before a command is executed, the search for a workspace directory is done by traversing parent directories until an _MTN directory is found or the filesystem root is reached. Upon finding an _MTN directory, the _MTN/options file is read for default options. The --root option may be used to stop the search early, before reaching the root of the physical filesystem.
Many monotone commands don't require a workspace and will simply proceed with no default options if no _MTN directory is found. However, some monotone commands do require a workspace and will fail if no _MTN directory can be found.
The checkout and setup commands create a new workspace and initialize a new _MTN/options file based on their current option settings.
People often want to write programs that call monotone — for example, to create a graphical interface to monotone's functionality, or to automate some task. For most programs, if you want to do this sort of thing, you just call the command line interface, and do some sort of parsing of the output. Monotone's output, however, is designed for humans: it's localized, it tries to prompt the user with helpful information depending on their request, if it detects that something unusual is happening it may give different output in an attempt to make this clear to the user, and so on. As a result, it is not particularly suitable for programs to parse.
Rather than trying to design output to work for both humans and computers, and serving neither audience well, we elected to create a separate interface to make programmatically extracting information from monotone easier. The command line interface has a command automate; this command has subcommands that print various sorts of information on standard output, in simple, consistent, and easily parseable form.
For details of this interface, see Automation.
Fairly often, in order to accomplish its job, monotone has to look at your workspace and figure out what has been changed in it since your last commit. Commands that do this include status, diff, update, commit, and others. There are two different techniques it can use to do this. The default, which is sufficient for most projects, is to simply read every file in the workspace, compute their sha1 hash, and compare them to the hashes monotone has stored. This is very safe and reliable, and turns out to be fast enough for most projects. However, on very large projects, ones whose source trees are many megabytes in size, it can become unacceptably slow.
The other technique, known as inodeprints, is designed for this situation. When running in inodeprints mode, monotone does not read the whole workspace; rather, it keeps a cache of interesting information about each file (its size, its last modification time, and so on), and skips reading any file for which these values have not changed. This is inherently somewhat less safe, and, as mentioned above, unnecessary for most projects, so it is disabled by default.
If you do determine that it is necessary to use inodeprints with your project, it is simple to enable them. Simply run mtn refresh_inodeprints; this will enable inodeprints mode and generate an initial cache. If you ever wish to turn them off again, simply delete the file _MTN/inodeprints. You can at any time delete or truncate the _MTN/inodeprints file; monotone uses it only as a cache and will continue to operate correctly.
Normally, instead of enabling this up on a per-workspace basis, you
will want to simply define the use_inodeprints hook to return
true; this will automatically enable inodeprints mode in any new
workspaces you create. See Hook Reference for details.
Monotone was constructed to serve both as a version control tool and as a quality assurance tool. The quality assurance features permit users to ignore, or “filter out”, versions which do not meet their criteria for quality. This section describes the way monotone represents and reasons about quality information.
Monotone often views the collection of revisions as a directed graph,
in which revisions are the nodes and changes between revisions are the
edges. We call this the revision graph. The revision graph has a
number of important subgraphs, many of which overlap. For example,
each branch is a subgraph of the revision graph, containing only the
nodes carrying a particular branch cert.
Many of monotone's operations involve searching the revision graph for the ancestors or descendents of a particular revision, or extracting the “heads” of a subgraph, which is the subgraph's set of nodes with no descendents. For example, when you run the update command, monotone searches the subgraph consisting of descendents of the base revision of the current workspace, trying to locate a unique head to update the base revision to.
Monotone's quality assurance mechanisms are mostly based on restricting the subgraph each command operates on. There are two methods used to restrict the subgraph:
branch certificates, you
can require that specific code reviewers have approved of each edge in
the subgraph you focus on.
testresult certificates, you
can require that the endpoints of an update operation have a
certificate asserting that the revision in question passed a certain
test, or testsuite.
The evaluation of trust is done on a cert-by-cert basis by calling a
set of lua hooks: get_revision_cert_trust,
get_manifest_cert_trust and get_file_cert_trust. These
hooks are only called when a cert has at least one good signature from
a known key, and are passed all the keys which have signed the
cert, as well as the cert's ID, name and value. The hook can then
evaluate the set of signers, as a group, and decide whether to grant
or deny trust to the assertion made by the cert.
The evaluation of testresults is controlled by the
accept_testresult_change hook. This hook is called when
selecting update candidates, and is passed a pair of tables describing
the testresult certs present on the source and proposed
destination of an update. Only if the change in test results are
deemed “acceptable” does monotone actually select an update target
to merge into your workspace.
For details on these hooks, see the Hook Reference.
Every monotone database has a set of vars associated with it. Vars are simple configuration variables that monotone refers to in some circumstances; they are used for configuration that monotone needs to be able to modify itself, and that should be per-database (rather than per-user or per-workspace, both of which are supported by monotonerc scripts). Vars are local to a database, and never transferred by netsync.
A var is a name = value pairing inside a domain. Domains define what the vars inside it are used for; for instance, one domain might contain database-global settings, and particular vars inside it would define things like that database's default netsync server. Another domain might contain key fingerprints for servers that monotone has interacted with in the past, to detect man-in-the-middle attacks; the vars inside this domain would map server names to their fingerprints.
You can set vars with the set command, delete them with the unset command, and see them with the ls vars command. See the documentation for these specific commands for more details.
There are several pre-defined domains that monotone knows about:
databasedefault-exclude-patterndefault-include-patterndefault-serverknown-serversA monotone workspace consists of control files and non-control files. Each type of file can be versioned or non-versioned. These classifications lead to four groups of files:
Control files contain special content formatted for use by monotone. Versioned files are recorded in a monotone database and have their state tracked as they are modified.
If a control file is versioned, it is considered part of the state of the workspace, and will be recorded as a manifest entry. If a control file is not versioned, it is used to manage the state of the workspace, but it not considered an intrinsic part of it.
Most files you manage with monotone will be versioned non-control files. For example, if you keep source code or documents in a monotone database, they are versioned non-control files. Non-versioned, non-control files in your workspace are generally temporary or junk files, such as backups made by editors or object files made by compilers. Such files are ignored by monotone.
Control files are identified by their names. Non-control files can have any name except the names reserved for control files. The names of control files follow a regular pattern:
The general intention is that versioned control files are things that you may want to edit directly. In comparison, you should never have to edit non-versioned control files directly; monotone should do that for you whenever it is appropriate. However, both are documented here, just in case a situation arises where you need to go “under the hood”.
The following control files are currently used. More control files may be added in the future, but they will follow the patterns given above.
Every workspace has a base revision, which is the revision that was
originally checked out to create that workspace. When the workspace
is committed, the base revision is considered to be the ancestor of
the committed revision.
Every certificate has a name. Some names have meaning which is built
in to monotone, others may be used for customization by a particular
user, site, or community. If you wish to define custom certificates,
you should prefix such certificate names with x-. For example,
if you want to make a certificate describing the existence of security
vulnerabilities in a revision, you might wish to create a certificate
called x-vulnerability. Monotone reserves all names which do
not begin with x- for possible internal use. If an x-
certificate becomes widely used, monotone will likely adopt it as a
reserved cert name and standardize its semantics.
Most reserved certificate names have no meaning yet; some do. Usually monotone is also responsible for generating many of these certs as part of normal operation, such as during a commit. Others will be added explicitly via other commands, like tag or approve.
As well as carrying other information, certs (and combinations of certs)
are useful for identifying revisions with Selectors; in
particular, this is the primary purpose of the tag cert.
The pre-defined, reserved certificate names are:
authorbranchbranch cert
associates a revision with a branch. The revision is said to be “in
the branch” named by the cert. The cert is generated when you commit
a revision, either directly with the commit command or
indirectly with the merge or propagate commands. The
branch certs are read and directly interpreted by many
monotone commands, and play a fundamental role in organizing work in
any monotone database.
changelogcommentcomment will be
shown together with changelog certs by the log command.
datetagtestresult0
or 1. It is generated by the testresult command and
represents the results of running a particular test on the underlying
revision. Typically you will make a separate signing key for each test
you intend to run on revisions. This cert influences the
update algorithm.
Some names in monotone are private to your work, such as filenames. Other names are potentially visible outside your project, such as rsa key identifiers or branch names. It is possible that if you choose such names carelessly, you will choose a name which someone else in the world is using, and subsequently you may cause confusion when your work and theirs is received simultaneously by some third party.
We therefore recommend two naming conventions:
graydon@pobox.com.
net.venge.monotone branch, because the
author owns the DNS domain venge.net.
Monotone contains a support for storing persistent attributes on files and directories, generally known as attrs for short. An attr associates a simple name/value pair with a file or directory, and is stored in the manifest. Attrs are first-class versioned data; they can be changed in a workspace, and those changes will be saved when the workspace is committed. The merger knows how to intelligently merge attrs.
The attribute mechanism was originally motivated by the fact that some people like to store executable programs in version control systems, and would like the programs to remain executable when they check out a workspace. For example, the configure shell script commonly shipped with many programs should be executable. Similarly, some people would like to store devices, symbolic links, read-only files, and all manner of extra attributes of a file, not directly related to a file's data content.
Monotone comes with support for some attrs built-in; for instance, if
an executable file is given to mtn add, then it will
automatically mark the new file with a mtn:execute attr, and
when the file is checked out later, the executable bit will be set
automatically. (Of course, if it is checked out on Windows, which
does not support the executable bit, then the executable bit will not
be set. However, monotone will still know that the attr is set, and
Windows users can view and modify the attr like anyone else.)
Attrs in the current workspace can be seen and modified using the mtn attr command; see Workspace. Attrs can also be found by examining any manifest directly.
You can tell monotone to automatically take actions based on these
attributes by defining hooks; see the attr_functions entry in
Hook Reference. Every time your workspace is written to,
monotone will run the corresponding hooks registered for each attr in
your workspace. This way, you can extend the vocabulary of attrs
understood by monotone simply by writing new hooks.
You can make up your own attrs for anything you find useful; the
mechanism is fully general. (If you make up some particularly useful
ones, we may even be interested in adding support to monotone proper.)
We only ask that if you do use custom attrs, you use some prefix for
them besides mtn:; attrs beginning with mtn: are
reserved for monotone's own use.
Monotone has two merging modes, controlled by the manual_merge
attribute.
By default all files are merged in automatic mode, unless the
manual_merge attribute for that file is present and
true.
In automatic mode files are merged without user intervention, using
monotone internal three-way merging algorithm.
Only if there are conflicts or an ancestor is not available monotone
switches to manual mode, essentially escalating the merging to the user.
When working in manual mode, monotone invokes the merge3 hook
to start an user defined external merge tool.
If the tool terminates without writing the merged file, monotone aborts the
merging, reverting any changes made.
By redefining the aforementioned hooks the user can not only choose a
preferred merge tool, but even select different programs for different
file types. For example, gimp for .png files, OpenOffice.org for
.doc, and so on.
Starting with monotone 0.20, the manual_merge attribute is
automatically set at add time for all “binary” files, i.e. all files
for which the binary_file hook returns true.
Currently, this means all files with extension gif, jpeg, png, bz2, gz
and zip, plus files containing at least one of the following
bytes:
0x00 thru 0x06
0x0E thru 0x1a
0x1c thru 0x1f
The attribute could also be manually forced or removed using the
appropriate monotone commands.
Remember that monotone switches to manual merging even if only one of
the files to be merged has the manual_merge attribute set.
While the state of your database is logically captured in terms of a packet stream, it is sometimes necessary or desirable (especially while monotone is still in active development) to modify the SQL table layout or storage parameters of your version database, or to make backup copies of your database in plain text. These issues are not properly addressed by generating packet streams: instead, you must use migration or dumping commands.
The mtn db migrate command is used to alter the SQL schema of a database. The schema of a monotone database is identified by a special hash of its generating SQL, which is stored in the database's auxiliary tables. Each version of monotone knows which schema version it is able to work with, and it will refuse to operate on databases with different schemas. When you run the migrate command, monotone looks in an internal list of SQL logic which can be used to perform in-place upgrades. It applies entries from this list, in order, attempting to change the database it has into the database it wants. Each step of this migration is checked to ensure no errors occurred and the resulting schema hashes to the intended value. The migration is attempted inside a transaction, so if it fails — for example if the result of migration hashes to an unexpected value — the migration is aborted.
If more drastic changes to the underlying database are made, such as changing the page size of sqlite, or if you simply want to keep a plain text version of your database on hand, the mtn db dump command can produce a plain ASCII SQL statement which generates the state of your database. This dump can later be reloaded using the mtn db load command.
Note that when reloading a dumped database, the schema of the dumped database is included in the dump, so you should not try to init your database before a load.
Monotone is capable of reading CVS files directly and importing them into a database. This feature is still somewhat immature, but moderately large “real world” CVS trees on the order of 1GB have successfully been imported.
Note however that the machine requirements for CVS trees of this size are not trivial: it can take several hours on a modern system to reconstruct the history of such a tree and calculate the millions of cryptographic certificates involved. We recommend experimenting with smaller trees first, to get a feel for the import process.
We will assume certain values for this example which will differ in your case:
example.net in this example.
import@example.net in this example.
wobbler in this example.
wobbler in this example.
Accounting for these differences at your site, the following is an example procedure for importing a CVS repository “from scratch”, and checking the resulting head version of the import out into a workspace:
$ mtn --db=test.mtn db init
$ mtn --db=test.mtn genkey import@example.net
$ mtn --db=test.mtn --branch=net.example.wobbler cvs_import /usr/local/cvsroot/wobbler
$ mtn --db=test.mtn --branch=net.example.wobbler checkout wobber-checkout
Suppose you made changes to your database, and want to send those changes to someone else but for some reason you cannot use netsync. Or maybe you want to extract and inject individual revisions automatically via an external program. In this case, you can convert the information into packets. Packets are a convenient way to represent revisions and other database contents as plain text with wrapped lines – just what you need if you want to send them in the body of an email.
This is a tutorial on how to transfer single revisions between databases by dumping them from one database to a text file and then reading the dump into a second database.
We will create two databases, A and B, then create a few revisions in A, and transfer part of them to B.
First we initialize the databases:
$ mtn -d A db init
$ mtn -d B db init
Now set up a branch in A:
$ mtn -d A setup -b test test
And let's put some revisions in that branch:
$ cd test/
$ cat > file
xyz
^D
$ mtn add file
$ mtn ci -m "One" You may need to select a key and type a passphrase here
$ cat > file2
file 2 getting in
^D
$ cat > file
ERASE
^D
$ mtn add file2
$ mtn ci -m "Two"
$ cat > file
THIRD
^D
$ mtn ci -m "Three"
OK, that's enough. Let's see what we have:
$ cd ..
$ mtn -d A automate select i: | mtn -d A automate toposort -
a423db0ad651c74e41ab2529eca6f17513ccf714
d14e89582ad9030e1eb62f563c8721be02ca0b65
151f1fb125f19ebe11eb8bfe3a5798fcbea4e736
Three revisions! Let's transfer the first one to the database B. First we get the meta-information on that revision:
$ mtn -d A automate get_revision a423db0ad651c74e41ab2529eca6f17513ccf714
format_version "1"
new_manifest [b6dbdbbe0e7f41e44d9b72f9fe29b1f1a4f47f18]
old_revision []
add_dir ""
add_file "file"
content [8714e0ef31edb00e33683f575274379955b3526c]
OK, one file was added in this revision. We'll transfer it. Now, ORDER MATTERS! We should transfer:
In that order. This is because certs make reference to release data, and release data makes reference to file data and file deltas.
mtn -d A automate packet_for_fdata 8714e0ef31edb00e33683f575274379955b3526c > PACKETS
mtn -d A automate packet_for_rdata a423db0ad651c74e41ab2529eca6f17513ccf714 >> PACKETS
mtn -d A automate packets_for_certs a423db0ad651c74e41ab2529eca6f17513ccf714 >> PACKETS
mtn -d B read < PACKETS
This revision (a423db0ad651c74e41ab2529eca6f17513ccf714) was already sent to database B. You may want to check the PACKETS file to see what the packets look like.
Now let's transfer one more revision:
mtn -d A automate get_revision d14e89582ad9030e1eb62f563c8721be02ca0b65
format_version "1"
new_manifest [48a03530005d46ed9c31c8f83ad96c4fa22b8b28]
old_revision [a423db0ad651c74e41ab2529eca6f17513ccf714]
add_file "file2"
content [d2178687226560032947c1deacb39d16a16ea5c6]
patch "file"
from [8714e0ef31edb00e33683f575274379955b3526c]
to [8b52d96d4fab6c1e56d6364b0a2673f4111b228e]
From what we see, in this revision we have one new file and one patch, so we do the same we did before for them:
mtn -d A automate packet_for_fdata d2178687226560032947c1deacb39d16a16ea5c6 > PACKETS2
mtn -d A automate packet_for_fdelta 8714e0ef31edb00e33683f575274379955b3526c 8b52d96d4fab6c1e56d6364b0a2673f4111b228e >> PACKETS2
mtn -d A automate packet_for_rdata d14e89582ad9030e1eb62f563c8721be02ca0b65 >> PACKETS2
mtn -d A automate packets_for_certs d14e89582ad9030e1eb62f563c8721be02ca0b65 >> PACKETS2
mtn -d B read < PACKETS2
Fine. The two revisions should be in the second database now. Let's take a look at what's in each database:
$ mtn -d A automate select i: | mtn -d A automate toposort -
a423db0ad651c74e41ab2529eca6f17513ccf714
d14e89582ad9030e1eb62f563c8721be02ca0b65
151f1fb125f19ebe11eb8bfe3a5798fcbea4e736
$ mtn -d B automate select i: | mtn -d B automate toposort -
a423db0ad651c74e41ab2529eca6f17513ccf714
d14e89582ad9030e1eb62f563c8721be02ca0b65
Good! B has the two first revisions (as expected), and A has all three. However, a checkout
of that branch on B will not work, because the certificate signatures cannot be verified.
We need to transfer the signatures too (suppose the key used had the ID "johndoe@domain.com"):
mtn -d A pubkey johndoe@domain.com > KEY_PACKETS
mtn -d B read < KEY_PACKETS
Done.
$ mtn -d B co -b test test-B
$ ls test-B
file2 _MTN x
$ more test-B/file2
file 2 getting in
And that's it! The revisions were successfully transfered.
This chapter translates common CVS commands into monotone commands. It is an easy alternative to reading through the complete command reference.
$ CVSROOT=:pserver:cvs.foo.com/wobbler
$ cvs -d $CVSROOT checkout -r 1.2
|
$ mtn pull www.foo.com com.foo.wobbler*
$ mtn checkout --revision=fe37 wobbler
|
The CVS command contacts a network server, retrieves a revision, and stores it in your workspace. There are two cosmetic differences with the monotone command: remote databases are specified by hostnames and globs, and revisions are denoted by sha1 values (or selectors).
There is also one deep difference: pulling revisions into your database is a separate step from checking out a single revision; after you have pulled from a network server, your database will contain several revisions, possibly the entire history of a project. Checking out is a separate step, after communication, which only copies a particular revision out of your database and into a named directory.
$ cvs commit -m "log message" |
$ mtn commit --message="log message"
$ mtn push www.foo.com com.foo.wobbler*
|
As with other networking commands, the communication step with monotone is explicit: committing changes only saves them to the local database. A separate command, push, sends the changes to a remote database.
$ cvs update -C file |
$ mtn revert file |
Unlike CVS, monotone includes a separate revert command for undoing local changes and restoring the workspace to the original contents of the base revision. Because this can be dangerous, revert insists on an explicit argument to name the files or directories to be reverted; use the current directory "." at the top of the workspace to revert everything. The revert command is also used to restore deleted files (with a convenient --missing option for naming these files).
In CVS, you would need to use update to restore missing or changed files, and you might get back a newer version of the file than you started with. In monotone, revert always takes you back to where you started, and the update command is only used to move the workspace to a different (usually newer) base revision.
$ cvs update -d |
$ mtn pull www.foo.com com.foo.wobbler*
$ mtn merge
$ mtn update
|
This command, like other networking commands, involves a separate communication step with monotone. The extra command, merge, ensures that the branch your are working on has a unique head. You can omit the merge step if you only want update to examine descendents of your base revision, and ignore other heads on your branch.
$ cvs tag FOO_TAG . |
$ mtn tag h: FOO_TAG |
With CVS, tags are placed on individual files, and the closest thing to identifying a consistent repository-wide revision is a set of files with the same tag. In monotone, all changes are part of a repository-wide revision, and some of those revisions may be tagged. Monotone has no partial tags that apply only to a subset of files.
$ cvs update -r FOO_TAG -d |
$ mtn update -r 830ac1a5f033825ab364f911608ec294fe37f7bc
$ mtn update -r t:FOO_TAG
|
With a revision parameter, the update command operates similarly in monotone and CVS. One difference is that a subsequent commit will be based off the chosen revision in monotone, while a commit in the CVS case is not possible without going back to the branch head again. This version of update can thus be very useful if, for example, you discover that the tree you are working against is somehow broken — you can update to an older non-broken version, and continue to work normally while waiting for the tree to be fixed.
$ cvs diff |
$ mtn diff |
$ cvs diff -r 1.2 -r 1.4 myfile |
$ mtn diff -r 3e7db -r 278df myfile |
Monotone's diff command is modeled on that of CVS, so the main features are the same: diff alone prints the differences between your workspace and its base revision, whereas diff accompanied by two revision numbers prints the difference between those two revisions. The major difference between CVS and monotone here is that monotone's revision numbers are revision IDs, rather than file IDs. If one leaves off the file argument, then diff can print the difference between two entire trees.
$ cvs status |
$ mtn status |
This command operates similarly in monotone and CVS. The only major difference is that monotone's status command always gives a status of the whole tree, and outputs a more compact summary than CVS.
$ cvs add dir
$ cvs add dir/subdir
$ cvs add dir/subdir/file.txt
|
$ mtn add dir/subdir/file.txt |
Monotone does not explicitly store directories, so adding a file only involves adding the file's complete path, including any directories. Directories are created as needed, and empty directories are ignored.
$ rm file.txt
$ cvs remove file.txt
|
$ mtn drop file.txt |
Monotone does not require that you erase a file from the workspace before you drop it. Dropping a file merely removes its entry in the manifest of the current revision unless you give it the --execute flag, which tells monotone to go ahead and also remove it from the filesystem.
$ cvs log [file] |
$ mtn log [file] |
Unlike CVS log, monotone log can also be used without a workspace; but in this case you must pass a --revision argument to tell monotone where to start displaying the log from.
$ cvs import wobbler vendor start |
$ mtn --db=/path/to/database.mtn --branch=com.foo.wobbler setup .
$ mtn add .
$ mtn commit
|
The setup command turns an ordinary directory into a monotone workspace. After that, you can add your files and commit them as usual.
$ cvs init -d /path/to/repository |
$ mtn db init --db=/path/to/database.mtn |
Monotone's “repository” is a single-file database, which is created and initialized by this command. This file is only ever used by you, and does not need to be in any special location, or readable by other users.
Monotone has a large number of commands. To help navigate through them all, commands are grouped into logical categories.
Without a --revision argument, the command outputs the contents of path as found in the current revision. This requires the command be executed from within a workspace.
With an explicit --revision argument, the command outputs
contents of path at that revision.
dir ""
file "Makefile"
content [84e2c30a2571bd627918deee1e6613d34e64a29e]
file "include/hello.h"
content [c61af2e67eb9b81e46357bb3c409a9a53a7cdfc6]
file "src/hello.c
content [97dfc6fd4f486df95868d85b4b81197014ae2a84]
Then the following files are created:
directory/
directory/Makefile
directory/include/hello.h
directory/src/hello.c
If you wish to checkout in the current directory, you can supply the special name . (a single period) for directory.
If no id is provided, as in the latter two commands, you
must provide a branchname; monotone will attempt to infer
id as the unique head of branchname if it exists.
Conceptually, disapproves contract is that disapprove(A) gives a revision B such that whenever B is merged with a descendent D of A the merge will result in what D “would have looked like” if A had never happened.
Note that as a consequence of this contract the disapprove command
only works if id has exactly one ancestor, since it hasn't been
worked out how to generate such a descendent in the multi-ancestor case.
The “heads” of a branch is the set of revisions which are members of
the branch, but which have no descendents. These revisions are
generally the “newest” revisions committed by you or your
colleagues, at least in terms of ancestry. The heads of a branch may
not be the newest revisions, in terms of time, but synchronization of
computer clocks is not reliable, so monotone usually ignores time.
Merging is performed by repeated pairwise merges: two heads are
selected, then their least common ancestor is located in the ancestry
graph and these 3 revisions are provided to the built-in 3-way merge
algorithm. The process then repeats for each additional head, using
the result of each previous merge as an input to the next.
The purpose of propagate is to copy all the changes on
sourcebranch, since the last propagate, to
destbranch. This command supports the idea of making separate
branches for medium-length development activities, such as
maintenance branches for stable software releases, trivial bug fix
branches, public contribution branches, or branches devoted to the
development of a single module within a larger project.
The purpose of merge_into_dir is to permit a project to contain another project in such a way that propagate can be used to keep the contained project up-to-date. It is meant to replace the use of nested checkouts in many circumstances.
Note that merge_into_dir does not permit changes made to the contained project in destbranch to be propagated back to sourcebranch. Attempting this would lead to sourcebranch containing both projects nested as in destbranch instead of only the project originally in sourcebranch, which is almost certainly not what would be intended.
This can be used with an empty directory to start a new blank project,
or within an existing directory full of files, prior to using
mtn commit. If no directory is specified, the current
directory is used.
As a convenience, the --unknown option can be used; this option will cause all of the files listed by mtn list unknown to be added.
While this command places an “add” entry on your work list, it does
not immediately affect your database. When you commit your
workspace, monotone will use the work list to build a new revision,
which it will then commit to the database. The new revision will have
any added entries inserted in its manifest.
While this command places a “drop” entry on your work list, it does not immediately affect your database. When you commit your workspace, monotone will use the work list to build a new revision, which it will then commit to the database. The new revision will have any dropped entries removed from its manifest.
Currently this command does not actually delete the file src in your filesystem; if you want to actually delete the file, you should run drop, and then perform the actual delete using whatever mechanism you normally use to delete files.
The option --execute will make “drop” perform the actual
deletion operations in the filesystem. It will ignore files or
directories which have already been deleted.
While this command places a “rename” entry on your work list, it does not immediately affect your database. When you commit your workspace, monotone will use the work list to build a new revision, which it will then commit to the database. The new revision will have any renamed entries in its manifest adjusted to their new names.
The option --execute will make “rename” perform the actual
rename operations in the filesystem. It will ignore missing source files
and will not overwrite existing destination files.
For each edited file, a delta is copied into the database. Then the newly constructed manifest is recorded (as a delta) and finally the new revision. Once all these objects are recorded in you database, commit updates _MTN/revision to indicate that the base revision is now the newly created revision, and that there are no pathname changes to apply.
Specifying pathnames to commit restricts the set of changes that are visible and results in only a partial commit of the workspace. Changes to files not included in the specified set of pathnames will be ignored and will remain in the workspace until they are included in a future commit. With a partial commit, only the relevant entries in _MTN/revision will be removed and other entries will remain for future commits.
From within a subdirectory of the workspace the commit command will, by default, include all changes in the workspace. Specifying only the pathname "." will restrict commit to files changed within the current subdirectory of the workspace.
The --message and --message-file options are mutually exclusive. Both provide a logmsg describing the commit. --message-file actually specifies the name of the file containing the log message, while --message provides it directly.
Multiple --message options may be provided on the command line. The log message will be formed by concatenating the --message options provided, with each one starting at the beginning of a new line.
The _MTN/log file can be edited by the user during their daily work
to record the changes made to the workspace. When running the
commit command without a logmsg supplied, the contents
of the _MTN/log file will be read and passed to the Lua hook
edit_comment as a second parameter named user_log_content.
If the commit is successful, the _MTN/log file is cleared of
all content making it ready for another edit/commit cycle.
If a --branch option is specified, the commit command commits to this branch (creating it if necessary). The branch becomes the new default branch of the workspace.
The commit command also synthesizes a number of certificates, which it attaches to the new manifest version and copies into your database:
author cert, indicating the person responsible for the changes
leading to the new revision. Normally this defaults to your signing key
or the return value of the get_author hook; you may override this
by passing the --author option to commit. This is useful when
committing a patch on behalf of someone else, or when importing “by
hand” from another version control system.
branch cert, indicating the branch the committed revision
belongs to.
date cert, indicating when the new revision was created.
Normally this defaults to the current time; you may override this by
passing the --date option to commit. This is useful when
importing “by hand” from another version control system.
changelog cert, containing the “log message” for these
changes. If you provided logmsg on the command line, this text
will be used, otherwise commit will run the Lua hook
edit_comment (commentary, user_log_content), which
typically invokes an external editor program, in which you can compose
and/or review your log message for the change.
If the flag --missing is given it reverts (ie, restores) any
files which monotone has listed in its manifest, but which have been
deleted from the workspace. Only missing files matching the given
file or directory arguments are reverted.
With an explicit --revision argument, the command uses that revision as the update target instead of finding an acceptable candidate.
The effect is always to take whatever changes you have made in the workspace, and to “transpose” them onto a new revision, using monotone's 3-way merge algorithm to achieve good results. Note that with the explicit --revision argument, it is possible to update “backwards” or “sideways” in history — for example, reverting to an earlier revision, or if your branch has two heads, updating to the other. In all cases, the end result will be whatever revision you specified, with your local changes (and only your local changes) applied.
If a --branch option is specified, the update command
tries to select the revision to update to from this branch. The branch
becomes the new default branch of the workspace (even if you also
specify an explicit --revision argument).
If only one revision is given, applies the changes made in to as compared with to's parent. If two revisions are given, applies the changes made to get from from to to.
Note that this is not a true cherrypick operation. A true cherrypick, as that word is used in version control theory, involves applying some changes out of context, and then recording the identity between the original changes and the newly applied changes for the use of later merges. This command does the first part, not the second. As far as monotone is concerned, the changes made by mtn pluck are exactly like those made in an editor; the command is simply a convenient way to make certain edits quickly. In practice, this is rarely a problem. mtn pluck should almost always be used between branches that will never be merged — for instance, backporting fixes from a development branch to a stable branch.
When you use pluck you are going behind monotone's back, and
reducing its ability to help you keep track of what has happened in
your history. Never use pluck where a true merging command
like merge, propagate, or explicit_merge
will do. If you find yourself using pluck often, you should
consider carefully whether there is any way to change your workflow to
reduce your need for plucking.
Its effect is to rename the directory whose name is currently new_root to become the root directory of the versioned tree, and to at the same time rename the directory that is currently the root of the versioned tree to have the name put_old. Conceptually, it is equivalent to executing the following commands in the root of the workspace:
$ mtn rename . new_root/put_old
$ mtn rename new_root .
Except, of course, that these rename commands are illegal, because after the first command the tree has no root at all, and there is a directory loop. This illegality is the only reason for pivot_root's existence; internally, the result is treated exactly like two renames, including with respect to merges and updates.
The use of --execute with this command is strongly recommended, though not required.
The network address given to serve as an argument to --bind should be a host name to listen on, optionally followed by a colon and a port number. The default port number is 4691. If no --bind option is given, the server listens on port 4691 of every network interface.
If serve is run with --stdio, a single netsync
session is served over the stdin and stdout file
descriptors. If --no-transport-auth is provided along with
--stdio, transport authentication and access control mechanisms
are disabled. Only use --no-transport-auth if you are certain
that the transport channel in use already provides sufficient
authentication and authorization facilities.
The uri-or-address arguments given to push, pull, and sync can be of two possible forms. If the argument is a URI, a lua hook may transform the URI into a connection command, and execute the command as a transport channel for netsync. If the argument is a simple hostname (with optional port number), monotone will use a TCP socket to the specified host and port as a transport channel for netsync.
The glob parameters indicate a set of branches to exchange. Multiple glob and --exclude options can be specified; every branch which matches a glob exactly, and does not match an exclude-glob, will be indexed and made available for synchronization.
For example, perhaps Bob and Alice wish to synchronize their
net.venge.monotone.win32 and net.venge.monotone.i18n
branches. Supposing Alice's computer has hostname
alice.someisp.com, then Alice might run:
$ mtn --bind=alice.someisp.com serve "net.venge.monotone*"
And Bob might run
$ mtn sync alice.someisp.com "net.venge.monotone*"
When the operation completes, all branches matching
net.venge.monotone* will be synchronized between Alice and Bob's
databases.
The pull, push, and sync commands only require you pass address and glob the first time you use one of them; monotone will memorize this use and in the future default to the same server and glob. For instance, if Bob wants to sync with Alice again, he can simply run:
$ mtn sync
Of course, he can still sync with other people and other branches by passing an address or address plus globs on the command line; this will not affect his default affinity for Alice. If you ever do want to change your defaults, simply pass the --set-default option when connecting to the server and branch pattern that you want to make the new default.
In the server, different permissions can be applied to each branch; see
the hooks get_netsync_read_permitted and
get_netsync_write_permitted (see Hook Reference).
If a --pid-file option is specified, the command serve will create the specified file and record the process identifier of the server in the file. This file can then be read to identify specific monotone server processes.
The syntax for patterns is very simple. * matches 0 or more
arbitrary characters. ? matches exactly 1 arbitrary character.
{foo,bar,baz} matches “foo”, or “bar”, or “baz”. These
can be combined arbitrarily. A backslash, \, can be prefixed to
any character, to match exactly that character — this might be useful
in case someone, for some odd reason, decides to put a “*” into their
branch name.
Specifying optional pathname... arguments to the status command restricts the set of changes that are visible and results in only a partial status of the workspace. Changes to files not included in the specified set of pathnames will be ignored.
From within a subdirectory of the workspace the status command
will, by default, include all changes in the workspace.
Specifying only the pathname "." will restrict status to files
changed within the current subdirectory of the workspace.
If --brief is given, the output consists of one line per revision with the revision ID, the author, the date and the branches (separated with commas).
If --last=n is given, at most n log entries will be given.
If --next=n is given, at most n log entries towards the current head revision will be given from the workspace's base revision in forward-ancestry order. This is useful to review changes that will be applied to the workspace when update is run.
By default, the log entries for merge nodes are shown. If --no-merges is given, the log entries for these nodes will be excluded.
If --no-files is given, the log output excludes the list of files changed in each revision.
Specifying --diffs causes the log output to include a unified diff of the changes in each revision.
If one or more revision IDs are given, the command starts tracing back through history from these revisions, otherwise it starts from the base revision of your workspace.
If one or more files are given, the command will only log the revisions
where those files are changed.
If --brief is specified, the output is in the form
<short revision id>.. by <author> <date>: <line>
Only the first 8 characters of the revision id are displayed, the
author cert value is truncated at the first @ or space
character and the date field is truncated to remove the time of day.
file, manifest or
revision IDs depending on which variant is used. For
example, suppose you enter this command and get this result:
$ mtn complete revision fa36
fa36deead87811b0e15208da2853c39d2f6ebe90
fa36b76dd0139177b28b379fe1d56b22342e5306
fa36965ec190bee14c5afcac235f1b8e2239bb2a
Then monotone is telling you that there are 3 revisions it knows
about, in its database, which begin with the 4 hex digits
fa36. This command is intended to be used by programmable
completion systems, such as those in bash and zsh.
The complete command for keys and revisions have a --verbose option. Programmable completion systems can use --verbose output to present users with additional information about each completion option.
For example, verbose output for revision looks like this:
$ mt complete revision 01f
01f5da490941bee1f0000f0561fc62eabfb2fa23 graydon@dub.net 2003-12-03T03:14:35
01f992577bd8bcdcade0f89e724fd5dc2d2bbe8a kinetik@orcon.nz 2005-05-11T05:19:29
01faad191d8d0474777c70b4d606782942333a78 kinetik@orcon.nz 2005-04-11T04:24:01
With one --revision option, diff will print the differences between the revision id and the current revision in the workspace. With two --revision options diff will print the differences between revisions id1 and id2, ignoring any workspace.
In all cases, monotone will print a textual summary – identical to
the summary presented by mtn status – of the logical
differences between revisions in lines proceeding the diff. These
lines begin with a single hash mark #, and should be ignored by
a program processing the diff, such as patch.
Specifying pathnames to the diff command restricts the set of changes that are visible and results in only a partial diff between two revisions. Changes to files not included in the specified set of pathnames will be ignored.
From within a subdirectory of the workspace the diff command will, by default, include all changes in the workspace. Specifying only the pathname "." will restrict diff to files changed within the current subdirectory of the workspace.
The output format of diff is controlled by the options --unified, --context, --show-encloser, and --external. By default, monotone uses its built-in diff algorithm to produce a listing in “unified diff” format (analogous to running the program diff -u); you can also explicitly request this with --unified. The built-in diff algorithm can also produce “context diff” format (analogous to diff -c), which you request by specifying --context. The short options that diff accepts for these modes, -u and -c, also work.
In either of these modes, you can request that monotone print the name
of the top-level code construct that encloses each “hunk” of
changes, with --show-encloser. The options that
diff accepts for this mode, -p and
--show-c-function, also work. Monotone finds the enclosing
construct by scanning backward from the first changed line in each
hunk for a line that matches a regular expression. The default
regular expression is correct for many programming languages. You can
adjust the expression used with the Lua hook
get_encloser_pattern; Hooks.
--unified requests the “unified diff” format, the default. --context requests the “context diff” format (analogous to running the program diff -c). Both of these formats are generated directly by monotone, using its built-in diff algorithm.
Sometimes, you may want more flexibility in output formats; for these
cases, you can use --external, which causes monotone to invoke
an external program to generate the actual output. By default, the
external program is diff, and you can use the option
--diff-args to pass additional arguments controlling
formatting. The actual invocation of diff, default arguments
passed to it, and so on, are controlled by the hook
external_diff; see Hooks for more details.
ok or bad
For example, this command lists the certificates associated with a particular version of monotone itself, in the monotone development branch:
$ mtn list certs 4a96
mtn: expanding partial id '4a96'
mtn: expanded to '4a96a230293456baa9c6e7167cafb3c5b52a8e7f'
-----------------------------------------------------------------
Key : graydon@pobox.com
Sig : ok
Name : author
Value : graydon@dub.venge.net
-----------------------------------------------------------------
Key : graydon@pobox.com
Sig : ok
Name : branch
Value : monotone
-----------------------------------------------------------------
Key : graydon@pobox.com
Sig : ok
Name : date
Value : 2003-10-17T03:20:27
-----------------------------------------------------------------
Key : graydon@pobox.com
Sig : ok
Name : changelog
Value : 2003-10-16 graydon hoare <graydon@pobox.com>
:
: * sanity.hh: Add a const version of idx().
: * diff_patch.cc: Change to using idx() everywhere.
: * cert.cc (find_common_ancestor): Rewrite to recursive
: form, stepping over historic merges.
: * tests/t_cross.at: New test for merging merges.
: * testsuite.at: Call t_cross.at.
:
If pattern is provided, it is used as a glob to limit the keys
listed. Otherwise all keys in your database are listed.
Specifying pathnames to the list known command restricts the set of paths that are searched for manifest files. Files not included in the specified set of pathnames will not be listed.
From within a subdirectory of the workspace the list
known command will, by default, search the entire workspace.
Specifying only the pathname "." will restrict the search for known
files to the current subdirectory of the workspace.
Specifying pathnames to the list unknown command restricts the set of paths that are searched for unknown files. Unknown files not included in the specified set of pathnames will not be listed.
From within a subdirectory of the workspace the list
unknown command will, by default, search the entire workspace.
Specifying only the pathname "." will restrict the search for unknown
files to the current subdirectory of the workspace.
ignore_file
(filename) hook.
Specifying pathnames to the list ignored command restricts the set of paths that are searched for ignored files. Ignored files not included in the specified set of pathnames will not be listed.
From within a subdirectory of the workspace the list
ignored command will, by default, search the entire workspace.
Specifying only the pathname "." will restrict the search for ignored
files to the current subdirectory of the workspace.
Specifying pathnames to the list missing command restricts the set of paths that are searched for missing files. Missing files not included in the specified set of pathnames will not be listed.
From within a subdirectory of the workspace the list
missing command will, by default, search the entire workspace.
Specifying only the pathname "." will restrict the search for missing
files to the current subdirectory of the workspace.
Specifying pathnames to the list changed command restricts the set of paths that are checked for changes. Files not included in the specified set of pathnames will not be listed.
From within a subdirectory of the workspace the list
changed command will, by default, search the entire workspace.
Specifying only the pathname "." will restrict the search for known
files to the current subdirectory of the workspace.
The private half of the key is stored in an encrypted form, so that anyone
who can read your keystore cannot extract your private key and use it.
You must provide a passphrase for your key when it is generated, which is used
to determine the encryption key. In the future you will need to enter this
passphrase again each time you sign a certificate, which happens every
time you commit to your database. You can tell monotone to
automatically use a certain passphrase for a given key using the
get_passphrase(keypair_id), but this significantly
increases the risk of a key compromise on your local computer. Be
careful using this hook.
get_revision_cert_trust (see Hook Reference). You pass it
a revision ID, a certificate name, a certificate value, and one or more
key IDs, and it will tell you whether, under your current settings,
Monotone would trust a cert on that revision with that value signed by
those keys.
h:branchname.
If certval is provided, it is the value of the certificate.
Otherwise the certificate value is read from stdin.
stdin.
This command is a synonym for mtn cert id tag
tagname.
Monotone can produce and consume data in a convenient, portable form called packets. A packet is a sequence of ASCII text, wrapped at 70-columns and easily sent through email or other transports. If you wish to manually transmit a piece of information – for example a public key – from one monotone database to another, it is often convenient to read and write packets.
Note: earlier versions of monotone queued and replayed packet streams for their networking system. This older networking system has been removed, as the netsync protocol has several properties which make it a superior communication system. However, the packet I/O facility will remain in monotone as a utility for moving individual data items around manually.
rcert packet for each cert in your
database associated with id. These can be used to transport
certificates safely between monotone databases. See Automation
for details of this command.
fdata or rdata packet for
the file, manifest or revision id in your database. These can
be used to transport files or revisions, in their entirety, safely
between monotone databases. See Automation for details of these
commands.
fdelta packet for the differences
between file versions id1 and id2, in your database.
These can be used to transport file differences safely between
monotone databases. See Automation for details of this
command.
keypair or pubkey packet for
the rsa key keyid. These can be used to transport public or
private keys safely between monotone databases.
stdin and stores them
in your database.
Note that when reloading a dumped database, the schema of the dumped
database is included in the dump, so you should not try to
init your database before a load.
If you have important information in your database, you should back up
a copy of it before migrating, in case there is an untrapped error
during migration.
However, it's also nice to notice such problems early, and in rarely used parts of history, while you still have backups. That's what this command is for. It systematically checks the database dbfile to ensure that it is complete and consistent. The following problems are detected:
This command also verifies that the sha1 hash of every file, manifest,
and revision is correct.
This section contains subcommands of the mtn automate command,
used for scripting monotone. All give output on stdout; they may
also give useful chatter on stderr, including warnings and error
messages.
1.2
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
ignore_branch.
net.venge.monotone
net.venge.monotone.win32
If a branch name is ignored by means of the lua hook
ignore_branch, it is neither printed, nor can it be matched by
a pattern.
format_version "1"
tag "monotree-0.3"
revision [35cff8e8ba14155f5f7ddf7965073f514fd60f61]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.2"
revision [5d288b39b49613b0d9dca8ece6b9a42c3773f35b]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
tag "monotree-0.1"
revision [8a121346ce2920b6f85df68b3b620de96bd14a8d]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib" "net.venge.monotone.contrib.monotree"
tag "monotree-0.4"
revision [f1afc520474f83c58262896ede027ef77226046e]
signer "njs@pobox.com"
branches "net.venge.monotone.contrib.monotree"
All stanzas are formatted by basic_io. Stanzas are separated by a blank line. Values will be escaped, '\' to '\\' and c ID, in hexadecimal, followed by a newline. The lines are printed in alphabetically sorted order.
The output does not include rev1, rev2, etc., except if
rev2 is itself an ancestor of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output will include one of the argument revisions only if that revision is
an ancestor of all other revisions given as arguments.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
The output does not include rev1, rev2, etc., except that if
rev2 is itself a descendent of rev1, then rev2 will be
included in the output.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
0c05e8ec9c6af4224672c7cc4c9ef05ae8bdb794
27ebcae50e1814e35274cb89b5031a423c29f95a 5830984dec5c41d994bcadfeab4bf1bf67747b89
4e284617c80bec7da03925062a84f715c1b042bd 27ebcae50e1814e35274cb89b5031a423c29f95a 657c756d24fb65213d59f4ae07e117d830dcc95b
The output as a whole is alphabetically sorted by line; additionally,
the parents within each line are alphabetically sorted.
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69eadb9b1ca7bdf9d40ce95fe2f29b61
75156724e0e2e3245838f356ec373c50fa469f1f
28ce076c69