87
121
old = new.basis_tree()
88
122
elif len(revision) > 0:
90
rev_id = revision[0].as_revision_id(wt.branch)
124
rev_id = revision[0].in_history(wt.branch).rev_id
91
125
old = wt.branch.repository.revision_tree(rev_id)
92
126
except errors.NoSuchRevision, e:
93
127
raise errors.BzrCommandError(str(e))
94
128
if (len(revision) > 1) and (revision[1].spec is not None):
96
rev_id = revision[1].as_revision_id(wt.branch)
130
rev_id = revision[1].in_history(wt.branch).rev_id
97
131
new = wt.branch.repository.revision_tree(rev_id)
98
132
new_is_working_tree = False
99
133
except errors.NoSuchRevision, e:
100
134
raise errors.BzrCommandError(str(e))
106
_raise_if_nonexistent(specific_files, old, new)
107
want_unversioned = not versioned
137
_raise_if_nonexistent(specific_files, old, new)
138
delta = new.changes_from(old, want_unchanged=show_unchanged,
139
specific_files=specific_files)
142
show_unchanged=show_unchanged,
144
short_status_letter = '?'
146
short_status_letter = ''
147
list_paths('unknown', new.unknowns(), specific_files, to_file,
149
conflict_title = False
150
# show the new conflicts only for now. XXX: get them from the delta.
151
for conflict in new.conflicts():
152
if not short and conflict_title is False:
153
print >> to_file, "conflicts:"
154
conflict_title = True
109
changes = new.iter_changes(old, show_unchanged, specific_files,
110
require_versioned=False, want_unversioned=want_unversioned)
111
reporter = _mod_delta._ChangeReporter(output_file=to_file,
112
unversioned_filter=new.is_ignored)
113
_mod_delta.report_changes(changes, reporter)
115
delta = new.changes_from(old, want_unchanged=show_unchanged,
116
specific_files=specific_files,
117
want_unversioned=want_unversioned)
118
# filter out unknown files. We may want a tree method for
120
delta.unversioned = [unversioned for unversioned in
121
delta.unversioned if not new.is_ignored(unversioned[0])]
124
show_unchanged=show_unchanged,
126
# show the new conflicts only for now. XXX: get them from the
128
conflicts = new.conflicts()
129
if specific_files is not None:
130
conflicts = conflicts.select_conflicts(new, specific_files,
131
ignore_misses=True, recurse=True)[1]
132
if len(conflicts) > 0 and not short:
133
to_file.write("conflicts:\n")
134
for conflict in conflicts:
139
to_file.write("%s %s\n" % (prefix, conflict))
140
if (new_is_working_tree and show_pending
141
and specific_files is None):
142
show_pending_merges(new, to_file, short)
159
print >> to_file, "%s %s" % (prefix, conflict)
160
if new_is_working_tree and show_pending:
161
show_pending_merges(new, to_file, short)
150
def _get_sorted_revisions(tip_revision, revision_ids, parent_map):
151
"""Get an iterator which will return the revisions in merge sorted order.
153
This will build up a list of all nodes, such that only nodes in the list
154
are referenced. It then uses MergeSorter to return them in 'merge-sorted'
157
:param revision_ids: A set of revision_ids
158
:param parent_map: The parent information for each node. Revisions which
159
are considered ghosts should not be present in the map.
160
:return: iterator from MergeSorter.iter_topo_order()
162
# MergeSorter requires that all nodes be present in the graph, so get rid
163
# of any references pointing outside of this graph.
165
for revision_id in revision_ids:
166
if revision_id not in parent_map: # ghost
167
parent_graph[revision_id] = []
169
# Only include parents which are in this sub-graph
170
parent_graph[revision_id] = [p for p in parent_map[revision_id]
171
if p in revision_ids]
172
sorter = tsort.MergeSorter(parent_graph, tip_revision)
173
return sorter.iter_topo_order()
176
165
def show_pending_merges(new, to_file, short=False):
177
166
"""Write out a display of pending merges in a working tree."""
178
167
parents = new.get_parent_ids()
179
168
if len(parents) < 2:
182
# we need one extra space for terminals that wrap on last char
183
term_width = osutils.terminal_width() - 1
191
170
pending = parents[1:]
192
171
branch = new.branch
193
172
last_revision = parents[0]
195
to_file.write('pending merges:\n')
196
graph = branch.repository.get_graph()
197
other_revisions = [last_revision]
198
log_formatter = log.LineLogFormatter(to_file)
174
print >>to_file, 'pending merges:'
175
if last_revision is not None:
177
ignore = set(branch.repository.get_ancestry(last_revision))
178
except errors.NoSuchRevision:
179
# the last revision is a ghost : assume everything is new
181
ignore = set([None, last_revision])
184
# TODO: this could be improved using merge_sorted - we'd get the same
185
# output rather than one level of indent.
199
186
for merge in pending:
201
rev = branch.repository.get_revisions([merge])[0]
189
from bzrlib.osutils import terminal_width
190
width = terminal_width()
191
m_revision = branch.repository.get_revision(merge)
196
print >> to_file, prefix, line_log(m_revision, width - 4)
197
inner_merges = branch.repository.get_ancestry(merge)
198
assert inner_merges[0] is None
200
inner_merges.reverse()
201
for mmerge in inner_merges:
204
mm_revision = branch.repository.get_revision(mmerge)
209
print >> to_file, prefix, line_log(mm_revision, width - 5)
202
211
except errors.NoSuchRevision:
203
# If we are missing a revision, just print out the revision id
204
to_file.write(first_prefix + '(ghost) ' + merge + '\n')
205
other_revisions.append(merge)
216
print >> to_file, prefix, merge
218
def list_paths(header, paths, specific_files, to_file, short_status_letter=''):
221
if specific_files and not is_inside_any(specific_files, path):
208
# Log the merge, as it gets a slightly different formatting
209
log_message = log_formatter.log_string(None, rev,
210
term_width - len(first_prefix))
211
to_file.write(first_prefix + log_message + '\n')
212
# Find all of the revisions in the merge source, which are not in the
213
# last committed revision.
214
merge_extra = graph.find_unique_ancestors(merge, other_revisions)
215
other_revisions.append(merge)
216
merge_extra.discard(_mod_revision.NULL_REVISION)
218
# Get a handle to all of the revisions we will need
220
revisions = dict((rev.revision_id, rev) for rev in
221
branch.repository.get_revisions(merge_extra))
222
except errors.NoSuchRevision:
223
# One of the sub nodes is a ghost, check each one
225
for revision_id in merge_extra:
227
rev = branch.repository.get_revisions([revision_id])[0]
228
except errors.NoSuchRevision:
229
revisions[revision_id] = None
231
revisions[revision_id] = rev
233
# Display the revisions brought in by this merge.
234
rev_id_iterator = _get_sorted_revisions(merge, merge_extra,
235
branch.repository.get_parent_map(merge_extra))
236
# Skip the first node
237
num, first, depth, eom = rev_id_iterator.next()
239
raise AssertionError('Somehow we misunderstood how'
240
' iter_topo_order works %s != %s' % (first, merge))
241
for num, sub_merge, depth, eom in rev_id_iterator:
242
rev = revisions[sub_merge]
244
to_file.write(sub_prefix + '(ghost) ' + sub_merge + '\n')
246
log_message = log_formatter.log_string(None,
247
revisions[sub_merge],
248
term_width - len(sub_prefix))
249
to_file.write(sub_prefix + log_message + '\n')
223
if not short_status_letter and not done_header:
224
print >>to_file, '%s:' % header
226
print >>to_file, '%s %s' % (short_status_letter, path)