1
# Copyright (C) 2005 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
61
61
import bzrlib.errors as errors
62
62
from bzrlib.symbol_versioning import deprecated_method, zero_eleven
63
63
from bzrlib.trace import mutter
64
from bzrlib.tsort import merge_sort
64
from bzrlib.tsort import(
67
70
def find_touching_revisions(branch, file_id):
221
224
symbol_versioning.warn('LogFormatters should provide show_merge_revno '
222
225
'instead of show_merge since bzr 0.11.',
223
226
DeprecationWarning, stacklevel=3)
224
view_revisions = list(get_view_revisions(mainline_revs, rev_nos, branch,
225
direction, include_merges=include_merges))
227
view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
228
direction, include_merges=include_merges)
230
view_revisions = _get_revisions_touching_file_id(branch,
235
view_revisions = list(view_revs_iter)
227
237
use_tags = getattr(lf, 'supports_tags', False)
247
257
delta_revisions), deltas))
248
258
for revision in revisions:
249
259
# The delta value will be None unless
250
# 1. verbose or specific_fileid is specified, and
260
# 1. verbose is specified, and
251
261
# 2. the revision is a mainline revision
252
262
yield revision, cur_deltas.get(revision.revision_id)
253
263
revision_ids = revision_ids[num:]
264
num = min(int(num * 1.5), 200)
256
266
# now we just print all the revisions
257
267
for ((rev_id, revno, merge_depth), (rev, delta)) in \
264
274
if merge_depth == 0:
265
# a mainline revision.
268
if not delta.touches_file_id(specific_fileid):
272
# although we calculated it, throw it away without display
276
276
lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
287
287
lf.show_merge_revno(rev, merge_depth, revno)
290
def _get_revisions_touching_file_id(branch, file_id, mainline_revisions,
292
"""Return the list of revision ids which touch a given file id.
294
This includes the revisions which directly change the file id,
295
and the revisions which merge these changes. So if the
303
And 'C' changes a file, then both C and D will be returned.
305
This will also can be restricted based on a subset of the mainline.
307
:return: A list of (revision_id, dotted_revno, merge_depth) tuples.
309
# find all the revisions that change the specific file
310
file_weave = branch.repository.weave_store.get_weave(file_id,
311
branch.repository.get_transaction())
312
weave_modifed_revisions = set(file_weave.versions())
313
# build the ancestry of each revision in the graph
314
# - only listing the ancestors that change the specific file.
315
rev_graph = branch.repository.get_revision_graph(mainline_revisions[-1])
316
sorted_rev_list = topo_sort(rev_graph)
318
for rev in sorted_rev_list:
319
parents = rev_graph[rev]
320
if rev not in weave_modifed_revisions and len(parents) == 1:
321
# We will not be adding anything new, so just use a reference to
322
# the parent ancestry.
323
rev_ancestry = ancestry[parents[0]]
326
if rev in weave_modifed_revisions:
327
rev_ancestry.add(rev)
328
for parent in parents:
329
rev_ancestry = rev_ancestry.union(ancestry[parent])
330
ancestry[rev] = rev_ancestry
332
def is_merging_rev(r):
333
parents = rev_graph[r]
335
leftparent = parents[0]
336
for rightparent in parents[1:]:
337
if not ancestry[leftparent].issuperset(
338
ancestry[rightparent]):
342
# filter from the view the revisions that did not change or merge
344
return [(r, n, d) for r, n, d in view_revs_iter
345
if r in weave_modifed_revisions or is_merging_rev(r)]
290
348
def get_view_revisions(mainline_revs, rev_nos, branch, direction,
291
349
include_merges=True):
292
350
"""Produce an iterator of revisions to show