/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1110 by Martin Pool
- merge aaron's merge improvements:
1
# Copyright (C) 2005 Canonical Ltd
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
17
1185.1.2 by Martin Pool
- merge various windows and other fixes from Ollie Rutherfurd
18
import os
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
19
import errno
1113 by Martin Pool
- fix is_ancestor import problem in merge
20
1545.2.1 by Aaron Bentley
Made the merge internals private
21
import bzrlib
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
22
from bzrlib._changeset import generate_changeset, ExceptionConflictHandler
23
from bzrlib._changeset import Inventory, Diff3Merge, ReplaceContents
1545.2.1 by Aaron Bentley
Made the merge internals private
24
from bzrlib._merge_core import WeaveMerge
25
from bzrlib._merge_core import merge_flex, ApplyMerge3, BackupBeforeChange
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
26
from bzrlib.branch import Branch
1545.2.1 by Aaron Bentley
Made the merge internals private
27
from bzrlib.delta import compare_trees
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
28
from bzrlib.errors import (BzrCommandError,
1534.4.28 by Robert Collins
first cut at merge from integration.
29
                           BzrError,
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
30
                           NoCommonAncestor,
31
                           NoCommits,
1534.4.28 by Robert Collins
first cut at merge from integration.
32
                           NoSuchRevision,
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
33
                           NotBranchError,
1185.33.27 by Martin Pool
[merge] much integrated work from robert and john
34
                           NotVersionedError,
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
35
                           UnrelatedBranches,
36
                           WorkingTreeNotRevision,
1534.4.28 by Robert Collins
first cut at merge from integration.
37
                           )
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
38
import bzrlib.osutils
39
from bzrlib.osutils import rename, pathjoin
1534.4.28 by Robert Collins
first cut at merge from integration.
40
from bzrlib.revision import common_ancestor, is_ancestor, NULL_REVISION
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
41
from bzrlib.trace import mutter, warning, note
42
43
# TODO: Report back as changes are merged in
44
45
# comments from abentley on irc: merge happens in two stages, each
46
# of which generates a changeset object
47
48
# stage 1: generate OLD->OTHER,
49
# stage 2: use MINE and OLD->OTHER to generate MINE -> RESULT
50
51
class _MergeConflictHandler(ExceptionConflictHandler):
52
    """Handle conflicts encountered while merging.
53
54
    This subclasses ExceptionConflictHandler, so that any types of
55
    conflict that are not explicitly handled cause an exception and
56
    terminate the merge.
57
    """
58
    def __init__(self, this_tree, base_tree, other_tree, ignore_zero=False):
59
        ExceptionConflictHandler.__init__(self)
60
        self.conflicts = 0
61
        self.ignore_zero = ignore_zero
62
        self.this_tree = this_tree
63
        self.base_tree = base_tree
64
        self.other_tree = other_tree
65
66
    def copy(self, source, dest):
67
        """Copy the text and mode of a file
68
        :param source: The path of the file to copy
69
        :param dest: The distination file to create
70
        """
71
        s_file = file(source, "rb")
72
        d_file = file(dest, "wb")
73
        for line in s_file:
74
            d_file.write(line)
75
        os.chmod(dest, 0777 & os.stat(source).st_mode)
76
77
    def dump(self, lines, dest):
78
        """Copy the text and mode of a file
79
        :param source: The path of the file to copy
80
        :param dest: The distination file to create
81
        """
82
        d_file = file(dest, "wb")
83
        for line in lines:
84
            d_file.write(line)
85
86
    def add_suffix(self, name, suffix, last_new_name=None, fix_inventory=True):
87
        """Rename a file to append a suffix.  If the new name exists, the
88
        suffix is added repeatedly until a non-existant name is found
89
90
        :param name: The path of the file
91
        :param suffix: The suffix to append
92
        :param last_new_name: (used for recursive calls) the last name tried
93
        """
