1
# Written by Alexander Belchenko
2
# based on Robert Collins code
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
"""Show all 'heads' in a repository"""
25
from bzrlib.commands import Command, display_command, register_command
26
from bzrlib import errors
27
from bzrlib.option import Option
30
class cmd_heads(Command):
31
"""Show all revisions in a repository not having descendants.
33
takes_options = [Option('by-date', help='Sort heads by date (descending)'),
34
Option('all', help='Show all heads (dead and alive)'),
35
Option('dead-only', help='Show only dead heads'),
36
Option('tips', help='Show tips of all branches'),
37
Option('debug-time', help='Enable debug print of operations times'),
40
encoding_type = "replace"
43
def run(self, by_date=False, all=False, dead_only=False, tips=False, debug_time=False):
45
from bzrlib.osutils import format_date
46
import bzrlib.repository
48
self._init_elapsed_time(debug_time)
54
branch = bzrlib.branch.Branch.open_containing('.')[0]
55
repo = branch.repository
56
except errors.NotBranchError:
58
repo = bzrlib.repository.Repository.open('.')
59
except errors.NotBranchError:
61
("You need to run this command "
62
"either from the root of a shared repository,\n"
67
g = repo.get_revision_graph()
68
possible_heads = set(g.keys())
70
for parents in g.values():
71
not_heads.update(set(parents))
73
self.heads = possible_heads.difference(not_heads)
75
# TODO: use different sorting schemes instead of alphabetical sort
76
self.heads = list(self.heads)
78
self._print_elapsed_time('get heads:')
80
## mark heads as dead or alive
81
# mark all heads as dead
84
for head in self.heads:
85
self.head_mark[head] = 'dead'
86
# give the list of live branches in repository or current branch
89
# runs from shared repo root
90
self._iter_branches_update_marks(u'.')
92
from bzrlib.urlutils import (dirname, local_path_from_url)
94
repo_base = repo.bzrdir.transport.base
95
branch_base = branch.bzrdir.transport.base
96
if repo_base == branch_base:
98
last_revid = branch.last_revision()
99
if last_revid in self.heads:
100
self.head_mark[last_revid] = 'alive'
102
self.head_mark[last_revid] = 'tip'
103
self.tips.setdefault(last_revid, []).\
104
append(local_path_from_url(dirname(branch_base)))
107
repo_root = local_path_from_url(dirname(repo_base))
108
self._iter_branches_update_marks(repo_root)
109
self._print_elapsed_time('make head marks:')
112
heads_tips = set(self.heads)
113
heads_tips.update(set(self.tips.keys()))
114
self.heads = list(heads_tips)
115
head_revisions = dict(zip(self.heads,
116
repo.get_revisions(self.heads)))
121
for head in self.heads:
122
rev = head_revisions[head]
123
timestamp = rev.timestamp
124
dates[timestamp] = head
130
self.heads.append(dates[k])
131
self._print_elapsed_time('sort by date:')
136
show_timezone = 'original'
138
for head in self.heads:
140
mark = self.head_mark[head]
147
if not tips or mark != 'tip':
151
if mark in ('alive', 'tip'):
154
print >>to_file, 'TIP of branches:',
155
print >>to_file, '[', ', '.join(t), ']'
157
print >>to_file, 'TIP of branch:', t[0]
159
if mark in ('alive', 'dead'):
160
print >>to_file, 'HEAD:',
162
print >>to_file, "revision-id:", head,
163
if mark == 'dead': print >>to_file, '(dead)'
164
else: print >>to_file
166
rev = head_revisions[head]
167
# borrowed from LongLogFormatter
168
print >>to_file, indent+'committer:', rev.committer
170
print >>to_file, indent+'branch nick: %s' % \
171
rev.properties['branch-nick']
174
date_str = format_date(rev.timestamp,
177
print >>to_file, indent+'timestamp: %s' % date_str
179
print >>to_file, indent+'message:'
181
print >>to_file, indent+' (no message)'
183
message = rev.message.rstrip('\r\n')
184
for l in message.split('\n'):
185
print >>to_file, indent+' ' + l
186
self._print_elapsed_time('print head:')
190
print >>to_file, 'No heads found'
195
def _iter_branches_update_marks(self, root):
198
for directory in os.listdir(u'.'):
199
if directory == '.bzr':
201
if not os.path.isdir(os.path.join(directory, '.bzr')):
204
b = bzrlib.branch.Branch.open_containing(directory)[0]
205
except errors.NotBranchError:
207
last_revid = b.last_revision()
208
if last_revid in self.heads:
209
self.head_mark[last_revid] = 'alive'
211
self.head_mark[last_revid] = 'tip'
212
self.tips.setdefault(last_revid, []).append(directory)
215
def _init_elapsed_time(self, debug_time=False):
216
self.debug_time = debug_time
218
self._time = time.time()
220
def _print_elapsed_time(self, msg):
222
last_time = time.time()
223
print msg, last_time - self._time
224
self._time = last_time
228
register_command(cmd_heads)