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"""
24
from bzrlib.commands import Command, display_command
25
from bzrlib import errors
26
from bzrlib.option import Option
27
from bzrlib.urlutils import unescape_for_display
30
class cmd_heads(Command):
31
"""Show all revisions in a repository not having descendants.
33
takes_options = [Option('by-date',
34
help='Sort heads by date (descending).'),
35
Option('all', help='Show all heads (dead and alive).'),
36
Option('dead-only', help='Show only dead heads.'),
37
Option('tips', help='Show tips of all branches.'),
39
help='Enable debug print of operations times.'),
42
encoding_type = "replace"
43
takes_args = ['location?']
46
def run(self, by_date=False, all=False, dead_only=False, tips=False,
47
debug_time=False, location='.'):
49
from bzrlib.osutils import format_date
50
import bzrlib.repository
52
self._init_elapsed_time(debug_time)
58
branch = bzrlib.branch.Branch.open_containing(location)[0]
59
repo = branch.repository
60
except errors.NotBranchError:
62
repo = bzrlib.repository.Repository.open(location)
63
except errors.NotBranchError:
65
("You need to run this command "
66
"either from the root of a shared repository,\n"
71
possible_heads = set(repo.all_revision_ids())
72
g = repo.get_graph().get_parent_map(possible_heads)
74
for parents in g.values():
75
not_heads.update(set(parents))
77
self.heads = possible_heads.difference(not_heads)
79
# TODO: use different sorting schemes instead of alphabetical sort
80
self.heads = list(self.heads)
82
self._print_elapsed_time('get heads:')
84
## mark heads as dead or alive
85
# mark all heads as dead
88
for head in self.heads:
89
self.head_mark[head] = 'dead'
90
# give the list of live branches in repository or current branch
92
self._iter_branches_update_marks(repo, self.outf.encoding)
93
self._print_elapsed_time('make head marks:')
96
heads_tips = set(self.heads)
97
heads_tips.update(set(self.tips.keys()))
98
self.heads = list(heads_tips)
99
head_revisions = dict(zip(self.heads,
100
repo.get_revisions(self.heads)))
105
for head in self.heads:
106
rev = head_revisions[head]
107
timestamp = rev.timestamp
108
dates[timestamp] = head
114
self.heads.append(dates[k])
115
self._print_elapsed_time('sort by date:')
120
show_timezone = 'original'
122
for head in self.heads:
124
mark = self.head_mark[head]
131
if not tips or mark != 'tip':
135
if mark in ('alive', 'tip'):
138
print >>to_file, 'TIP of branches:',
139
print >>to_file, '[', ', '.join(t), ']'
141
print >>to_file, 'TIP of branch:', t[0]
143
if mark in ('alive', 'dead'):
144
print >>to_file, 'HEAD:',
146
print >>to_file, "revision-id:", head,
147
if mark == 'dead': print >>to_file, '(dead)'
148
else: print >>to_file
150
rev = head_revisions[head]
151
# borrowed from LongLogFormatter
152
print >>to_file, indent+'committer:', rev.committer
154
print >>to_file, indent+'branch nick: %s' % \
155
rev.properties['branch-nick']
158
date_str = format_date(rev.timestamp,
161
print >>to_file, indent+'timestamp: %s' % date_str
163
print >>to_file, indent+'message:'
165
print >>to_file, indent+' (no message)'
167
message = rev.message.rstrip('\r\n')
168
for l in message.split('\n'):
169
print >>to_file, indent+' ' + l
170
self._print_elapsed_time('print head:')
174
print >>to_file, 'No heads found'
179
def _iter_branches_update_marks(self, repo, encoding):
180
for b in repo.find_branches(using=True):
181
last_revid = b.last_revision()
182
if last_revid in self.heads:
183
self.head_mark[last_revid] = 'alive'
185
self.head_mark[last_revid] = 'tip'
186
escaped = unescape_for_display(b.base, encoding)
187
self.tips.setdefault(last_revid, []).append(escaped)
189
def _init_elapsed_time(self, debug_time=False):
190
self.debug_time = debug_time
192
self._time = time.time()
194
def _print_elapsed_time(self, msg):
196
last_time = time.time()
197
print msg, last_time - self._time
198
self._time = last_time