94
        if last_new_name is None:
95
            last_new_name = name
96
        new_name = last_new_name+suffix
97
        try:
98
            rename(name, new_name)
99
            if fix_inventory is True:
100
                try:
101
                    relpath = self.this_tree.relpath(name)
102
                except NotBranchError:
103
                    relpath = None
104
                if relpath is not None:
105
                    file_id = self.this_tree.path2id(relpath)
106
                    if file_id is not None:
107
                        new_path = self.this_tree.relpath(new_name)
108
                        rename(new_name, name)
109
                        self.this_tree.rename_one(relpath, new_path)
110
                        assert self.this_tree.id2path(file_id) == new_path
111
        except OSError, e:
112
            if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY:
113
                raise
114
            return self.add_suffix(name, suffix, last_new_name=new_name, 
115
                                   fix_inventory=fix_inventory)
116
        return new_name
117
118
    def conflict(self, text):
119
        warning(text)
120
        self.conflicts += 1
121
        
122
123
    def merge_conflict(self, new_file, this_path, base_lines, other_lines):
124
        """
125
        Handle diff3 conflicts by producing a .THIS, .BASE and .OTHER.  The
126
        main file will be a version with diff3 conflicts.
127
        :param new_file: Path to the output file with diff3 markers
128
        :param this_path: Path to the file text for the THIS tree
129
        :param base_path: Path to the file text for the BASE tree
130
        :param other_path: Path to the file text for the OTHER tree
131
        """
132
        self.add_suffix(this_path, ".THIS", fix_inventory=False)
133
        self.dump(base_lines, this_path+".BASE")
134
        self.dump(other_lines, this_path+".OTHER")
135
        rename(new_file, this_path)
136
        self.conflict("Diff3 conflict encountered in %s" % this_path)
137
138
    def weave_merge_conflict(self, filename, weave, other_i, out_file):
139
        """
140
        Handle weave conflicts by producing a .THIS, and .OTHER.  The
141
        main file will be a version with diff3-style conflicts.
142
        """
143
        self.add_suffix(filename, ".THIS", fix_inventory=False)
144
        out_file.commit()
145
        self.dump(weave.get_iter(other_i), filename+".OTHER")
146
        self.conflict("Text conflict encountered in %s" % filename)
147
148
    def new_contents_conflict(self, filename, other_contents):
149
        """Conflicting contents for newly added file."""
150
        other_contents(filename + ".OTHER", self, False)
151
        self.conflict("Conflict in newly added file %s" % filename)
152
    
153
154
    def target_exists(self, entry, target, old_path):
155
        """Handle the case when the target file or dir exists"""
156
        moved_path = self.add_suffix(target, ".moved")
157
        self.conflict("Moved existing %s to %s" % (target, moved_path))
158
159
    def rmdir_non_empty(self, filename):
160
        """Handle the case where the dir to be removed still has contents"""
161
        self.conflict("Directory %s not removed because it is not empty"\
162
            % filename)
163
        return "skip"
164
165
    def rem_contents_conflict(self, filename, this_contents, base_contents):
166
        base_contents(filename+".BASE", self)
167
        this_contents(filename+".THIS", self)
168
        self.conflict("Other branch deleted locally modified file %s" %
169
                      filename)
170
        return ReplaceContents(this_contents, None)
171
172
    def abs_this_path(self, file_id):
173
        """Return the absolute path for a file_id in the this tree."""
174
        return self.this_tree.id2abspath(file_id)
175
176
    def add_missing_parents(self, file_id, tree):
177
        """If some of the parents for file_id are missing, add them."""
178
        entry = tree.inventory[file_id]
179
        if entry.parent_id not in self.this_tree:
180
            return self.create_all_missing(entry.parent_id, tree)
181
        else:
182
            return self.abs_this_path(entry.parent_id)
183
184
    def create_all_missing(self, file_id, tree):
185
        """Add contents for a file_id and all its parents to a tree."""
