13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Display what revisions are missing in 'other' from 'this' and vice versa."""
19
from bzrlib.log import (
23
22
import bzrlib.revision as _mod_revision
26
25
def iter_log_revisions(revisions, revision_source, verbose):
27
26
last_tree = revision_source.revision_tree(_mod_revision.NULL_REVISION)
30
# We need the following for backward compatibilty (hopefully
31
# this will be deprecated soon :-/) -- vila 080911
36
revno, rev_id, merge_depth = rev
28
for revno, rev_id in revisions:
37
29
rev = revision_source.get_revision(rev_id)
39
delta = revision_source.get_revision_delta(rev_id)
31
remote_tree = revision_source.revision_tree(rev_id)
32
parent_rev_id = rev.parent_ids[0]
33
if last_rev_id == parent_rev_id:
34
parent_tree = last_tree
36
parent_tree = revision_source.revision_tree(parent_rev_id)
37
revision_tree = revision_source.revision_tree(rev_id)
39
last_tree = revision_tree
40
delta = revision_tree.changes_from(parent_tree)
42
yield log.LogRevision(rev, revno, merge_depth, delta=delta)
45
def find_unmerged(local_branch, remote_branch, restrict='all',
46
include_merged=None, backward=False,
47
local_revid_range=None, remote_revid_range=None,
48
include_merges=symbol_versioning.DEPRECATED_PARAMETER):
43
yield LogRevision(rev, revno, delta=delta)
46
def find_unmerged(local_branch, remote_branch, restrict='all'):
49
47
"""Find revisions from each side that have not been merged.
51
49
:param local_branch: Compare the history of local_branch
55
53
unique revisions from both sides. If 'local', we will return None
56
54
for the remote revisions, similarly if 'remote' we will return None for
57
55
the local revisions.
58
:param include_merged: Show mainline revisions only if False,
59
all revisions otherwise.
60
:param backward: Show oldest versions first when True, newest versions
62
:param local_revid_range: Revision-id range for filtering local_branch
63
revisions (lower bound, upper bound)
64
:param remote_revid_range: Revision-id range for filtering remote_branch
65
revisions (lower bound, upper bound)
66
:param include_merges: Deprecated historical alias for include_merged
68
57
:return: A list of [(revno, revision_id)] for the mainline revisions on
71
if symbol_versioning.deprecated_passed(include_merges):
72
symbol_versioning.warn(
73
'include_merges was deprecated in 2.5.'
74
' Use include_merged instead.',
75
DeprecationWarning, stacklevel=2)
76
if include_merged is None:
77
include_merged = include_merges
78
if include_merged is None:
79
include_merged = False
80
60
local_branch.lock_read()
82
62
remote_branch.lock_read()
84
return _find_unmerged(
85
local_branch, remote_branch, restrict=restrict,
86
include_merged=include_merged, backward=backward,
87
local_revid_range=local_revid_range,
88
remote_revid_range=remote_revid_range)
64
return _find_unmerged(local_branch,
65
remote_branch, restrict=restrict)
90
67
remote_branch.unlock()
92
69
local_branch.unlock()
95
def _enumerate_mainline(ancestry, graph, tip_revno, tip, backward=True):
72
def _enumerate_mainline(ancestry, graph, tip_revno, tip):
96
73
"""Enumerate the mainline revisions for these revisions.
98
75
:param ancestry: A set of revisions that we care about
99
76
:param graph: A Graph which lets us find the parents for a revision
100
77
:param tip_revno: The revision number for the tip revision
101
78
:param tip: The tip of mainline
102
:param backward: Show oldest versions first when True, newest versions
104
79
:return: [(revno, revision_id)] for all revisions in ancestry that
105
80
are left-hand parents from tip, or None if ancestry is None.
121
96
parents = parent_map.get(cur)
123
98
break # Ghost, we are done
124
mainline.append((str(cur_revno), cur))
99
mainline.append((cur_revno, cur))
132
def _enumerate_with_merges(branch, ancestry, graph, tip_revno, tip,
134
"""Enumerate the revisions for the ancestry.
136
:param branch: The branch we care about
137
:param ancestry: A set of revisions that we care about
138
:param graph: A Graph which lets us find the parents for a revision
139
:param tip_revno: The revision number for the tip revision
140
:param tip: The tip of the ancsetry
141
:param backward: Show oldest versions first when True, newest versions
143
:return: [(revno, revision_id)] for all revisions in ancestry that
144
are parents from tip, or None if ancestry is None.
148
if not ancestry: #Empty ancestry, no need to do any work
151
merge_sorted_revisions = branch.iter_merge_sorted_revisions()
152
# Now that we got the correct revnos, keep only the relevant
154
merge_sorted_revisions = [
155
# log.reverse_by_depth expects seq_num to be present, but it is
156
# stripped by iter_merge_sorted_revisions()
157
(0, revid, n, d, e) for revid, n, d, e in merge_sorted_revisions
158
if revid in ancestry]
160
merge_sorted_revisions = log.reverse_by_depth(merge_sorted_revisions)
162
for seq, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
163
revline.append(('.'.join(map(str, revno)), rev_id, merge_depth))
167
def _filter_revs(graph, revs, revid_range):
168
if revid_range is None or revs is None:
170
return [rev for rev in revs
171
if graph.is_between(rev[1], revid_range[0], revid_range[1])]
174
def _find_unmerged(local_branch, remote_branch, restrict,
175
include_merged, backward,
176
local_revid_range=None, remote_revid_range=None):
106
def _find_unmerged(local_branch, remote_branch, restrict):
177
107
"""See find_unmerged.
179
109
The branches should already be locked before entering.
183
113
if local_revno == remote_revno and local_revision_id == remote_revision_id:
184
114
# A simple shortcut when the tips are at the same point
186
graph = local_branch.repository.get_graph(remote_branch.repository)
116
graph = local_branch.repository.get_graph(
117
remote_branch.repository)
187
118
if restrict == 'remote':
188
119
local_extra = None
189
remote_extra = graph.find_unique_ancestors(remote_revision_id,
120
remote_extra = graph.find_unique_ancestors(
121
remote_revision_id, [local_revision_id])
191
122
elif restrict == 'local':
192
123
remote_extra = None
193
local_extra = graph.find_unique_ancestors(local_revision_id,
194
[remote_revision_id])
124
local_extra = graph.find_unique_ancestors(
125
local_revision_id, [remote_revision_id])
196
127
if restrict != 'all':
197
128
raise ValueError('param restrict not one of "all", "local",'
198
129
' "remote": %r' % (restrict,))
199
local_extra, remote_extra = graph.find_difference(local_revision_id,
202
locals = _enumerate_with_merges(local_branch, local_extra,
204
local_revision_id, backward)
205
remotes = _enumerate_with_merges(remote_branch, remote_extra,
207
remote_revision_id, backward)
209
# Now that we have unique ancestors, compute just the mainline, and
210
# generate revnos for them.
211
locals = _enumerate_mainline(local_extra, graph, local_revno,
212
local_revision_id, backward)
213
remotes = _enumerate_mainline(remote_extra, graph, remote_revno,
214
remote_revision_id, backward)
215
return _filter_revs(graph, locals, local_revid_range), _filter_revs(graph,
216
remotes, remote_revid_range)
130
local_extra, remote_extra = graph.find_difference(
131
local_revision_id, remote_revision_id)
132
# Now that we have unique ancestors, compute just the mainline, and
133
# generate revnos for them.
134
local_mainline = _enumerate_mainline(local_extra, graph, local_revno,
136
remote_mainline = _enumerate_mainline(remote_extra, graph, remote_revno,
138
return local_mainline, remote_mainline
219
141
def sorted_revisions(revisions, history_map):