1
=======================
2
Integrating with Bazaar
3
=======================
5
This page should hopefully become a quick guide to integrating other
6
(Python-based) software with Bazaar.
8
Manipulating the Working Tree
9
=============================
10
Most objects in Bazaar are in files, named after the class they contain.
11
To manipulate the Working Tree we need a valid WorkingTree object, which
12
is loaded from the workingtree.py file, eg::
14
from bzrlib import workingtree
15
wt = workingtree.WorkingTree.open('/home/jebw/bzrtest')
18
This gives us a WorkingTree object, which has various methods spread over
19
itself, and its parent classes MutableTree and Tree - its worth having a
20
look through these three files (workingtree.py, mutabletree.py and tree.py)
21
to see which methods are available.
25
There are two methods for comparing trees: ``changes_from`` and
26
``iter_changes``. ``iter_changes`` is more regular and precise, but it is
27
somewhat harder to work with. See the API documentation for more details.
29
``changes_from`` creates a Delta object showing changes::
31
from bzrlib import delta
32
changes = wt.changes_from(wt.basis_tree())
34
This gives us a Delta object, which has several lists of files for each type of
35
change, eg changes.added is a list of added files, changes.removed is list
36
of removed files, changes.modified is a list of modified files. The contents
37
of the lists aren't just filenames, but include other information as well.
38
To grab just the filename we want the first value, eg::
40
print("list of newly added files")
41
for filename in changes.added:
42
print("%s has been added" % filename[0])
45
The exception to this is changes.renamed, where the list returned for each
46
renamed files contains both the old and new names -- one or both may interest
47
you, depending on what you're doing.
51
print("list of renamed files")
52
for filename in changes.renamed:
53
print("%s has been renamed to %s" % (filename[0], filename[1]))
59
If you want to add files the same way ``bzr add`` does, you can use
60
MutableTree.smart_add. By default, this is recursive. Paths can either be
61
absolute or relative to the workingtree::
63
wt.smart_add(['dir1/filea.txt', 'fileb.txt',
64
'/home/jebw/bzrtesttree/filec.txt'])
67
For more precise control over which files to add, use MutableTree.add::
69
wt.add(['dir1/filea.txt', 'fileb.txt', '/home/jebw/bzrtesttree/filec.txt'])
75
You can remove multiple files at once. The file paths need to be relative
78
wt.remove(['filea.txt', 'fileb.txt', 'dir1'])
81
By default, the files are not deleted, just removed from the inventory.
82
To delete them from the filesystem as well::
84
wt.remove(['filea.txt', 'fileb.txt', 'dir1'], keep_files=False)
90
You can rename one file to a different name using WorkingTree.rename_one.
91
You just provide the old and new names, eg::
93
wt.rename_one('oldfile.txt','newfile.txt')
99
You can move multiple files from one directory into another using
102
wt.move(['olddir/file.txt'], 'newdir')
105
More complicated renames/moves can be done with transform.TreeTransform,
106
which is outside the scope of this document.
112
To commit _all_ the changes to our working tree we can just call the
113
WorkingTree's commit method, giving it a commit message, eg::
115
wt.commit('this is my commit message')
118
To commit only certain files, we need to provide a list of filenames which we
119
want committing, eg::
121
wt.commit(message='this is my commit message', specific_files=['fileA.txt',
122
'dir2/fileB.txt', 'fileD.txt'])
125
Generating a Log for a File
126
===========================
128
Generating a log is, in itself, simple. Grab a branch (see below) and pass
129
it to show_log together with a log formatter, eg::
131
from bzrlib import log
132
from bzrlib import branch
134
b = branch.Branch.open('/path/to/bazaar/branch')
135
lf = log.LongLogFormatter(to_file=sys.stdout)
139
Three log formatters are included with bzrlib: LongLogFormatter,
140
ShortLogFormatter and LineLogFormatter. These provide long, short and
141
single-line log output formats. It's also possible to write your own in
147
To annotate a file, we want to walk every line of a file, retrieving the
148
revision which last modified/created that line and then retrieving the
149
information for that revision.
151
First we get an annotation iterator for the file we are interested in::
153
tree, relpath = workingtree.WorkingTree.open_containing('/path/to/file.txt')
154
fileid = tree.path2id(relpath)
155
annotation = list(tree.annotate_iter(fileid))
158
To avoid repeatedly retrieving the same revisions we grab all revisions
159
associated with the file at once and build up a map of id to revision
160
information. We also build an map of revision numbers, again indexed
163
revision_ids = set(revision_id for revision_id, text in annotation)
164
revisions = tree.branch.repository.get_revisions(revision_ids)
165
revision_map = dict(izip(revision_ids, revisions))
166
revno_map = tree.branch.get_revision_id_to_revno_map()
169
Finally, we use our annotation iterator to walk the lines of the file,
170
displaying the information from our revision maps as we go::
172
for revision_id, text in annotation :
173
rev = revision_map[revision_id]
174
revno = revno_map[revision_id]
175
revno_string = '.'.join(str(i) for i in revno)
176
print "%s, %s: %s" % (revno_string, rev.committer, text)
179
Working with branches
180
=====================
182
To work with a branch you need a branch object, created from your branch::
184
from bzrlib import branch
186
b = branch.Branch.open('/home/jebw/bzrtest')
189
Branching from an existing branch
190
=================================
192
To branch you create a branch object representing the branch you are
193
branching from, and supply a path/url to the new branch location.
194
The following code clones the bzr.dev branch (the latest copy of the Bazaar
195
source code) - be warned it has to download 60meg so takes a while to run
198
from bzrlib import branch
200
b = branch.Branch.open('http://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev')
201
nb = b.bzrdir.sprout('/tmp/newBzrBranch').open_branch()
204
This provides no feedback, since Bazaar automatically uses the 'silent' UI.
207
Pushing and pulling branches
208
============================
210
To push a branch you need to open the source and destination branches, then
211
just call push with the other branch as a parameter::
213
from bzrlib import branch
215
b1 = branch.Branch.open('file:///home/user/mybranch')
216
b2 = branch.Branch.open('http://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev')
220
Pulling is much the same::
225
If you have a working tree, as well as a branch, you should use
226
WorkingTree.pull, not Branch.pull.
228
This won't handle conflicts automatically though, so any conflicts will be
229
left in the working tree for the user to resolve.
232
Checkout from an existing branch
233
================================
235
This performs a Lightweight checkout from an existing Branch::
237
from bzrlib import bzrdir
239
accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch('http:URL')
240
source.create_checkout('/tmp/newBzrCheckout', None, True, accelerator_tree)
243
To make a heavyweight checkout, change the last line to::
245
source.create_checkout('/tmp/newBzrCheckout', None, False, accelerator_tree
251
Finding the last revision number or id
252
--------------------------------------
254
To get the last revision number and id of a branch use::
256
revision_number, revision_id = branch.last_revision_info()
259
If all you care about is the revision_id there is also the
262
revision_id = branch.last_revision()
265
Getting the list of revision ids that make up a branch
266
------------------------------------------------------
268
IMPORTANT: This should be avoided wherever possible, as it scales with the
271
revisions = branch.revision_history()
273
now revisions[0] is the revision id of the first commit, and revs[-1] is the
274
revision id of the most recent. Note that if all you want is the last
275
revision then you should use branch.last_revision() as described above, as
276
it is vastly more efficient.
279
Getting a Revision object from a revision id
280
--------------------------------------------
282
The Revision object has attributes like "message" to get the information
285
repo = branch.repository
286
revision = repo.get_revision(rev_id)
289
Accessing the files from a revision
290
-----------------------------------
292
To get the file contents and tree shape for a specific revision you need
293
a RevisionTree. These are supplied by the repository for a specific
296
revtree = repo.revision_tree(rev_id)
298
RevisionTrees, like all trees, can be compared as described in "Comparing
301
The most common way to list files in a tree is ``Tree.iter_entries()``.
302
The simplest way to get file content is ``Tree.get_file()``. The best way
303
to retrieve file content for large numbers of files `Tree.iter_files_bytes()``