186
        entry = tree.inventory[file_id]
187
        if entry.parent_id is not None and entry.parent_id not in self.this_tree:
188
            abspath = self.create_all_missing(entry.parent_id, tree)
189
        else:
190
            abspath = self.abs_this_path(entry.parent_id)
191
        entry_path = pathjoin(abspath, entry.name)
192
        if not os.path.isdir(entry_path):
193
            self.create(file_id, entry_path, tree)
194
        return entry_path
195
196
    def create(self, file_id, path, tree):
197
        """Uses tree data to create a filesystem object for the file_id"""
1545.2.10 by Aaron Bentley
Fixed up non-absolute imports
198
        from bzrlib._changeset import get_contents
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
199
        get_contents(tree, file_id)(path, self)
200
201
    def missing_for_merge(self, file_id, other_path):
202
        """The file_id doesn't exist in THIS, but does in OTHER and BASE"""
203
        self.conflict("Other branch modified locally deleted file %s" %
204
                      other_path)
205
        parent_dir = self.add_missing_parents(file_id, self.other_tree)
206
        stem = pathjoin(parent_dir, os.path.basename(other_path))
207
        self.create(file_id, stem+".OTHER", self.other_tree)
208
        self.create(file_id, stem+".BASE", self.base_tree)
209
210
    def threeway_contents_conflict(filename, this_contents, base_contents,
211
                                   other_contents):
212
        self.conflict("Three-way conflict merging %s" % filename)
213
214
    def finalize(self):
215
        if self.conflicts == 0:
216
            if not self.ignore_zero:
217
                note("All changes applied successfully.")
218
        else:
219
            note("%d conflicts encountered." % self.conflicts)
1545.2.4 by Aaron Bentley
PEP8 fixes
220
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
221
def _get_tree(treespec, local_branch=None):
622 by Martin Pool
Updated merge patch from Aaron
222
    location, revno = treespec
1442.1.64 by Robert Collins
Branch.open_containing now returns a tuple (Branch, relative-path).
223
    branch = Branch.open_containing(location)[0]
493 by Martin Pool
- Merge aaron's merge command
224
    if revno is None:
974.1.36 by aaron.bentley at utoronto
Committed it even though the test case doesn't work
225
        revision = None
226
    elif revno == -1:
1241 by Martin Pool
- rename last_patch to last_revision
227
        revision = branch.last_revision()
974.1.36 by aaron.bentley at utoronto
Committed it even though the test case doesn't work
228
    else:
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
229
        revision = branch.get_rev_id(revno)
1185.12.98 by Aaron Bentley
Support for forcing merges of unrelated trees
230
        if revision is None:
231
            revision = NULL_REVISION
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
232
    return branch, _get_revid_tree(branch, revision, local_branch)
974.1.36 by aaron.bentley at utoronto
Committed it even though the test case doesn't work
233
1545.2.4 by Aaron Bentley
PEP8 fixes
234
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
235
def _get_revid_tree(branch, revision, local_branch):
974.1.36 by aaron.bentley at utoronto
Committed it even though the test case doesn't work
236
    if revision is None:
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
237
        base_tree = branch.bzrdir.open_workingtree()
493 by Martin Pool
- Merge aaron's merge command
238
    else:
974.1.32 by aaron.bentley at utoronto
Made merge do greedy fetching.
239
        if local_branch is not None:
1185.65.30 by Robert Collins
Merge integration.
240
            if local_branch.base != branch.base:
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
241
                local_branch.fetch(branch, revision)
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
242
            base_tree = local_branch.repository.revision_tree(revision)
974.1.32 by aaron.bentley at utoronto
Made merge do greedy fetching.
243
        else:
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
244
            base_tree = branch.repository.revision_tree(revision)
1185.12.41 by abentley
Got rid of MergeAdapterTree
245
    return base_tree
