mercurial/merge.py
changeset 2815 4870f795f681
parent 2814 0f787997e3c2
child 2836 e78cad1f6b1f
equal deleted inserted replaced
2814:0f787997e3c2 2815:4870f795f681
    46     os.unlink(b)
    46     os.unlink(b)
    47     os.unlink(c)
    47     os.unlink(c)
    48     return r
    48     return r
    49 
    49 
    50 def update(repo, node, branchmerge=False, force=False, partial=None,
    50 def update(repo, node, branchmerge=False, force=False, partial=None,
    51            forcemerge=False, wlock=None, show_stats=True, remind=True):
    51            wlock=None, show_stats=True, remind=True):
       
    52 
       
    53     overwrite = force and not branchmerge
       
    54     forcemerge = force and branchmerge
    52 
    55 
    53     if not wlock:
    56     if not wlock:
    54         wlock = repo.wlock()
    57         wlock = repo.wlock()
    55 
    58 
    56     ### check phase
    59     ### check phase
    57 
    60 
    58     pl = repo.dirstate.parents()
    61     pl = repo.dirstate.parents()
    59     if not force and pl[1] != nullid:
    62     if not overwrite and pl[1] != nullid:
    60         raise util.Abort(_("outstanding uncommitted merges"))
    63         raise util.Abort(_("outstanding uncommitted merges"))
    61 
    64 
    62     p1, p2 = pl[0], node
    65     p1, p2 = pl[0], node
    63     pa = repo.changelog.ancestor(p1, p2)
    66     pa = repo.changelog.ancestor(p1, p2)
    64 
    67 
    66     linear_path = (pa == p1 or pa == p2)
    69     linear_path = (pa == p1 or pa == p2)
    67     if branchmerge and linear_path:
    70     if branchmerge and linear_path:
    68         raise util.Abort(_("there is nothing to merge, just use "
    71         raise util.Abort(_("there is nothing to merge, just use "
    69                            "'hg update' or look at 'hg heads'"))
    72                            "'hg update' or look at 'hg heads'"))
    70 
    73 
    71     if not force and not linear_path and not branchmerge:
    74     if not overwrite and not linear_path and not branchmerge:
    72         raise util.Abort(_("this update spans a branch, use 'hg merge' "
    75         raise util.Abort(_("update spans branches, use 'hg merge' "
    73                            "or 'hg update -C' to lose changes"))
    76                            "or 'hg update -C' to lose changes"))
    74 
    77 
    75     modified, added, removed, deleted, unknown = repo.changes()
    78     modified, added, removed, deleted, unknown = repo.changes()
    76     if branchmerge and not forcemerge:
    79     if branchmerge and not forcemerge:
    77         if modified or added or removed:
    80         if modified or added or removed:
    85     m2 = repo.manifest.read(m2n).copy()
    88     m2 = repo.manifest.read(m2n).copy()
    86     mf2 = repo.manifest.readflags(m2n)
    89     mf2 = repo.manifest.readflags(m2n)
    87     ma = repo.manifest.read(man)
    90     ma = repo.manifest.read(man)
    88     mfa = repo.manifest.readflags(man)
    91     mfa = repo.manifest.readflags(man)
    89 
    92 
    90     if not forcemerge and not force:
    93     if not forcemerge and not overwrite:
    91         for f in unknown:
    94         for f in unknown:
    92             if f in m2:
    95             if f in m2:
    93                 t1 = repo.wread(f)
    96                 t1 = repo.wread(f)
    94                 t2 = repo.file(f).read(m2[f])
    97                 t2 = repo.file(f).read(m2[f])
    95                 if cmp(t1, t2) != 0:
    98                 if cmp(t1, t2) != 0:
    97                                        " dir and differs from remote") % f)
   100                                        " dir and differs from remote") % f)
    98 
   101 
    99     # resolve the manifest to determine which files
   102     # resolve the manifest to determine which files
   100     # we care about merging
   103     # we care about merging
   101     repo.ui.note(_("resolving manifests\n"))
   104     repo.ui.note(_("resolving manifests\n"))
   102     repo.ui.debug(_(" force %s branchmerge %s partial %s linear %s\n") %
   105     repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
   103                   (force, branchmerge, partial and True or False, linear_path))
   106                   (overwrite, branchmerge, partial and True or False, linear_path))
   104     repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
   107     repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
   105                   (short(man), short(m1n), short(m2n)))
   108                   (short(man), short(m1n), short(m2n)))
   106 
   109 
   107     merge = {}
   110     merge = {}
   108     get = {}
   111     get = {}
   157                     merge[f] = (m1.get(f, nullid), m2[f], mode)
   160                     merge[f] = (m1.get(f, nullid), m2[f], mode)
   158                     s = 1
   161                     s = 1
   159                 # are we clobbering?
   162                 # are we clobbering?
   160                 # is remote's version newer?
   163                 # is remote's version newer?
   161                 # or are we going back in time?
   164                 # or are we going back in time?
   162                 elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
   165                 elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
   163                     repo.ui.debug(_(" remote %s is newer, get\n") % f)
   166                     repo.ui.debug(_(" remote %s is newer, get\n") % f)
   164                     get[f] = m2[f]
   167                     get[f] = m2[f]
   165                     s = 1
   168                     s = 1
   166             elif f in umap or f in added:
   169             elif f in umap or f in added:
   167                 # this unknown file is the same as the checkout
   170                 # this unknown file is the same as the checkout
   168                 # we need to reset the dirstate if the file was added
   171                 # we need to reset the dirstate if the file was added
   169                 get[f] = m2[f]
   172                 get[f] = m2[f]
   170 
   173 
   171             if not s and mfw[f] != mf2[f]:
   174             if not s and mfw[f] != mf2[f]:
   172                 if force:
   175                 if overwrite:
   173                     repo.ui.debug(_(" updating permissions for %s\n") % f)
   176                     repo.ui.debug(_(" updating permissions for %s\n") % f)
   174                     util.set_exec(repo.wjoin(f), mf2[f])
   177                     util.set_exec(repo.wjoin(f), mf2[f])
   175                 else:
   178                 else:
   176                     a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
   179                     a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
   177                     mode = ((a^b) | (a^c)) ^ a
   180                     mode = ((a^b) | (a^c)) ^ a
   181                         util.set_exec(repo.wjoin(f), mode)
   184                         util.set_exec(repo.wjoin(f), mode)
   182             del m2[f]
   185             del m2[f]
   183         elif f in ma:
   186         elif f in ma:
   184             if n != ma[f]:
   187             if n != ma[f]:
   185                 r = _("d")
   188                 r = _("d")
   186                 if not force and (linear_path or branchmerge):
   189                 if not overwrite and (linear_path or branchmerge):
   187                     r = repo.ui.prompt(
   190                     r = repo.ui.prompt(
   188                         (_(" local changed %s which remote deleted\n") % f) +
   191                         (_(" local changed %s which remote deleted\n") % f) +
   189                          _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
   192                          _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
   190                 if r == _("d"):
   193                 if r == _("d"):
   191                     remove.append(f)
   194                     remove.append(f)
   192             else:
   195             else:
   193                 repo.ui.debug(_("other deleted %s\n") % f)
   196                 repo.ui.debug(_("other deleted %s\n") % f)
   194                 remove.append(f) # other deleted it
   197                 remove.append(f) # other deleted it
   195         else:
   198         else:
   196             # file is created on branch or in working directory
   199             # file is created on branch or in working directory
   197             if force and f not in umap:
   200             if overwrite and f not in umap:
   198                 repo.ui.debug(_("remote deleted %s, clobbering\n") % f)
   201                 repo.ui.debug(_("remote deleted %s, clobbering\n") % f)
   199                 remove.append(f)
   202                 remove.append(f)
   200             elif n == m1.get(f, nullid): # same as parent
   203             elif n == m1.get(f, nullid): # same as parent
   201                 if p2 == pa: # going backwards?
   204                 if p2 == pa: # going backwards?
   202                     repo.ui.debug(_("remote deleted %s\n") % f)
   205                     repo.ui.debug(_("remote deleted %s\n") % f)
   211             continue
   214             continue
   212         if f[0] == "/":
   215         if f[0] == "/":
   213             continue
   216             continue
   214         if f in ma and n != ma[f]:
   217         if f in ma and n != ma[f]:
   215             r = _("k")
   218             r = _("k")
   216             if not force and (linear_path or branchmerge):
   219             if not overwrite and (linear_path or branchmerge):
   217                 r = repo.ui.prompt(
   220                 r = repo.ui.prompt(
   218                     (_("remote changed %s which local deleted\n") % f) +
   221                     (_("remote changed %s which local deleted\n") % f) +
   219                      _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
   222                      _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
   220             if r == _("k"):
   223             if r == _("k"):
   221                 get[f] = n
   224                 get[f] = n
   222         elif f not in ma:
   225         elif f not in ma:
   223             repo.ui.debug(_("remote created %s\n") % f)
   226             repo.ui.debug(_("remote created %s\n") % f)
   224             get[f] = n
   227             get[f] = n
   225         else:
   228         else:
   226             if force or p2 == pa: # going backwards?
   229             if overwrite or p2 == pa: # going backwards?
   227                 repo.ui.debug(_("local deleted %s, recreating\n") % f)
   230                 repo.ui.debug(_("local deleted %s, recreating\n") % f)
   228                 get[f] = n
   231                 get[f] = n
   229             else:
   232             else:
   230                 repo.ui.debug(_("local deleted %s\n") % f)
   233                 repo.ui.debug(_("local deleted %s\n") % f)
   231 
   234 
   232     del mw, m1, m2, ma
   235     del mw, m1, m2, ma
   233 
   236 
   234     if force:
   237     if overwrite:
   235         for f in merge:
   238         for f in merge:
   236             get[f] = merge[f][1]
   239             get[f] = merge[f][1]
   237         merge = {}
   240         merge = {}
   238 
   241 
   239     if linear_path or force:
   242     if linear_path or overwrite:
   240         # we don't need to do any magic, just jump to the new rev
   243         # we don't need to do any magic, just jump to the new rev
   241         p1, p2 = p2, nullid
   244         p1, p2 = p2, nullid
   242 
   245 
   243     xp1 = hex(p1)
   246     xp1 = hex(p1)
   244     xp2 = hex(p2)
   247     xp2 = hex(p2)