@@ -2840,7 +2840,10 @@
source = ctx.extra().get('source')
if not source:
source = ctx.hex()
- extra = {'source': source}
+ extra = {
+ 'source': source,
+ 'branch': current.extra().get('branch', 'default'),
+ }
user = ctx.user()
if opts.get('user'):
user = opts['user']
@@ -2857,34 +2860,84 @@
try:
# ui.forcemerge is an internal variable, do not document
repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
- stats = mergemod.update(repo, ctx.node(), True, True, False,
- ctx.p1().node())
+ action = mergemod.calculateupdates(repo, current, ctx,
+ ctx.p1(),
+ branchmerge=True,
+ force=True,
+ partial=False)
finally:
repo.ui.setconfig('ui', 'forcemerge', '')
- # report any conflicts
- if stats and stats[3] > 0:
- # write out state for --continue
- nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
- repo.opener.write('graftstate', ''.join(nodelines))
- raise util.Abort(
- _("unresolved conflicts, can't continue"),
- hint=_('use hg resolve and hg graft --continue'))
+
+ filelist, filectxfn = mergemod.memapplyinfo(ctx, action)
+ memoryapply = bool(filelist)
+
+ if memoryapply:
+ repo.ui.debug("performing (graft) merge in-memory\n")
+ memctx = context.memctx(repo, (current.node(), None),
+ text=message,
+ files=filelist,
+ filectxfn=filectxfn,
+ user=user,
+ date=date,
+ extra=extra)
+ else:
+ repo.ui.debug("performing (graft) merge on-disk\n")
+ try:
+ # first update to the current rev if we've
+ # commited anything since the last update
+ if current.node() != repo['.'].node():
+ mergemod.update(repo, current.node(),
+ branchmerge=False,
+ force=True,
+ partial=None)
+ # ui.forcemerge is an internal variable, do not document
+ repo.ui.setconfig('ui', 'forcemerge',
+ opts.get('tool', ''))
+ stats = mergemod.applyupdates(repo, action,
+ wctx=repo[None],
+ mctx=ctx,
+ actx=ctx.p1(),
+ overwrite=False)
+ repo.setparents(current.node(), ctx.node())
+ mergemod.recordupdates(repo, action, branchmerge=True)
+ finally:
+ repo.ui.setconfig('ui', 'forcemerge', '')
+ # report any conflicts
+ if stats and stats[3] > 0:
+ # write out state for --continue
+ nodelines = [repo[rev].hex() + "\n"
+ for rev in revs[pos:]]
+ repo.opener.write('graftstate', ''.join(nodelines))
+ raise util.Abort(
+ _("unresolved conflicts, can't continue"),
+ hint=_('use hg resolve and hg graft --continue'))
+
+ if cont or not memoryapply:
+ cont = False
+ repo.setparents(current.node(), nullid)
+ repo.dirstate.write()
+ # fix up dirstate for copies and renames
+ cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
+
+ # commit
+ node = repo.commit(text=message, user=user,
+ date=date, extra=extra, editor=editor)
+
else:
cont = False
-
- # drop the second merge parent
- repo.setparents(current.node(), nullid)
- repo.dirstate.write()
- # fix up dirstate for copies and renames
- cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
-
- # commit
- node = repo.commit(text=message, user=user,
- date=date, extra=extra, editor=editor)
+ node = repo.commitctx(memctx)
+
if node is None:
ui.status(_('graft for revision %s is empty\n') % ctx.rev())
else:
current = repo[node]
+ # if we've committed at least one revision, update to the most recent
+ if current.node() != repo['.'].node():
+ mergemod.update(repo, current.node(),
+ branchmerge=False,
+ force=True,
+ partial=False)
+
finally:
wlock.release()
@@ -651,3 +651,43 @@
if not partial:
repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
return stats
+
+
+def memapplyinfo(mctx, action):
+ """Extract a list of files and a filectxfunction from an action list
+
+ This function is for translating from the merge-internal action
+ list format to a list of files, and a file context function,
+ suitable for constructing a memctx object.
+
+ Please note that not all actions are supported for in-memory
+ commits. This function will return a None, None tuple if you pass
+ it a list with an unsupprted action.
+
+ When successful, this function will return a (filelist, filectxfn) tuple.
+ """
+
+ memactions = set(['g'])
+ copymap = copies.pathcopies(mctx.p1(), mctx)
+
+ actionmap = {}
+ filelist = []
+ for a in action:
+ actionmap[a[0]] = a
+ filelist.append(a[0])
+ if a[1] not in memactions:
+ return None, None
+
+
+ def filectxfn(repo, memctx, path):
+ a = actionmap[path]
+ flags = a[2]
+ islink = 'l' in flags
+ isexec = 'x' in flags
+ mfilectx = mctx.filectx(path)
+ return context.memfilectx(path, mfilectx.data(),
+ islink=islink,
+ isexec=isexec,
+ copied=copymap.get(path))
+
+ return filelist, filectxfn
@@ -135,8 +135,9 @@
checking for directory renames
resolving manifests
overwrite: False, partial: False
- ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
+ ancestor: 68795b066622, local: ef0ef43d49e7, remote: 5d205f8b35b6
b: local copied/moved to a -> m
+ performing (graft) merge on-disk
preserving b for resolve of b
updating: b 1/1 files (100.00%)
picked tool 'internal:merge' for b (binary False symlink False)
@@ -148,18 +149,24 @@
searching for copies back to rev 1
resolving manifests
overwrite: False, partial: False
- ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
+ ancestor: 4c60f11aa304, local: 6b9e5368ca4e, remote: 97f8bfe72746
e: remote is newer -> g
- updating: e 1/1 files (100.00%)
- getting e
+ performing (graft) merge in-memory
e
grafting revision 4
searching for copies back to rev 1
resolving manifests
overwrite: False, partial: False
- ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
+ ancestor: 4c60f11aa304, local: 1905859650ec, remote: 9c233e8e184d
e: versions differ -> m
d: remote is newer -> g
+ performing (graft) merge on-disk
+ resolving manifests
+ overwrite: True, partial: False
+ ancestor: 6b9e5368ca4e+, local: 6b9e5368ca4e+, remote: 1905859650ec
+ e: remote is newer -> g
+ updating: e 1/1 files (100.00%)
+ getting e
preserving e for resolve of e
updating: d 1/2 files (50.00%)
getting d