493 by Martin Pool
- Merge aaron's merge command
246
247
1185.35.4 by Aaron Bentley
Implemented remerge
248
def transform_tree(from_tree, to_tree, interesting_ids=None):
249
    merge_inner(from_tree.branch, to_tree, from_tree, ignore_zero=True,
250
                interesting_ids=interesting_ids)
628 by Martin Pool
- merge aaron's updated merge/pull code
251
1457.1.12 by Robert Collins
Update comment to reflect author.
252
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
253
def merge_inner(this_branch, other_tree, base_tree, ignore_zero=False,
1185.33.27 by Martin Pool
[merge] much integrated work from robert and john
254
                backup_files=False, 
255
                merge_type=ApplyMerge3, 
256
                interesting_ids=None, 
257
                show_base=False, 
258
                reprocess=False, 
259
                other_rev_id=None,
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
260
                interesting_files=None,
261
                this_tree=None):
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
262
    """Primary interface for merging. 
263
264
        typical use is probably 
265
        'merge_inner(branch, branch.get_revision_tree(other_revision),
266
                     branch.get_revision_tree(base_revision))'
267
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
268
    if this_tree is None:
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
269
        this_tree = this_branch.bzrdir.open_workingtree()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
270
    merger = Merger(this_branch, other_tree, base_tree, this_tree=this_tree)
1457.1.7 by Robert Collins
Change cmd_revert to use merge_inner.
271
    merger.backup_files = backup_files
1185.35.4 by Aaron Bentley
Implemented remerge
272
    merger.merge_type = merge_type
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
273
    merger.interesting_ids = interesting_ids
1457.1.7 by Robert Collins
Change cmd_revert to use merge_inner.
274
    if interesting_files:
275
        assert not interesting_ids, ('Only supply interesting_ids'
276
                                     ' or interesting_files')
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
277
        merger._set_interesting_files(interesting_files)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
278
    merger.show_base = show_base 
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
279
    merger.reprocess = reprocess
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
280
    merger.conflict_handler = _MergeConflictHandler(merger.this_tree, 
281
                                                    base_tree, other_tree,
282
                                                    ignore_zero=ignore_zero)
1185.35.4 by Aaron Bentley
Implemented remerge
283
    merger.other_rev_id = other_rev_id
284
    merger.other_basis = other_rev_id
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
285
    return merger.do_merge()
286
287
288
class Merger(object):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
289
    def __init__(self, this_branch, other_tree=None, base_tree=None, this_tree=None):
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
290
        object.__init__(self)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
291
        assert this_tree is not None, "this_tree is required"
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
292
        self.this_branch = this_branch
293
        self.this_basis = this_branch.last_revision()
294
        self.this_rev_id = None
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
295
        self.this_tree = this_tree
1185.12.83 by Aaron Bentley
Preliminary weave merge support
296
        self.this_revision_tree = None
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
297
        self.this_basis_tree = None
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
298
        self.other_tree = other_tree
299
        self.base_tree = base_tree
300
        self.ignore_zero = False
301
        self.backup_files = False
302
        self.interesting_ids = None
303
        self.show_base = False
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
304
        self.reprocess = False
1545.2.6 by Aaron Bentley
Removed _merge, renamed MergeConflictHandler to _MergeConflictHandler
305
        self.conflict_handler = _MergeConflictHandler(self.this_tree, 
306
                                                      base_tree, other_tree)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
307
308
    def revision_tree(self, revision_id):
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
309
        return self.this_branch.repository.revision_tree(revision_id)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
310
311
    def ensure_revision_trees(self):
312
        if self.this_revision_tree is None:
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
313
            self.this_basis_tree = self.this_branch.repository.revision_tree(
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
314
                self.this_basis)
315
            if self.this_basis == self.this_rev_id:
316
                self.this_revision_tree = self.this_basis_tree
317
1185.12.83 by Aaron Bentley
Preliminary weave merge support
318
        if self.other_rev_id is None:
319
            other_basis_tree = self.revision_tree(self.other_basis)
320
            changes = compare_trees(self.other_tree, other_basis_tree)
321
            if changes.has_changed():
322
                raise WorkingTreeNotRevision(self.this_tree)
323
            other_rev_id = other_basis
324
            self.other_tree = other_basis_tree
325
326
    def file_revisions(self, file_id):
327
        self.ensure_revision_trees()
328
        def get_id(tree, file_id):
329
            revision_id = tree.inventory[file_id].revision
330
            assert revision_id is not None
331
            return revision_id
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
332
        if self.this_rev_id is None:
333
            if self.this_basis_tree.get_file_sha1(file_id) != \
334
                self.this_tree.get_file_sha1(file_id):
335
                raise WorkingTreeNotRevision(self.this_tree)
336
337
        trees = (self.this_basis_tree, self.other_tree)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
338
        return [get_id(tree, file_id) for tree in trees]
339
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
340
    def merge_factory(self, file_id, base, other):
1185.12.83 by Aaron Bentley
Preliminary weave merge support
341
        if self.merge_type.history_based:
1185.35.4 by Aaron Bentley
Implemented remerge
342
            if self.show_base is True:
343
                raise BzrError("Cannot show base for hisory-based merges")
344
            if self.reprocess is True:
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
345
                raise BzrError("Cannot reprocess history-based merges")
1185.35.4 by Aaron Bentley
Implemented remerge
346
                
1185.12.83 by Aaron Bentley
Preliminary weave merge support
347
            t_revid, o_revid = self.file_revisions(file_id)
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
348
            weave = self.this_basis_tree.get_weave(file_id)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
349
            contents_change = self.merge_type(weave, t_revid, o_revid)
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
350
        else:
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
351
            if self.show_base is True or self.reprocess is True:
1185.12.83 by Aaron Bentley
Preliminary weave merge support
352
                contents_change = self.merge_type(file_id, base, other, 
1185.24.3 by Aaron Bentley
Integrated reprocessing into the rest of the merge stuff
353
                                                  show_base=self.show_base, 
354
                                                  reprocess=self.reprocess)
1185.12.83 by Aaron Bentley
Preliminary weave merge support
355
            else:
356
                contents_change = self.merge_type(file_id, base, other)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
357
        if self.backup_files:
358
            contents_change = BackupBeforeChange(contents_change)
359
        return contents_change
360
361
    def check_basis(self, check_clean):
362
        if self.this_basis is None:
363
            raise BzrCommandError("This branch has no commits")
364
        if check_clean:
365
            self.compare_basis()
366
            if self.this_basis != self.this_rev_id:
367
                raise BzrCommandError("Working tree has uncommitted changes.")
368
369
    def compare_basis(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
370
        changes = compare_trees(self.this_tree, 
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
371
                                self.this_tree.basis_tree(), False)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
372
        if not changes.has_changed():
373
            self.this_rev_id = self.this_basis
374
375
    def set_interesting_files(self, file_list):
1457.1.8 by Robert Collins
Replace the WorkingTree.revert method algorithm with a call to merge_inner.
376
        try:
377
            self._set_interesting_files(file_list)
378
        except NotVersionedError, e:
379
            raise BzrCommandError("%s is not a source file in any"
380
                                      " tree." % e.path)
381
382
    def _set_interesting_files(self, file_list):
383
        """Set the list of interesting ids from a list of files."""
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
384
        if file_list is None:
385
            self.interesting_ids = None
386
            return
387
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
388
        interesting_ids = set()
1185.50.53 by John Arbash Meinel
[patch] Aaron Bentley: make revert work in a subdirectory.
389
        for path in file_list:
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
390
            found_id = False
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
391
            for tree in (self.this_tree, self.base_tree, self.other_tree):
1465 by Robert Collins
Bugfix the new pull --clobber to not generate spurious conflicts.
392
                file_id = tree.inventory.path2id(path)
393
                if file_id is not None:
394
                    interesting_ids.add(file_id)
395
                    found_id = True
396
            if not found_id:
1185.50.53 by John Arbash Meinel
[patch] Aaron Bentley: make revert work in a subdirectory.
397
                raise NotVersionedError(path=path)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
398
        self.interesting_ids = interesting_ids
399
400
    def set_pending(self):
1185.12.77 by Aaron Bentley
Prevented all ancestors from being marked as pending merges
401
        if not self.base_is_ancestor:
402
            return
403
        if self.other_rev_id is None:
404
            return
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
405
        ancestry = self.this_branch.repository.get_ancestry(self.this_basis)
1185.66.2 by Aaron Bentley
Moved get_ancestry to RevisionStorage
406
        if self.other_rev_id in ancestry:
1185.12.77 by Aaron Bentley
Prevented all ancestors from being marked as pending merges
407
            return
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
408
        self.this_tree.add_pending_merge(self.other_rev_id)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
409
410
    def set_other(self, other_revision):
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
411
        other_branch, self.other_tree = _get_tree(other_revision, 
412
                                                  self.this_branch)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
413
        if other_revision[1] == -1:
414
            self.other_rev_id = other_branch.last_revision()
415
            if self.other_rev_id is None:
416
                raise NoCommits(other_branch)
417
            self.other_basis = self.other_rev_id
418
        elif other_revision[1] is not None:
419
            self.other_rev_id = other_branch.get_rev_id(other_revision[1])
420
            self.other_basis = self.other_rev_id
421
        else:
422
            self.other_rev_id = None
423
            self.other_basis = other_branch.last_revision()
424
            if self.other_basis is None:
425
                raise NoCommits(other_branch)
1185.65.30 by Robert Collins
Merge integration.
426
        if other_branch.base != self.this_branch.base:
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
427
            self.this_branch.fetch(other_branch, last_revision=self.other_basis)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
428
429
    def set_base(self, base_revision):
1185.12.96 by Aaron Bentley
Merge from mpool
430
        mutter("doing merge() with no base_revision specified")
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
431
        if base_revision == [None, None]:
432
            try:
433
                self.base_rev_id = common_ancestor(self.this_basis, 
434
                                                   self.other_basis, 
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
435
                                                   self.this_branch.repository)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
436
            except NoCommonAncestor:
437
                raise UnrelatedBranches()
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
438
            self.base_tree = _get_revid_tree(self.this_branch, self.base_rev_id,
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
439
                                            None)
440
            self.base_is_ancestor = True
441
        else:
1545.2.3 by Aaron Bentley
Updated following j-a-meinel's comments
442
            base_branch, self.base_tree = _get_tree(base_revision)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
443
            if base_revision[1] == -1:
444
                self.base_rev_id = base_branch.last_revision()
445
            elif base_revision[1] is None:
446
                self.base_rev_id = None
493 by Martin Pool
- Merge aaron's merge command
447
            else:
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
448
                self.base_rev_id = base_branch.get_rev_id(base_revision[1])
1534.1.31 by Robert Collins
Deprecated fetch.fetch and fetch.greedy_fetch for branch.fetch, and move the Repository.fetch internals to InterRepo and InterWeaveRepo.
449
            self.this_branch.fetch(base_branch)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
450
            self.base_is_ancestor = is_ancestor(self.this_basis, 
451
                                                self.base_rev_id,
452
                                                self.this_branch)
453
454
    def do_merge(self):
455
        def get_inventory(tree):
456
            return tree.inventory
1185.35.5 by Aaron Bentley
Made weave merge succeed if interesting files match history
457
        
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
458
        inv_changes = merge_flex(self.this_tree, self.base_tree, 
459
                                 self.other_tree,
460
                                 generate_changeset, get_inventory,
461
                                 self.conflict_handler,
462
                                 merge_factory=self.merge_factory, 
463
                                 interesting_ids=self.interesting_ids)
464
465
        adjust_ids = []
466
        for id, path in inv_changes.iteritems():
467
            if path is not None:
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
468
                if path == u'.':
469
                    path = u''
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
470
                else:
1185.31.18 by John Arbash Meinel
[patch] Alexey Shamrin's patch for small win32 fixes
471
                    assert path.startswith('.' + '/') or path.startswith('.' + '\\'), "path is %s" % path
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
472
                path = path[2:]
473
            adjust_ids.append((path, id))
474
        if len(adjust_ids) > 0:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
475
            self.this_tree.set_inventory(self.regen_inventory(adjust_ids))
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
476
        conflicts = self.conflict_handler.conflicts
477
        self.conflict_handler.finalize()
478
        return conflicts
479
480
    def regen_inventory(self, new_entries):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
481
        old_entries = self.this_tree.read_working_inventory()
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
482
        new_inventory = {}
483
        by_path = {}
484
        new_entries_map = {} 
485
        for path, file_id in new_entries:
486
            if path is None:
487
                continue
488
            new_entries_map[file_id] = path
489
490
        def id2path(file_id):
491
            path = new_entries_map.get(file_id)
492
            if path is not None:
493
                return path
494
            entry = old_entries[file_id]
495
            if entry.parent_id is None:
496
                return entry.name
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
497
            return pathjoin(id2path(entry.parent_id), entry.name)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
498
            
499
        for file_id in old_entries:
500
            entry = old_entries[file_id]
501
            path = id2path(file_id)
502
            new_inventory[file_id] = (path, file_id, entry.parent_id, 
503
                                      entry.kind)
504
            by_path[path] = file_id
974.1.21 by aaron.bentley at utoronto
Handled path generation properly
505
        
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
506
        deletions = 0
507
        insertions = 0
508
        new_path_list = []
509
        for path, file_id in new_entries:
510
            if path is None:
511
                del new_inventory[file_id]
512
                deletions += 1
513
            else:
514
                new_path_list.append((path, file_id))
515
                if file_id not in old_entries:
516
                    insertions += 1
517
        # Ensure no file is added before its parent
518
        new_path_list.sort()
519
        for path, file_id in new_path_list:
520
            if path == '':
521
                parent = None
522
            else:
523
                parent = by_path[os.path.dirname(path)]
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
524
            abspath = pathjoin(self.this_tree.basedir, path)
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
525
            kind = bzrlib.osutils.file_kind(abspath)
526
            new_inventory[file_id] = (path, file_id, parent, kind)
527
            by_path[path] = file_id 
493 by Martin Pool
- Merge aaron's merge command
528
1185.12.76 by Aaron Bentley
Refactored merge and merge_inner to use Merger
529
        # Get a list in insertion order
530
        new_inventory_list = new_inventory.values()
531
        mutter ("""Inventory regeneration:
532
    old length: %i insertions: %i deletions: %i new_length: %i"""\
533
            % (len(old_entries), insertions, deletions, 
534
               len(new_inventory_list)))
535
        assert len(new_inventory_list) == len(old_entries) + insertions\
536
            - deletions
537
        new_inventory_list.sort()
538
        return new_inventory_list
974.1.9 by Aaron Bentley
Added merge-type parameter to merge.
539
1545.2.4 by Aaron Bentley
PEP8 fixes
540
974.1.9 by Aaron Bentley
Added merge-type parameter to merge.
541
merge_types = {     "merge3": (ApplyMerge3, "Native diff3-style merge"), 
1185.12.83 by Aaron Bentley
Preliminary weave merge support
542
                     "diff3": (Diff3Merge,  "Merge using external diff3"),
543
                     'weave': (WeaveMerge, "Weave-based merge")
974.1.9 by Aaron Bentley
Added merge-type parameter to merge.
544
              }