1. Preface
This is intended as a quick & dirty summary of using Breezy (https://www.breezy-vcs.org/) to develop ctwm (http://www.ctwm.org/).
That this is a combination of “how to use brz” and “recommended workflow for working on ctwm”. It doesn’t by any means describe the only way work can be done, but does give workflows that should keep things orderly. If you don’t already know brz yourself, I’d stick pretty close to it.
Actually, it’s not really as short and quick as originally intended. It’s no substitute for grokking the full brz docs, but is probably enough to get you through day to day working on ctwm by itself.
1.1. See Also
Various bits of the actual brz docs.
- https://www.breezy-vcs.org/doc/en/
-
The main brz docs provide full reference, tutorials, etc.
- http://wiki.bazaar.canonical.com/MatthewFuller/SpotDocs
-
SpotDocs are some bits I wrote up years ago for general bzr support purposes, and I still think are generally useful. In particular, the PiecesInBrief doc describing the taxonomy and vocabulary of brz.
2. Intro and Justifications
The most important difference in day-to-day working with brz versus mtn is that while in mtn you sync a repository containing multiple branches, with your working trees (or checkouts) generally separate from it, in brz you sync individual branches generally colocated with their working trees. I give workflows here using a single shared repository, which holds the revisions of the history; skipping that step will involve each branch holding an individual full history copy, which wastes disk space (cheap) and disk/network IO (not so cheap).
The second most important difference is the special treatment of first or
left-hand parents, and their use in making merged revisions "roll up"
under them. This is why I’m recommending here the use of a checkout
rather than an independent branch for the local trunk. This adds minor
complication in having to remember the separate commands for updating it
etc, but I think that’s a good tradeoff. It’s also important in the
context of brz merge
.
3. Initial setup
3.1. Configuring brz
There are various things you can do to configure your local brz,
including aliases (see below) and so forth. But the only
thing really necessary is telling brz who you are via the whoami
command. This sets your identity, put on the revs you commit. Set this
to your name and email.
% brz whoami "Matthew Fuller <fullermd@over-yonder.net>"
3.2. Configuring your workspace.
First we’ll setup a shared repository, which will share the history storage across all the branches. I’ll assume all your ctwm work happens in ~/work/ctwm/brz. It doesn’t matter much where you declare this, except that you want all your branches to be ‘under’ it in the filesystem, and probably want it to be pretty close to them (e.g., don’t make your shared repo directly in ~ or ~/work; that might cause you to accidentally share it with other brz projects, which you don’t want).
% cd ~/work/ctwm/brz
% brz init-repo .
# Don't miss that trailing period.
This will leave you a ~/work/ctwm/brz/.brz directory, which contains the repo. You should never need to directly deal with this again; any new branches you make underneath ~/work/ctwm/brz will automatically use it.
3.3. Hosting
We use Launchpad for hosting the code repositories. The main project site is https://launchpad.net/ctwm. Launchpad provides anonymous read access to the repository over dumb http, which is somewhat slower than a smart transport. Using a smart transport is faster, and also required for write access.
To use the smart bzr+ssh transport, you’ll need to
create a Launchpad account if
you don’t already have one, setup an
ssh key for
LP to use, and use brz lp-login
to tell brz about your launchpad
account.
There’s a special lp: directory service in brz, so using lp:something as the location for a branch does some internal translation to the real URL. So references like lp:ctwm in this doc really should be used just as written.
-
lp:ctwm is the trunk.
-
lp:ctwm/xyz names can be assigned as needed.
Aside from those short names, the general structure of lp: lookups is lp:~OWNER/PROJECT/BRANCH, so lp:ctwm is actually an alias to lp:~ctwm/ctwm/trunk; i.e., a branch owned by the ctwm team, for the ctwm project, called trunk (names don’t have to be unique across users).
Committers have write access to trunk and any other branches (and to make new ones) owned by the ctwm team (as well as the ability to make new ctwm-owned branches). This should be used for long-lived globally-interesting branches, like additional release streams.
Anybody with a LP account, committer or no, can put ctwm-related branches under their own account at locations like lp:~myuser/ctwm/something. This is useful for sharing WIP, or your own personal fork, etc. These will show up as associated with the ctwm project.
3.4. Major branches
All current branches are visible at https://code.launchpad.net/ctwm. The major long-lived branches are currently:
-
lp:ctwm
-
This is the development trunk.
-
lp:ctwm/web
-
The website.
NoteSince there’s no common data/history between the code and the website, you can put them in separate repositories without losing anything. That’s relatively more advanced workflow stuff than I discuss in this doc though.
4. Getting and working on branches
4.1. Checking out trunk
trunk is the ‘main’ branch, and is somewhat special in that multiple people work on it. As a result, we treat it somewhat specially here by making a checkout of it, rather than a separate branch.
Note
|
For Committers
It’ll be simpler if you’re logged in to Launchpad before doing this, so that it’s setup to talk to LP over a writable transport. xref hosting section above. It’s not a huge deal to change it around afterward if you forget to do this first, but it’s always simpler not to have to change. |
So with all the above initial setup done, we make the checkout.
% cd ~/work/ctwm/brz
% brz co lp:ctwm trunk
Afterward, you’ll have a local copy of the trunk in ~/work/ctwm/brz/trunk. This is what brz called a ‘heavy’ checkout, which means you do mirror the full history locally, so operations like log don’t need to hit the network.
4.2. Working with trunk
To update your trunk copy, use the brz update
command. In essence, you
work with this pretty much like you would with a cvs or svn checkout.
Important
|
You do not want to use the brz pull command with a
checkout, so don’t do that with this trunk! |
For committers, you can commit in that trunk checkout. Because of the
way a checkout works, the new revision will be immediately pushed up to
the central branch as part of that process, and if it can’t be, the
commit will fail. For instance, if your checkout is out of date (new
changes have been made upstream), you’ll have to do an update
before
brz will let you commit
.
Note
|
Of course, don’t forget to tell me to add you to the brz team on LP first, so you can write to trunk! |
Tip
|
Project Policy
Whether work is done directly on the trunk branch or in a separate branch is a judgment call. Generally, simple self-contained things can just be done on trunk, as it’s easier. More involved things should be on their own branches. I feel like a nice rule of thumb is that if it’s small enough to comfortably be done in one commit, and safe enough to consider publishable right away, I just do it on trunk. Otherwise, it goes in its own branch. |
For stuff that is too big or experimental to just drop into trunk, it
should be worked on in separate branches, and then brought into trunk via
brz merge
.
4.3. Working with branches
4.3.1. Making a branch to work in
The brz branch
command is used to make new branches based on an
existing one.
% cd ~/work/ctwm/brz
% brz branch trunk fix-foo
Now you have a new branch (with its own working tree) in ~/work/ctwm/brz/fix-foo. This branch is purely local; nobody else can see it, stuff you do in it won’t touch the network, etc. So you can work in there on fixing foo, whatever that is. See below for a quick rundown of everyday commands for working within a branch.
4.3.2. Sharing the branch
You can make the changes visible to other people in a large variety of ways; I’ll just skim over the most likely ones.
Put it on Launchpad
With a Launchpad account, you can push it up to your own account’s branch namespace.
you% cd ~/work/ctwm/brz/fix-foo
you% brz push lp:~/ctwm/fix-foo
Tip
|
lp:~/x/y is a shortcut for lp:~yourself/x/y |
Now other people can pull down the branch themselves to look at or base new work off of:
someoneelse% cd ~/work/ctwm/brz
someoneelse% brz branch lp:~YOURUSER/ctwm/fix-foo
# Now they have the branch in ~/work/ctwm/brz/fix-foo
someoneelse% brz branch lp:~YOURUSER/ctwm/fix-foo YOURUSER-fix-foo
# Now they have the branch in ~/work/ctwm/brz/YOURUSER-fix-foo
When you have additional changes to push up, you can simply run brz
push
again, from anywhere in ~/work/ctwm/brz/fix-foo (you don’t need
to specify the location again, unless it changes; brz remembers where
you’re pushing too). And other people can pull down those changes you’ve
pushed up via brz pull
.
Put it somewhere else
You can also put brz branches somewhere else, or self-hosted. While it’s slower and not as capable as a smart server, brz supports ‘dumb’ transports like http. So if you have a web server available, just putting the branch somewhere web-accessible can let other people grab it from there.
# Is your dev box web-accessible?
% ln -s ~/work/ctwm/brz/my-branch ~/public_html/ctwm/my-branch
# Other people can run: brz branch http://yoursystem/~you/ctwm/my-branch
# Is brz installed on your web server?
% brz push bzr+ssh://myserver/~/public_html/ctwm/my-branch
# Other people see it just like above
# Is brz not installed on your web server?
% brz push sftp://myserver/~/public_html/ctwm/my-branch
# Still same
If the other people grabbing your branch already have e.g. trunk in their local shared repo, grabbing your branch should only need to transfer the additional revs you’ve added, not the whole history. Doing this over dumb http is harder than if they had smart access, but it’s not terrible.
Send bundles via email
brz also has the ability to create a standalone ‘merge-proposal’,
particularly one with an included ‘bundle’. This lets you send a block
of changes in a single file, that you can transfer in any number of ways
(email, put on a website, carrier pigeon). When doing this, brz compares
your branch to another ‘source’ branch, and puts together the set of
revisions needed to bring your changes onto it. It defaults to the
parent of your branch (that is, the branch you ran brz branch
from to
create it), which is usually the right choice.
% cd ~/work/ctwm/brz/fix-foo
% brz send -o/tmp/fix-foo.bundle
Now the file /tmp/fix-foo.bundle contains both a human-readable diff
(useful for reviewing the change), and a machine readable "bundle"
containing all the revisions. Other people can then use that file by
itself as the source for something like brz merge
just as if it were a
published copy of your branch.
Note
|
brz send has a lot of options, including the ability to spawn
your MUA directly. Consult upstream docs for details. |
4.3.3. Landing your changes into trunk
Once your fix-foo is ready to be released to the world, you’ll want to
merge it into trunk. This is done via the brz merge
command.
Important
|
Remember that brz merge does not commit the merge; it only
prepares it. This is different from how monotone works, as well as
git. Don’t forget to brz ci after you’re done, or you can wind up
accidentally intertwining future changes with the merge! |
% cd ~/work/ctwm/brz/trunk
% brz up
# Just in case: make sure you're up to date
% brz merge ../fix-foo
# Check over merge, fix any conflicts
% brz ci
Suggested log messages would be along the lines of
Land fixes that make foo work right with bar.
This doesn't fix foo's interaction with quux, but that's much more
involved so we're not bothering with it right now.
Because of the way commands like brz log
default to hiding away the
‘merged’ revisions, the default output will list only that merge rev and
its log message, so make sure it describes well enough the final result
of the process. The individual revs that were merged are all present and
available if anybody ever needs to drill down into the details.
After this is done, and assuming that completes the process of fixing foo, you can now discard that fix-foo branch if you want.
% rm -rf ~/work/ctwm/brz/fix-foo
Removing it from anywhere else you’ve put it (pushed to launchpad or your webserver, etc) is left as an exercise for the reader.
5. Day to day commands and operations
There are a lot of useful things I don’t talk about here, but this should easily cover 95% of your needs. See upstream docs for additional goodies.
5.1. Help
-
brz help
-
Has full reference for the various commands, as well as some other topics.
| less
is often appropriate…
5.2. Dealing with branches
-
brz branch
-
This is how you make a new branch (mirroring an existing branch is just a degenerate case of this; you’re making a new branch you never make local changes to). Standard syntax is
brz branch SOURCE [DEST]
; if DEST is left off, the last path component of SOURCE is used.% brz branch http://some/branch/some/where # Branch winds up in 'where' % brz branch http://some/branch/some/where localdir # Branch winds up in 'localdir'
-
brz pull
-
This is a sort of ‘mirror’ command; it brings your branch up to being a fully up-to-date copy of its ‘parent’ (by default, the branch you
brz branch
ed it from).This only operates if your local branch is ‘out of date’ relative to the upstream. If the branches have ‘diverged’ (e.g, you have committed local changes), pull will refuse to do anything.
-
brz push
-
This lets you push changes to an upstream branch of some sort. Often used to update a publicly-accessible copy of your branch.
CautionYou don’t want to use push
orpull
with your checkout of trunk (or any other checkout of a branch you have. For checkouts, thecommit
process automatically publishes the change, and you useupdate
to catch up with upstream changes. -
brz update
(brz up
) -
This is used in a checkout (as recommended above for trunk), to bring it up to date with the branch it’s a checkout of. It’s sorta an equivalent of pull for checkouts (not really, but a reasonable metaphor). Like in centralized systems like svn,
commit
will give an error if you’re out of date with the upstream;update
is how you catch up. -
brz commit
(brz ci
) -
Commits a change to the branch. In a checkout, the ‘branch’ is the upstream location, so this automatically publishes it.
You can commit single files or directories by passing them as args to the command. You can specify the commit log on the command line via
-m
; otherwise brz will spawn your $EDITOR.Tipbrz ci
has a--local
arg. I suggest you never, ever, ever use it. It’ll probably cause you serious troubles later if you do. You should forget it exists; I only mention it here in case you accidentally come across it yourself…
5.3. Working in your trees
These commands don’t (immediately) update anything in the branch; they just set how things will happen in the next commit.
-
brz add
-
Adds a new file as versioned, so it will wind up in the next
brz ci
(and future revs). -
brz rm
-
Removes a file from version control. It will be removed from the next commit (and future commits). Note that brz will automatically list as removed any files that don’t exist when you commit, so you can often just use your system
rm
and let brz pick up the missing file from there. It’s usually simpler.Tiprm
has some DWIM magic for what it does with the file in the filesystem. I suggest usingbrz rm --keep
to make it leave the existing file alone, just remove it from the list of things version controlled. That way you can usebrz rm
when you don’t want the file to immediately disappear from your system (as a sort of unversion action), andrm
(the system command) when you want it to do both. You can set an alias in brz (see my aliases below) to make this default. -
brz mv
-
Renames a file (or directory). Because brz tracks file identity, this isn’t the same as doing a
brz rm
+brz add
, so if you’re intending to rename a file, usebrz mv
. It has some provision like--after
to tell brz about the change after you’ve already done it viamv
or a GUI file manager or some other mechanism out of brz’s control. See full docs for details. -
brz revert
-
This reverts outstanding uncommitted changes. With no args, it wipes out all changes you’ve made since the last commit. By specifying file(s) or dir(s), it will roll back just those changes. Useful for "oh, nevermind" and "wow, I screwed that up bad" situations.
5.4. Viewing information
-
brz log
-
Views the history log. You can specify individual files, groups of files, or directories, to see only the revs that affect those files (though note that this slows things down a lot). Various formats can be chosen like
--short
or--line
; I like using--short
day to day.-v
makes it show the files affected by each rev.As talked about above,
log
by default collapses away merged revisions, showing only the single commit that merges in the other branches. Using the-n0
arg to log you can make it show all those merged details. -
brz diff
-
Show diffs. With no args, it shows your outstanding uncommitted changes. By providing multiple historical revisions, you can see the differences between them (e.g.,
brz diff -r12..15
shows the diffs from rev 12 to rev 15). See below for some details about how to describe revs.A handy shortcut is the
-c
arg, which shows the changes made by a single revision relative to its (first) parent. Sobrz diff -r5..6
can be written more simply asbrz diff -c6
. -
brz status
(brz stat
) -
Shows a short summary of files that have been added, removed, or changed, plus info about a pending merge. Like
diff
above, this defaults to outstanding uncommitted changes, but can show between historical revs using-r
or-c
similarly. e.g.,brz stat -c-1
to show the files changes in the most recent commit (see revision specification below for use of negative numbers, and other ways to refer to revisions). -
brz missing
-
This is used to compare two branches, to see what revisions each has that the other doesn’t. e.g.,
% cd ~/work/ctwm/brz/trunk % brz missing ../fix-foo # shows what revs each has that the other lacks
I like using the
--line
log formatter for this, since it’s a quick enough summary for most purposes. -
brz tags
-
View the tags and what revs they apply to.
Details of creating tags (hint:
brz tag
) aren’t discussed here. But not much different from any other DVCS. Tags show up in thelog
output as well.
5.5. Maintenance
-
brz pack
-
This (re-)compresses the repository. New commits come in as full texts, and are only delta-compressed when they get repacked. brz does incremental automatic repacks every so often, so you don’t really ever need to do this manually. But it does cram things more tightly.
-
brz check
-
Runs a full integrity check of your repository, making sure all the stored checksums of things match, etc. Nice for peace of mind.
6. Misc bits
6.1. Revision specification
There are various ways to specify revisions. A full description can be
found in brz help revisionspec
or in the online docs. I’ll just skim
over a few of the high points.
-
The revision numbers shown in
brz log
; positive integers, as well as the dotted-decimal variants for merged revs. Note that these only have meaning in the context of a particular branch. -
The long ugly revision-id string that you get from something like
brz log --showids
(generally looks like an email address, followed by a datestamp and some other numbers). These uniquely identify a rev globally, whatever branch it may be in. -
Negative integers; these count backward from the head, so
-1
is the latest or head revision,-2
is the one before that, etc. Useful for looking at recent history (e.g.,brz diff -c-1
to show the change of the last commit). -
A branch name represents the current head of that branch.
-
A tag name representing that tag (e.g., ctwm-3.8.1).
Revspecs can be prefixed for disambiguation (e.g., tag:ctwm-3.8.1
) when
necessary, or will try to guess what you mean. The guesses are usually
pretty good, but see the brz help revisionspec
for details.
Commands that can take two revs (like diff
and stat
, or log
to show
only a subset of revs) pass them to a single -r
arg separated by
“..
” (two periods). So for instance, to look at the diff
or
log
since the 3.8.1 release, you’d run something like “brz diff
-rctwm-3.8.1..-1
”. You can make the range open-ended, since -1
is
as far as it can go anyway: “-rctwm-3.8.1..
”.
6.2. Branch aliases
There are also some "magic" branch aliases that are occasionally useful,
especially with commands like missing
. e.g.:
% cd ~/work/ctwm/brz/trunk
% brz missing :bound
# This tells you what has happened in trunk that you haven't yet
# gotten; i.e., what running 'update' will fetch down)
% cd ../my_working_branch
% brz missing :push
# What changes I've made since the last time I 'push'd this branch up
# to a public location
You can also create your own location aliases globally or per-branch via the bookmarks plugin described below.
6.3. Some command aliases I find useful
Via brz alias
, you can specify command aliases built in to brz. They
become commands you use just like any other, including the ability to
shadow existing commands. Here are some I use, expressed as the command
that will create them.
-
brz alias ci="commit --show-diff"
-
Default to showing the diff in the editor for the commit log. Note that this overrides the default ci alias, which is the same as commit.
-
brz alias flog="log --forward --short"
-
Useful quick log view, especially in construct like “
brz flog -r-10..
”. -
brz alias llog="log -v --long -n0"
-
Shows a more full details log, including the merged revs and files touched in each rev.
-
brz alias missing="missing --line"
-
I only care about a quick summary when I use
missing
. -
brz alias rm="rm --keep"
-
This makes
brz rm
never touch the files in the filesystem. This lets me unversion a file without getting rid of it (I may want to keep it around for reference), and if I want to actually remove it, I just use rm(1) anyway since brz notices and respects that.
(And many more. You’ll find things you specify often and want to shortcut; I won’t rob you of the fun of discovering them yourself :)
6.4. Network transparency
Note that among brz’s capabilities is an abstraction of transports. That means that almost anything you can do against a local branch, you can do against a remote branch as well.
For instance, you can run log remotely.
% brz branch lp:ctwm /tmp/ctwm
% cd /tmp/ctwm
% brz log
# Or do it without making a local branch
% brz log lp:ctwm
You can also merge a branch directly without grabbing it locally first
# Either branch locally first
% cd ~/work/ctwm/brz
% brz branch http://some/branch incoming
% cd trunk
% brz merge ../incoming
# Or go direct
% cd ~/work/ctwm/brz/trunk
% brz merge http://some/branch
Be aware, though, that a lot of these things will be much slower. The
case of merge above is sensible; you’d be copying the same amount of
information either way. And since you’re often not going to do much with
someone’s branch except merge it one time, it can be the right thing
to just merge direct from the remote location. Another command often
useful against a remote branch would be brz missing
.
However, doing a remote log (or diff) is usually a less good idea, since the way the information is accessed remotely is extremely inefficient; it’s going to be very slow, use a lot more bandwidth than you’d expect, and put a heavy load on the server.