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
28
from bzrlib.urlutils import unescape_for_display
31
class cmd_heads(Command):
32
"""Show all revisions in a repository not having descendants.
34
takes_options = [Option('by-date',
35
help='Sort heads by date (descending).'),
36
Option('all', help='Show all heads (dead and alive).'),
37
Option('dead-only', help='Show only dead heads.'),
38
Option('tips', help='Show tips of all branches.'),
40
help='Enable debug print of operations times.'),
43
encoding_type = "replace"
44
takes_args = ['location?']
47
def run(self, by_date=False, all=False, dead_only=False, tips=False,
48
debug_time=False, location='.'):
50
from bzrlib.osutils import format_date
51
import bzrlib.repository
53
self._init_elapsed_time(debug_time)
59
branch = bzrlib.branch.Branch.open_containing(location)[0]
60
repo = branch.repository
61
except errors.NotBranchError:
63
repo = bzrlib.repository.Repository.open(location)
64
except errors.NotBranchError:
66
("You need to run this command "
67
"either from the root of a shared repository,\n"
72
possible_heads = set(repo.all_revision_ids())
73
g = repo.get_graph().get_parent_map(possible_heads)
75
for parents in g.values():
76
not_heads.update(set(parents))
78
self.heads = possible_heads.difference(not_heads)
80
# TODO: use different sorting schemes instead of alphabetical sort
81
self.heads = list(self.heads)
83
self._print_elapsed_time('get heads:')
85
## mark heads as dead or alive
86
# mark all heads as dead
89
for head in self.heads:
90
self.head_mark[head] = 'dead'
91
# give the list of live branches in repository or current branch
93
self._iter_branches_update_marks(repo, self.outf.encoding)
94
self._print_elapsed_time('make head marks:')
97
heads_tips = set(self.heads)
98
heads_tips.update(set(self.tips.keys()))
99
self.heads = list(heads_tips)
100
head_revisions = dict(zip(self.heads,
101
repo.get_revisions(self.heads)))
106
for head in self.heads:
107
rev = head_revisions[head]
108
timestamp = rev.timestamp
109
dates[timestamp] = head
115
self.heads.append(dates[k])
116
self._print_elapsed_time('sort by date:')
121
show_timezone = 'original'
123
for head in self.heads:
125
mark = self.head_mark[head]
132
if not tips or mark != 'tip':
136
if mark in ('alive', 'tip'):
139
print >>to_file, 'TIP of branches:',
140
print >>to_file, '[', ', '.join(t), ']'
142
print >>to_file, 'TIP of branch:', t[0]
144
if mark in ('alive', 'dead'):
145
print >>to_file, 'HEAD:',
147
print >>to_file, "revision-id:", head,
148
if mark == 'dead': print >>to_file, '(dead)'
149
else: print >>to_file
151
rev = head_revisions[head]
152
# borrowed from LongLogFormatter
153
print >>to_file, indent+'committer:', rev.committer
155
print >>to_file, indent+'branch nick: %s' % \
156
rev.properties['branch-nick']
159
date_str = format_date(rev.timestamp,
162
print >>to_file, indent+'timestamp: %s' % date_str
164
print >>to_file, indent+'message:'
166
print >>to_file, indent+' (no message)'
168
message = rev.message.rstrip('\r\n')
169
for l in message.split('\n'):
170
print >>to_file, indent+' ' + l
171
self._print_elapsed_time('print head:')
175
print >>to_file, 'No heads found'
180
def _iter_branches_update_marks(self, repo, encoding):
181
for b in repo.find_branches(using=True):
182
last_revid = b.last_revision()
183
if last_revid in self.heads:
184
self.head_mark[last_revid] = 'alive'
186
self.head_mark[last_revid] = 'tip'
187
escaped = unescape_for_display(b.base, encoding)
188
self.tips.setdefault(last_revid, []).append(escaped)
190
def _init_elapsed_time(self, debug_time=False):
191
self.debug_time = debug_time
193
self._time = time.time()
195
def _print_elapsed_time(self, msg):
197
last_time = time.time()
198
print msg, last_time - self._time
199
self._time = last_time